CoolCMS API

FormTrait uses trait:short, trait:short

Builds the shipper tariff edit form (hosted in a dedicated AJAX modal on `ShipperPresenter`).

The shipper is always server-side context ($this->shipperId, set in the constructor of ShipperTariffEdit), never a form field. Pricing is generation based: history is immutable, bands may be open-ended, and prices are kept per currency.

Saving goes through AdminComponentFormTrait::createAdminComponentForm() with a custom $afterSave hook (buildAfterSave()) and never redirects the page.

Table of Contents

Properties

$shipperTariffBandErrors  : array<int, string>
Band validation errors collected while building; `saveShipperTariffForm()` uses them to decide whether saving is allowed at all.
$shipperTariffBandWarnings  : array<int, string>
$shipperTariffCurrentAxisDates  : array{prices: ?string, payments: ?string}|null
Date of the currently valid generation of each axis (per-request cache), see {@see getShipperTariffCurrentAxisDates()}.
$shipperTariffGenerationPrefill  : array{bands: list>, payments: array}|null
Prefill for a newly added generation; computed once per request and applied to every empty container that `onCreate` meets.

Methods

canRemoveShipperTariffGeneration()  : bool
Tells whether a generation may be removed: only a new or scheduled one (from today's midnight on). The currently valid one may not, because deleting it would make an older generation take over, a silent return to old prices.
getShipperTariffBandIssues()  : array<int, array{type: string, from: string, to: string}>
Returns the strips between bands, as `['overlap' => range]` or `['gap' => range]` keyed by the index of the band before which the strip is rendered. It is computed on a sorted copy but returns the index in the submitted order, so the template reorders nothing.
getShipperTariffGenerationBadgeKey()  : string
Returns the badge key of the card header. With migrated data the axes diverge (the price list is valid from another date than the matrix), giving two "current" cards, so the badge says which axis the card holds.
getShipperTariffGenerationState()  : string
Returns `current` (valid now), `scheduled` or `history`, for the badge and card color.
getShipperTariffGenerationSummary()  : array{bands: int, currencies: int, methods: int}
Returns the card header summary: number of bands, number of currencies with at least one price, and number of available payment methods.
isShipperTariffGenerationDateLocked()  : bool
Tells whether the "valid from" field is locked: for history (fully read-only) and for the currently valid generation, whose values are editable but whose date is a fact; repricing from another date is a new generation. A disabled input is not posted, the build takes the date from `origDateFrom`.
isShipperTariffGenerationOpenByDefault()  : bool
Tells whether the card's `<details>` is open by default: a new generation (empty `origDateFrom`) is open because it is being worked on; all others (valid, scheduled, history) are collapsed.
isShipperTariffGenerationReadOnly()  : bool
Tells whether a generation is read-only. Only superseded history is: a generation before today's midnight that a newer one has replaced on its axis. The currently valid generation (even dated in the past) is editable, and a new one (empty `origDateFrom`) is always editable.
restoreShipperTariffGenerationDisplay()  : void
Restores the display of fields that do not survive a POST followed by an AJAX redraw. The template calls it via `{do}` first in every generation card (before totals are computed).
shipperTariffCurrencyHasPrice()  : bool
Tells whether the currency has a price in at least one band of this generation. Used only by {@see getShipperTariffGenerationSummary()} for the currency count; the template lists all currencies for every band regardless.
createComponentEditForm()  : Form
isTargetAllowed()  : bool
Returns whether the logged-in user may open the given admin target. For visibility (tiles, autocomplete, buttons); it does not throw.
requirePrivilege()  : void
Throws 403 when the logged-in user lacks the given admin privilege.
resolvePageTarget()  : string|null
Returns the RBAC key of the target page: `<presenter>:<action>`, e.g. `:Admin:System:User:show`.
resolveSupplyKindDefaultId()  : int|null
addShipperTariffBandControls()  : void
Fields of one weight band inside a generation (currency becomes a table row in the template).
addShipperTariffGenerationMultiplier()  : void
Adds the outer `generations` multiplier, the nested `bands` multiplier and the fixed payment matrix.
addShipperTariffMainFields()  : void
addShipperTariffPaymentMatrixControls()  : void
Adds the payment matrix of a generation: a fixed 2D loop (methods x currencies), not a multiplier, because both axes are code lists that admins do not create in this form.
addShipperTariffTranslationFields()  : void
applyShipperTariffGenerations()  : void
Rebuilds both time series of the tariff from the submitted generations.
buildAfterSave()  : callable
Builds the post-save action (`AdminComponentFormTrait` hook); never redirects the page for AJAX.
buildShipperTariffBandDefaultRows()  : array<int, array<string, mixed>>
Builds the band rows of one generation, sorted by `weightFrom` and renumbered (sorting happens on load only).
buildShipperTariffEntity()  : ShipperTariff
buildShipperTariffGenerationDefaultRows()  : array<int, array<string, mixed>>
Maps the existing series to default rows of the outer multiplier.
buildShipperTariffGenerationRowForDate()  : array<string, mixed>
Builds the row of one generation (bands plus payment matrix) for a specific date; shared by {@see buildShipperTariffGenerationDefaultRows()} and {@see duplicateShipperTariffGeneration()}.
buildShipperTariffPaymentMatrixRow()  : array<string, mixed>
Maps the payment matrix cells of one generation to `pmAvailable_<mid>`, `pmPrice_<mid>_<cid>` and `pmFreeFrom_<mid>_<cid>`. Shared by {@see buildShipperTariffGenerationDefaultRows()} (existing generation) and {@see resolveShipperTariffGenerationPrefill()} (prefill of a new one).
collectShipperTariffBands()  : array<int, array{weightFrom: string, weightTo: ?string, row: array}>
Extracts and validates the bands of one generation. The returned order is the submitted order, not the sorted one: validation runs on a sorted copy so that error messages can name the exact range while the user's rows are not rearranged.
decimalOrNull()  : string|null
NOTE: this is not a duplicate of {@see \App\Core\Utils\Helpers\Decimal::fromInput()}. It quantizes to a given number of decimal places (`$scale`) instead of normalizing input. The scale differs per column (weight vs. shipping price), so it does not belong in the shared helper, which deliberately knows no scale so it cannot be unified across modules by accident.
duplicateShipperTariffGeneration()  : Container|null
Handles the "duplicate" action in the card header: copies the whole stored generation (bands and matrix) into a new generation so the admin only adjusts the date and prices.
entityReference()  : Shipper
Builds a thin shipper reference (the hydrator assembles the entity from the id).
fillShipperTariffGenerationContainer()  : void
Fills a generation container with row data (format of {@see buildShipperTariffGenerationRowForDate()}) so that it also works on a submitted form; the only reliable path for the AJAX actions "add generation" (prefill) and "duplicate".
getShipperTariffCurrentAxisDates()  : array{prices: ?string, payments: ?string}
Returns the date of the currently valid generation of each axis separately (the greatest `date_from <= now`) in the `Y-m-d H:i:s` format that the hidden `origDateFrom` carries.
isOwnEditFormSubmit()  : bool
Tells whether this request is a POST submit of this very `editForm`. The `_do` value carries the full component path, so a component created after the key switch has a different path and safely gets defaults.
isShipperTariffGenerationEmpty()  : bool
Detects a new empty container by the absence of data, not by index: `onCreate` runs for all generation containers on every request, including history and half-edited generations after a redraw. Empty `origDateFrom` alone is not enough (a new generation has it empty even after the admin typed something), so all fields the prefill would overwrite are checked too.
isShipperTariffHistoric()  : bool
loadShipperTariffSelectData()  : void
Loads the form axes (regions, VAT rates, currencies, payment methods) once per request; called from `createComponentEditForm()` before the fields and defaults are built.
prefillNewShipperTariffGeneration()  : void
Prefills a newly added generation with the data of the currently valid one. Leaves `validFrom` and `origDateFrom` alone: empty `origDateFrom` marks a new generation for rendering and the immutability guard, and `validFrom` must be chosen deliberately by the admin.
redrawTariffModal()  : void
Redraws the host snippet `tariffEditHost` after an AJAX validation or save failure. The component renders again with the same submitted form (inline field errors) plus flash, and the modal stays open.
resolveShipperTariffGenerationDate()  : DateTime|null
Converts `validFrom` to a `DateTime`. Empty means effective immediately (now). A past date would write into history, so it is an error, not a silent shift to today.
resolveShipperTariffGenerationPrefill()  : array{bands: list>, payments: array}
Resolves the prefill data of a new generation. Bands and the payment matrix are looked up separately because they are two independent time series ({@see ShipperTariff}).
resolveShipperTariffPrefillDate()  : DateTime|null
Resolves the generation date for the prefill: the greatest `date_from <= now` (the currently valid generation), or the nearest future one when the whole price list is only scheduled.
saveShipperTariffForm()  : bool
setShipperTariffFormDefaults()  : void
shipperTariffBandContainers()  : array<int, Container>
shipperTariffControlValue()  : mixed
Returns a container control's value without type juggling over `IComponent` (which has no `getValue()`).
shipperTariffPaymentMethodRef()  : PaymentMethod
Builds a thin payment method reference (the hydrator assembles the entity from the id).
shipperTariffValuesToArray()  : array<string, mixed>
Converts a form container (`ArrayHash` from the multiplier) to a plain array so that typed offsets can be used. Anything other than an array or `ArrayHash` is an empty row.
translateShipperTariff()  : string
validateShipperTariffBandCoverage()  : void
Validates band invariants within one generation: at most one open band, the open band must be the topmost, no overlaps (error) and ideally no gaps (warning only, a carrier may legitimately not ship every weight).

Properties

$shipperTariffBandErrors

Band validation errors collected while building; `saveShipperTariffForm()` uses them to decide whether saving is allowed at all.

private array<int, string> $shipperTariffBandErrors = []

$shipperTariffBandWarnings

private array<int, string> $shipperTariffBandWarnings = []

warnings (gaps between bands); flashed, do not block saving

$shipperTariffCurrentAxisDates

Date of the currently valid generation of each axis (per-request cache), see {@see getShipperTariffCurrentAxisDates()}.

private array{prices: ?string, payments: ?string}|null $shipperTariffCurrentAxisDates = null

$shipperTariffGenerationPrefill

Prefill for a newly added generation; computed once per request and applied to every empty container that `onCreate` meets.

private array{bands: list>, payments: array}|null $shipperTariffGenerationPrefill = null

Methods

canRemoveShipperTariffGeneration()

Tells whether a generation may be removed: only a new or scheduled one (from today's midnight on). The currently valid one may not, because deleting it would make an older generation take over, a silent return to old prices.

public canRemoveShipperTariffGeneration(Container $generation) : bool
Parameters
$generation : Container
Return values
bool

getShipperTariffBandIssues()

Returns the strips between bands, as `['overlap' => range]` or `['gap' => range]` keyed by the index of the band before which the strip is rendered. It is computed on a sorted copy but returns the index in the submitted order, so the template reorders nothing.

public getShipperTariffBandIssues(Container $generation) : array<int, array{type: string, from: string, to: string}>
Parameters
$generation : Container
Return values
array<int, array{type: string, from: string, to: string}>

getShipperTariffGenerationBadgeKey()

Returns the badge key of the card header. With migrated data the axes diverge (the price list is valid from another date than the matrix), giving two "current" cards, so the badge says which axis the card holds.

public getShipperTariffGenerationBadgeKey(Container $generation) : string
Parameters
$generation : Container
Return values
string

getShipperTariffGenerationState()

Returns `current` (valid now), `scheduled` or `history`, for the badge and card color.

public getShipperTariffGenerationState(Container $generation) : string
Parameters
$generation : Container
Return values
string

getShipperTariffGenerationSummary()

Returns the card header summary: number of bands, number of currencies with at least one price, and number of available payment methods.

public getShipperTariffGenerationSummary(Container $generation) : array{bands: int, currencies: int, methods: int}
Parameters
$generation : Container
Return values
array{bands: int, currencies: int, methods: int}

isShipperTariffGenerationDateLocked()

Tells whether the "valid from" field is locked: for history (fully read-only) and for the currently valid generation, whose values are editable but whose date is a fact; repricing from another date is a new generation. A disabled input is not posted, the build takes the date from `origDateFrom`.

public isShipperTariffGenerationDateLocked(Container $generation) : bool
Parameters
$generation : Container
Return values
bool

isShipperTariffGenerationOpenByDefault()

Tells whether the card's `<details>` is open by default: a new generation (empty `origDateFrom`) is open because it is being worked on; all others (valid, scheduled, history) are collapsed.

public isShipperTariffGenerationOpenByDefault(Container $generation) : bool
Parameters
$generation : Container
Return values
bool

isShipperTariffGenerationReadOnly()

Tells whether a generation is read-only. Only superseded history is: a generation before today's midnight that a newer one has replaced on its axis. The currently valid generation (even dated in the past) is editable, and a new one (empty `origDateFrom`) is always editable.

public isShipperTariffGenerationReadOnly(Container $generation) : bool

The Api immutability guard enforces the same rule.

Parameters
$generation : Container
Return values
bool

restoreShipperTariffGenerationDisplay()

Restores the display of fields that do not survive a POST followed by an AJAX redraw. The template calls it via `{do}` first in every generation card (before totals are computed).

public restoreShipperTariffGenerationDisplay(Container $generation) : void

Disabled fields are not submitted and defaults are applied on GET only, so after any AJAX action (duplicate, add or remove band) they would render empty:

  • the locked date of the valid generation is restored from the hidden origDateFrom;
  • read-only history has disabled selects (VAT) and checkboxes, so the whole row is restored from stored data (its POST is ignored on build anyway).

Posted values of editable fields are never overwritten.

Parameters
$generation : Container

shipperTariffCurrencyHasPrice()

Tells whether the currency has a price in at least one band of this generation. Used only by {@see getShipperTariffGenerationSummary()} for the currency count; the template lists all currencies for every band regardless.

public shipperTariffCurrencyHasPrice(Container $generation, int $currencyId) : bool
Parameters
$generation : Container
$currencyId : int
Return values
bool

createComponentEditForm()

protected createComponentEditForm() : Form
Return values
Form

isTargetAllowed()

Returns whether the logged-in user may open the given admin target. For visibility (tiles, autocomplete, buttons); it does not throw.

protected isTargetAllowed(string|null $key) : bool

IMPORTANT: fail-closed like requirePrivilege(): an empty key and a presenter without isAllowed() both mean no. A component that skips this question lists the target to everyone.

Parameters
$key : string|null
Return values
bool

requirePrivilege()

Throws 403 when the logged-in user lacks the given admin privilege.

protected requirePrivilege(string $key) : void

Call it as the first statement of a mutating signal, before loading data, so the check cannot be bypassed by something being written first.

Parameters
$key : string

resolvePageTarget()

Returns the RBAC key of the target page: `<presenter>:<action>`, e.g. `:Admin:System:User:show`.

protected static resolvePageTarget(object|null $page) : string|null

Same interpretation as Menu::filterByPrivileges(), BasePresenter::authorizeListing() and PrivilegeCheckTrait::checkCurrentPrivilege(). The key is derived from the page target only, never from a file or class name.

Returns null when the page is missing or has no presenter, so there is nothing to allow.

Parameters
$page : object|null

AdminPage entity (hydrated, hence just object)

Return values
string|null

resolveSupplyKindDefaultId()

protected resolveSupplyKindDefaultId(SupplyKindManager $manager, array<int, mixed> $options[, string|null $preferredKey = null ]) : int|null
Parameters
$manager : SupplyKindManager
$options : array<int, mixed>

select options (SupplyKindManager::findSelectOptions())

$preferredKey : string|null = null
Return values
int|null

addShipperTariffBandControls()

Fields of one weight band inside a generation (currency becomes a table row in the template).

private addShipperTariffBandControls(Container $container) : void
Parameters
$container : Container

addShipperTariffGenerationMultiplier()

Adds the outer `generations` multiplier, the nested `bands` multiplier and the fixed payment matrix.

private addShipperTariffGenerationMultiplier(Form $form) : void

IMPORTANT: the redraw closure is shared and always redraws the outer generations snippet, also for the nested band buttons. A nested multiplier cannot have its own snippet (it would sit inside the outer one and its name could not be a literal per index).

Parameters
$form : Form

addShipperTariffMainFields()

private addShipperTariffMainFields(Form $form) : void
Parameters
$form : Form

addShipperTariffPaymentMatrixControls()

Adds the payment matrix of a generation: a fixed 2D loop (methods x currencies), not a multiplier, because both axes are code lists that admins do not create in this form.

private addShipperTariffPaymentMatrixControls(Container $generation) : void

pmAvailable_<mid> gates the whole method row across currencies; payment method availability is a tariff property, not a currency one.

Parameters
$generation : Container

addShipperTariffTranslationFields()

private addShipperTariffTranslationFields(Form $form) : void
Parameters
$form : Form

applyShipperTariffGenerations()

Rebuilds both time series of the tariff from the submitted generations.

private applyShipperTariffGenerations(ArrayHash<string|int, mixed> $values, ShipperTariff $tariff) : void

Superseded history (older than the currently valid generation of its axis) is carried over as the original entities; it must be returned to the collection, otherwise orphanRemoval deletes it. Editable generations are rebuilt from scratch as a snapshot: every band x currency with a price and every method x currency combination (even unavailable ones) is written.

IMPORTANT: the currently valid generation is editable; only history already replaced by a newer generation is locked. The date of the valid generation cannot be changed (the input is disabled, the build takes it from origDateFrom); repricing from a date is a new generation.

Parameters
$values : ArrayHash<string|int, mixed>
$tariff : ShipperTariff

buildAfterSave()

Builds the post-save action (`AdminComponentFormTrait` hook); never redirects the page for AJAX.

private buildAfterSave() : callable
  • save (AJAX): closes the modal.
  • update (AJAX): keeps the modal open and redraws the component (fresh $editedShipperTariff, see saveShipperTariffForm()); always also redraws the tariff list and flash.
  • non-AJAX fallback: full redirect to the tariffs tab.
Return values
callable

buildShipperTariffBandDefaultRows()

Builds the band rows of one generation, sorted by `weightFrom` and renumbered (sorting happens on load only).

private buildShipperTariffBandDefaultRows(array<int, ShipperTariffPrice> $prices) : array<int, array<string, mixed>>
Parameters
$prices : array<int, ShipperTariffPrice>
Return values
array<int, array<string, mixed>>

buildShipperTariffEntity()

private buildShipperTariffEntity(ArrayHash<string|int, mixed> $values) : ShipperTariff
Parameters
$values : ArrayHash<string|int, mixed>
Tags
phpstan-impure

Fills $shipperTariffBandErrors and $shipperTariffBandWarnings.

Return values
ShipperTariff

buildShipperTariffGenerationDefaultRows()

Maps the existing series to default rows of the outer multiplier.

private buildShipperTariffGenerationDefaultRows(ShipperTariff $tariff) : array<int, array<string, mixed>>

Rows are grouped by date_from (both series separately but into the same generation, as they share the date; a generation with only a payment matrix and no bands must still be shown). Generations are ordered date_from descending (newest first) and future (scheduled) ones are shown too. Each row is built by buildShipperTariffGenerationRowForDate(), shared with duplicateShipperTariffGeneration().

Parameters
$tariff : ShipperTariff
Return values
array<int, array<string, mixed>>

buildShipperTariffGenerationRowForDate()

Builds the row of one generation (bands plus payment matrix) for a specific date; shared by {@see buildShipperTariffGenerationDefaultRows()} and {@see duplicateShipperTariffGeneration()}.

private buildShipperTariffGenerationRowForDate(ShipperTariff $tariff, string $dateKey, array<int, ShipperTariffPrice> $prices, array<int, PaymentMethodPrice> $payments) : array<string, mixed>
Parameters
$tariff : ShipperTariff
$dateKey : string
$prices : array<int, ShipperTariffPrice>
$payments : array<int, PaymentMethodPrice>
Return values
array<string, mixed>

buildShipperTariffPaymentMatrixRow()

Maps the payment matrix cells of one generation to `pmAvailable_<mid>`, `pmPrice_<mid>_<cid>` and `pmFreeFrom_<mid>_<cid>`. Shared by {@see buildShipperTariffGenerationDefaultRows()} (existing generation) and {@see resolveShipperTariffGenerationPrefill()} (prefill of a new one).

private buildShipperTariffPaymentMatrixRow(array<int, PaymentMethodPrice> $paymentPrices) : array<string, mixed>
Parameters
$paymentPrices : array<int, PaymentMethodPrice>
Return values
array<string, mixed>

collectShipperTariffBands()

Extracts and validates the bands of one generation. The returned order is the submitted order, not the sorted one: validation runs on a sorted copy so that error messages can name the exact range while the user's rows are not rearranged.

private collectShipperTariffBands(array<string, mixed> $generation, string $dateKey) : array<int, array{weightFrom: string, weightTo: ?string, row: array}>
Parameters
$generation : array<string, mixed>
$dateKey : string
Tags
phpstan-impure

Fills $shipperTariffBandErrors and $shipperTariffBandWarnings.

Return values
array<int, array{weightFrom: string, weightTo: ?string, row: array}>

decimalOrNull()

NOTE: this is not a duplicate of {@see \App\Core\Utils\Helpers\Decimal::fromInput()}. It quantizes to a given number of decimal places (`$scale`) instead of normalizing input. The scale differs per column (weight vs. shipping price), so it does not belong in the shared helper, which deliberately knows no scale so it cannot be unified across modules by accident.

private decimalOrNull(mixed $value, int $scale) : string|null
Parameters
$value : mixed
$scale : int
Return values
string|null

duplicateShipperTariffGeneration()

Handles the "duplicate" action in the card header: copies the whole stored generation (bands and matrix) into a new generation so the admin only adjusts the date and prices.

private duplicateShipperTariffGeneration(Container $generation) : Container|null

Defaults are built from the stored $this->editedShipperTariff filtered by this card's origDateFrom, not from the POST: readonly/disabled history fields are not fully posted.

The redraw is not part of this method; the onClick handler in addShipperTariffGenerationMultiplier() calls it separately, so the method can run outside an attached presenter, where redrawControl() has nothing to redraw.

Parameters
$generation : Container
Return values
Container|null

entityReference()

Builds a thin shipper reference (the hydrator assembles the entity from the id).

private entityReference(int $shipperId) : Shipper
Parameters
$shipperId : int
Return values
Shipper

fillShipperTariffGenerationContainer()

Fills a generation container with row data (format of {@see buildShipperTariffGenerationRowForDate()}) so that it also works on a submitted form; the only reliable path for the AJAX actions "add generation" (prefill) and "duplicate".

private fillShipperTariffGenerationContainer(Container $generation, array<string, mixed> $row) : void

A plain setValues($row) is not enough: Multiplier::setValues() only stores the bands values and builds copies later in createCopies(), which on a submitted form builds them from the HTTP data; a new container has none, so no bands appear. Bands are therefore created explicitly with addCopy($i) plus setValues($bandRow) on every copy.

Parameters
$generation : Container
$row : array<string, mixed>

getShipperTariffCurrentAxisDates()

Returns the date of the currently valid generation of each axis separately (the greatest `date_from <= now`) in the `Y-m-d H:i:s` format that the hidden `origDateFrom` carries.

private getShipperTariffCurrentAxisDates() : array{prices: ?string, payments: ?string}

null means the axis has no valid generation.

Return values
array{prices: ?string, payments: ?string}

isOwnEditFormSubmit()

Tells whether this request is a POST submit of this very `editForm`. The `_do` value carries the full component path, so a component created after the key switch has a different path and safely gets defaults.

private isOwnEditFormSubmit() : bool
Return values
bool

isShipperTariffGenerationEmpty()

Detects a new empty container by the absence of data, not by index: `onCreate` runs for all generation containers on every request, including history and half-edited generations after a redraw. Empty `origDateFrom` alone is not enough (a new generation has it empty even after the admin typed something), so all fields the prefill would overwrite are checked too.

private isShipperTariffGenerationEmpty(Container $generation) : bool
Parameters
$generation : Container
Return values
bool

isShipperTariffHistoric()

private isShipperTariffHistoric(DateTime|null $dateFrom, DateTime $todayMidnight) : bool
Parameters
$dateFrom : DateTime|null
$todayMidnight : DateTime
Return values
bool

loadShipperTariffSelectData()

Loads the form axes (regions, VAT rates, currencies, payment methods) once per request; called from `createComponentEditForm()` before the fields and defaults are built.

private loadShipperTariffSelectData() : void

The shipper options are not loaded because the shipper is server-side context.

prefillNewShipperTariffGeneration()

Prefills a newly added generation with the data of the currently valid one. Leaves `validFrom` and `origDateFrom` alone: empty `origDateFrom` marks a new generation for rendering and the immutability guard, and `validFrom` must be chosen deliberately by the admin.

private prefillNewShipperTariffGeneration(Container $generation) : void
Parameters
$generation : Container

redrawTariffModal()

Redraws the host snippet `tariffEditHost` after an AJAX validation or save failure. The component renders again with the same submitted form (inline field errors) plus flash, and the modal stays open.

private redrawTariffModal() : void

resolveShipperTariffGenerationDate()

Converts `validFrom` to a `DateTime`. Empty means effective immediately (now). A past date would write into history, so it is an error, not a silent shift to today.

private resolveShipperTariffGenerationDate(array<string, mixed> $generation, DateTime $todayMidnight) : DateTime|null
Parameters
$generation : array<string, mixed>
$todayMidnight : DateTime
Tags
phpstan-impure

Fills $shipperTariffBandErrors.

Return values
DateTime|null

resolveShipperTariffGenerationPrefill()

Resolves the prefill data of a new generation. Bands and the payment matrix are looked up separately because they are two independent time series ({@see ShipperTariff}).

private resolveShipperTariffGenerationPrefill(ShipperTariff $tariff) : array{bands: list>, payments: array}
Parameters
$tariff : ShipperTariff
Return values
array{bands: list>, payments: array}

resolveShipperTariffPrefillDate()

Resolves the generation date for the prefill: the greatest `date_from <= now` (the currently valid generation), or the nearest future one when the whole price list is only scheduled.

private resolveShipperTariffPrefillDate(array<int, DateTime> $dates, DateTime $now) : DateTime|null

Empty input (a series without any price) returns null and the caller skips the prefill for that axis.

Parameters
$dates : array<int, DateTime>
$now : DateTime
Return values
DateTime|null

saveShipperTariffForm()

private saveShipperTariffForm(ArrayHash<string|int, mixed> $values, Form|null $form) : bool
Parameters
$values : ArrayHash<string|int, mixed>
$form : Form|null
Return values
bool

setShipperTariffFormDefaults()

private setShipperTariffFormDefaults(Form $form) : void
Parameters
$form : Form

shipperTariffBandContainers()

private shipperTariffBandContainers(Container $generation) : array<int, Container>
Parameters
$generation : Container
Return values
array<int, Container>

shipperTariffControlValue()

Returns a container control's value without type juggling over `IComponent` (which has no `getValue()`).

private shipperTariffControlValue(Container $container, string $name) : mixed
Parameters
$container : Container
$name : string

shipperTariffPaymentMethodRef()

Builds a thin payment method reference (the hydrator assembles the entity from the id).

private shipperTariffPaymentMethodRef(int $methodId) : PaymentMethod
Parameters
$methodId : int
Return values
PaymentMethod

shipperTariffValuesToArray()

Converts a form container (`ArrayHash` from the multiplier) to a plain array so that typed offsets can be used. Anything other than an array or `ArrayHash` is an empty row.

private shipperTariffValuesToArray(mixed $values) : array<string, mixed>
Parameters
$values : mixed
Return values
array<string, mixed>

translateShipperTariff()

private translateShipperTariff(string $key[, array<string, string> $params = [] ]) : string
Parameters
$key : string
$params : array<string, string> = []
Return values
string

validateShipperTariffBandCoverage()

Validates band invariants within one generation: at most one open band, the open band must be the topmost, no overlaps (error) and ideally no gaps (warning only, a carrier may legitimately not ship every weight).

private validateShipperTariffBandCoverage(array<int, array{weightFrom: string, weightTo: ?string, row: array}> $bands, string $dateKey) : void
Parameters
$bands : array<int, array{weightFrom: string, weightTo: ?string, row: array}>
$dateKey : string
Tags
phpstan-impure

Fills $shipperTariffBandErrors and $shipperTariffBandWarnings.

On this page

Search results