ColumnValue
in package
Gates over a value from a form, measured by the limits of the real column.
The class does not invent or copy the limits: it reads them by reflection from
#[ORM\Column] through ColumnLimits, the same place Doctrine reads them from. This
closes the class of defects where a gate measured a different value, shape or range than
what is actually written.
Why the database is not enough: with a strict sql_mode an overflow fails the whole save
with a generic database error that cannot be shown on the field; with a non-strict one it
throws no exception and silently stores nonsense ('abc' becomes 0.000, 1e1000 becomes
9999999.999, 25 characters into varchar(20) are cut). Doctrine
guards nothing on this path (DecimalType::convertToDatabaseValue() is a passthrough).
IMPORTANT: a fits*() gate and its to*() counterpart belong together. The gate must
measure the value that toDecimal() actually returns for storing (after rounding to
the column scale), and the form must store exactly that value, not the raw input.
Otherwise a gap opens between the gate and the write: "12,5" passes the gate as 12.5 and
'12,5' goes to the DB, which rejects it (strict sql_mode) or makes 12.000 (non-strict).
NOTE: exponential notation (1e5) is deliberately not expanded here, unlike the import
(ImportRules::normalizeDecimal()), where
spreadsheets produce it. Nobody types it into a web form; it is a typo or an overflow
attempt, and rejecting it with a message is clearer for the visitor than silent expansion.
Table of Contents
Methods
- fitsDecimal() : bool
- Tells whether the value fits the decimal column of the entity.
- fitsDecimalColumn() : bool
- Same check as {@see fitsDecimal()} against an explicit `decimal(precision, scale)` (the real column read by {@see ColumnSchema}).
- fitsInteger() : bool
- Tells whether the value is a whole number within `[$min, $max]` inclusive. Plain digits with an optional leading minus only (no decimals, no exponent, no thousands separators); compared as strings with bcmath, so a value beyond `PHP_INT_MAX` is rejected instead of overflowing to float.
- fitsLength() : bool
- Tells whether the text fits the column length. Counted in characters (`mb_strlen`): `length` from `#[ORM\Column]` is a character count for these columns, not bytes.
- isDecimalShape() : bool
- Checks the number shape: decimal point or comma, thousands separators allowed (shared notation of {@see Decimal::clean()}), exponent not allowed.
- isEmpty() : bool
- Not filled in means nothing to guard (optional fields pass; `setRequired()` handles required ones).
- isNegativeDecimal() : bool
- Whether the value is a number below zero (`-0` and an unreadable value are not), measured on the raw value like {@see fitsDecimal()}. Lets a form tell "negative" apart from "too large".
- toDecimal() : numeric-string|null
- Returns the value prepared for writing to a decimal column: dot notation, rounded to the column scale. `null` means not filled in or not a number (that variant never reaches the write, {@see isDecimalShape()} rejects it in the form).
- asText() : string|null
- Returns the scalar as trimmed text; `null` means not filled in (also for arrays and objects, which do not belong in the field).
- isNegative() : bool
- normalize() : string|null
- Converts the input to a number in dot notation, or `null` when it is not a number.
- roundHalfUp() : numeric-string
- bcmath half-up (`bcadd`/`bcdiv` truncate on their own); same approach as `OrderCalculator::round3()`.
Methods
fitsDecimal()
Tells whether the value fits the decimal column of the entity.
public
static fitsDecimal(mixed $value, class-string $entity, string $property[, bool $allowNegative = false ]) : bool
The range is measured on the rounded value, on what is written, not on the raw input.
Compared with bcmath: (float) overflows to INF for large values and any comparison
with it lies.
Parameters
- $value : mixed
- $entity : class-string
- $property : string
- $allowNegative : bool = false
Return values
boolfitsDecimalColumn()
Same check as {@see fitsDecimal()} against an explicit `decimal(precision, scale)` (the real column read by {@see ColumnSchema}).
public
static fitsDecimalColumn(mixed $value, int $precision, int $scale[, bool $allowNegative = false ]) : bool
Parameters
- $value : mixed
- $precision : int
- $scale : int
- $allowNegative : bool = false
Return values
boolfitsInteger()
Tells whether the value is a whole number within `[$min, $max]` inclusive. Plain digits with an optional leading minus only (no decimals, no exponent, no thousands separators); compared as strings with bcmath, so a value beyond `PHP_INT_MAX` is rejected instead of overflowing to float.
public
static fitsInteger(mixed $value, int $min, int $max) : bool
Parameters
- $value : mixed
- $min : int
- $max : int
Return values
boolfitsLength()
Tells whether the text fits the column length. Counted in characters (`mb_strlen`): `length` from `#[ORM\Column]` is a character count for these columns, not bytes.
public
static fitsLength(mixed $value, class-string $entity, string $property) : bool
Parameters
- $value : mixed
- $entity : class-string
- $property : string
Return values
boolisDecimalShape()
Checks the number shape: decimal point or comma, thousands separators allowed (shared notation of {@see Decimal::clean()}), exponent not allowed.
public
static isDecimalShape(mixed $value) : bool
Parameters
- $value : mixed
Return values
boolisEmpty()
Not filled in means nothing to guard (optional fields pass; `setRequired()` handles required ones).
public
static isEmpty(mixed $value) : bool
Parameters
- $value : mixed
Return values
boolisNegativeDecimal()
Whether the value is a number below zero (`-0` and an unreadable value are not), measured on the raw value like {@see fitsDecimal()}. Lets a form tell "negative" apart from "too large".
public
static isNegativeDecimal(mixed $value) : bool
Parameters
- $value : mixed
Return values
booltoDecimal()
Returns the value prepared for writing to a decimal column: dot notation, rounded to the column scale. `null` means not filled in or not a number (that variant never reaches the write, {@see isDecimalShape()} rejects it in the form).
public
static toDecimal(mixed $value, class-string $entity, string $property) : numeric-string|null
Parameters
- $value : mixed
- $entity : class-string
- $property : string
Return values
numeric-string|nullasText()
Returns the scalar as trimmed text; `null` means not filled in (also for arrays and objects, which do not belong in the field).
private
static asText(mixed $value) : string|null
Parameters
- $value : mixed
Return values
string|nullisNegative()
private
static isNegative(string $normalized) : bool
Parameters
- $normalized : string
Return values
boolnormalize()
Converts the input to a number in dot notation, or `null` when it is not a number.
private
static normalize(mixed $value) : string|null
Parameters
- $value : mixed
Return values
string|nullroundHalfUp()
bcmath half-up (`bcadd`/`bcdiv` truncate on their own); same approach as `OrderCalculator::round3()`.
private
static roundHalfUp(numeric-string $value, int $scale) : numeric-string
Parameters
- $value : numeric-string
-
value after normalize(); no other value may get here
- $scale : int