CoolCMS API

DecimalQuantityTrait

Accessors for a `quantity` mapped as `decimal(8,2)`.

Used only by line entities with a non-integer quantity (work hours, meters, kilograms): InvoiceItem and InvoiceTemplateItem. Gifts, shipping and payment methods have piece quantities and stay int.

Contract:

  • The getter returns a numeric string, like the monetary $price, because DBAL decimal never returns a float. The consumer casts itself ((float) $line->getQuantity()); abs() and intdiv() reject a string and fail with a TypeError under strict_types=1.
  • The setter takes int|float|string, so every existing writer keeps working.
  • The value is normalized to a fixed two-decimal form ('2.50', '2.00'). The database returns '2.00' after the column change, so a rewrite with the same value is not marked as changed by Doctrine change tracking.
  • Rounding is half-up to 2 places, the same as MySQL does when storing into decimal(8,2). Otherwise the calculator would work with a finer number than the database holds and a reloaded invoice would give a different total.
  • Non-numeric input gives '0.00'; null, '' or 'abc' must not reach the multiplication by price.
  • The range is not clipped: decimal(8,2) holds at most 999999.99, but silent clamping would make the entity claim a different number than the database. The caller validates the range (see InvoiceComposer); the setter must not throw during form hydration instead of a validation message.

IMPORTANT: deploy the code before alter table ... modify quantity decimal(8,2). In that window a decimal quantity must not be entered; the server-side guard DecimalQuantityGuardTrait in beforeSave of both Api managers enforces it (invoice and template): a non-integer quantity over the still int column fails with VALIDATION_FAILED and the write is rolled back. The database does not reliably reject it (depending on sql_mode it may store '2.50' as 3 without any error), and because totals are recomputed from the stored quantity on every save, the invoice would silently grow. Integer quantities pass unchanged and the guard turns itself off after the column change.

Table of Contents

Constants

QUANTITY_SCALE  : int = 2
Number of decimal places of the `decimal(8,2)` column.

Methods

getQuantity()  : string
setQuantity()  : $this
normalizeQuantity()  : string
Converts input from any writer to a numeric string with scale 2.

Constants

QUANTITY_SCALE

Number of decimal places of the `decimal(8,2)` column.

private int QUANTITY_SCALE = 2

Methods

setQuantity()

public setQuantity(int|float|string $quantity) : $this
Parameters
$quantity : int|float|string
Return values
$this

normalizeQuantity()

Converts input from any writer to a numeric string with scale 2.

private normalizeQuantity(int|float|string $quantity) : string

A string is stripped of thousand separators (including non-breaking and narrow spaces) and a comma is taken as the decimal separator. The admin form and external callers send 2,5 as often as 2.5, and without the conversion is_numeric('2,5') would fail and the quantity would silently drop to zero.

The cleanup is done by the shared Decimal::clean() so that the entity and the form see the same input; scale and zero instead of null belong to this entity.

Parameters
$quantity : int|float|string
Return values
string
On this page

Search results