Skip to main content
Version: 3.x

Number

Version
3.x
Updated
View markdown

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

SettingMeaning
numberTypeinteger | decimal | money | percent. Default decimal
decimalsDigits after the point. 0 for integer
min / maxRange, validated in check()
signedAllow negatives. Form validation only
nullableKeep NULL for an empty value instead of coercing it to 0
unitSuffix on output, e.g. kg, %
symbolMoney only: true for the base-currency symbol, or an explicit string
thousandsGroup 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.

Variantdecimalssignedunitsymbolmin / max
integer0trueno
decimal (default)2trueno
money2falseyes
percent2false%no0 / 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 an int column, 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 0 unless '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 string template, so maxLength and style are 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