Number
- Version
- 3.x
- Updated
One configurable numeric type covering integers, decimals, money and percentages. It replaced
dedicated integer and money types — do not reintroduce those.
Storage kind: column · Column: int for the integer variant, decimal(20,4) otherwise
Use it for anything the code will do arithmetic on or compare numerically. Do not use it for an
identifier that happens to be an integer — a foreign key belongs in join, a country in
countryselect. Those store integers too, but the point of them is the
picker and the label lookup, and a number field is a text input.
Settings
| Setting | Meaning |
|---|---|
numberType | integer | decimal | money | percent. Default decimal |
decimals | Digits after the point. 0 for integer |
min / max | Range, validated in check() |
signed | Allow negatives. Form validation only |
nullable | Keep NULL for an empty value instead of coercing it to 0 |
unit | Suffix on output, e.g. kg, % |
symbol | Money only: true for the base-currency symbol, or an explicit string |
thousands | Group integer digits on output with the localised separator |
numberType is a preset: it fills the others with sensible values, and any explicitly declared
key wins over the preset.
| Variant | decimals | signed | unit | symbol | min / max |
|---|---|---|---|---|---|
integer | 0 | true | — | no | — |
decimal (default) | 2 | true | — | no | — |
money | 2 | false | — | yes | — |
percent | 2 | false | % | no | 0 / 100 |
percent is the only variant that presets a range. If you need a percentage that may exceed 100 —
a markup, an index — declare 'max' => null explicitly alongside it.
Choosing the variant
integer— counts, quantities, positions. Stored in anintcolumn, so nothing after the decimal point survives.decimal— measurements, factors, anything numeric that is not currency. The default, and signed, because a measurement can be negative.money— prices and amounts. Adds the base-currency symbol on output.percent— rates and discounts. Adds%and clamps to 0–100.
signed does not make the column unsigned
It governs validation: check() refuses a negative for an unsigned field with a clear message
rather than silently flooring it. The column's signedness comes from dataType.
Deriving one from the other mistyped 33 money columns, because most money columns here are
deliberately signed: discounts, price overrides and import adjustments go negative. money presets
signed => false for the common case — a product price — so any money field that can legitimately
go negative must say 'signed' => true.
Note the asymmetry between validation and normalisation: check() reports the negative, but a value
that reaches normalize() on an unsigned field is floored to zero rather than kept. Validation is
the gate; do not rely on the floor to tell you something went wrong.
Notes
- Values are normalised from the localised decimal mark on input and stored with a dot, so the raw
column value is always canonical. Grouping characters, currency symbols and units are stripped on
the way in, so a pasted
"1.234,56 €"parses. - Empty becomes
0unless'nullable' => true. On a nullable field an unset number stays NULL, which is what you want when "no value" and "zero" mean different things — a price ceiling, say. - Rendering falls back to the
stringtemplate, somaxLengthandstyleare accepted but rarely meaningful.
@see string.md — stringType => 'number' is the old way; do not declare a new one
@see ../com_configbox_property_definition_settings.md §2