ShipperTariffEdit
extends BaseComponent
in package
uses
AdminComponentFormTrait, FormTrait, FormHelpersTrait, BranchTrait
Add / edit form of a shipper tariff, hosted in the modal of {@see ShipperPresenter} (tab with the tariff list and modal editing; a `Multiplier<ShipperTariffEdit>` keyed by a persistent active key).
The shipper is never a form field: it always comes from the server-side context
($shipperId constructor argument), so a forged shipper id cannot be submitted.
The form covers address, branches, texts, price generations (nested Multiplier of
generations and bands) and the fixed payment matrix.
Table of Contents
Constants
- EDIT_INCLUDES : array<int, string> = [ 'translations', 'shipper', 'shipperRegion', '...
- Canonical includes list, the single source of truth for loading the edited tariff.
Properties
- $container : Container
- $routerDispatcher : RouterDispatcher
- $translator : ITranslator
- $appContext : AppContext
- $componentParameters : array<string, mixed>
- $currencyContext : CurrencyContext|null
- $deviceDetector : DeviceDetector|null
- $languageContext : LanguageContext|null
- $localizationContext : LocalizationContext|null
- $settingContext : SettingContext
- $themeContext : ThemeContext|null
- $translatorDomain : string
- $adminLanguageManager : LanguageManager
- $currencyManager : CurrencyManager
- $editedShipperTariff : ShipperTariff|null
- Edited tariff (null when adding); see {@see resolveEditedTariff()}.
- $editingBranchId : int|null
- Branch currently edited in the modal (`branchId`); null when adding a new one.
- $formActionsFactory : FormActionsFactory
- $formNotices : array<int, array{type: string, key: string}>
- Result-level messages of saving the tariff, rendered directly in the modal content.
- $langNavFactory : LangNavFactory
- $paymentMethodManager : PaymentMethodManager
- $shipperId : int
- Edited shipper (server-side context, never taken from the form).
- $shipperRegionManager : ShipperRegionManager
- $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>
- $shipperTariffCurrencies : array<int, Currency>
- $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.
- $shipperTariffManager : ShipperTariffManager
- $shipperTariffPaymentMethods : array<int, PaymentMethod>
- $shipperTariffRegionOptions : array<int, NotTranslate>
- $shipperTariffSupplyKindOptions : array<int, string>
- $shipperTariffVatOptions : array<int, NotTranslate>
- $supplyKindManager : SupplyKindManager
- $tariffId : int|null
- $vatManager : VatManager
Methods
- __call() : mixed
- Dispatches `renderXyz()` to `render('Xyz', ...$args)`.
- __construct() : mixed
- 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.
- createComponent() : IComponent|null
- getAppContext() : AppContext
- getComponentParameter() : mixed
- Returns a component parameter, or null when it is not set.
- getContainer() : Container
- getCurrencyContext() : CurrencyContext|null
- getLanguageContext() : LanguageContext|null
- getLocalizationContext() : LocalizationContext|null
- getRouterDispatcher() : RouterDispatcher
- getSettingContext() : SettingContext
- getSettings() : array<int, array<string, mixed>>
- 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.
- getThemeContext() : ThemeContext|null
- handleAddBranch() : void
- handleDeleteBranch() : void
- Deletes a branch over AJAX (no redirect, which would close the open tariff modal).
- handleEditBranch() : void
- hasServiceByType() : bool
- Returns whether the container has a service of the given type.
- initializeAllContexts() : void
- injectDeviceDetector() : void
- 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.
- onBranchFormSuccess() : void
- onCreate() : void
- render() : void
- 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).
- setAppContext() : $this
- setComponentParameter() : void
- Sets a component parameter.
- setCurrencyContext() : $this
- setLanguageContext() : $this
- setLocalizationContext() : $this
- setSettingContext() : $this
- setThemeContext() : $this
- setup() : void
- setupAppContext() : void
- 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.
- typedComponent() : T
- Returns a subcomponent with a verified type.
- createAdminComponentForm() : Form
- createComponentAdminFormActions() : FormActions
- Creates the save / back buttons of the form.
- createComponentAdminLangNav() : LangNav
- Creates the language tabs of the multilingual fields.
- createComponentBranchForm() : Form
- createComponentEditForm() : Form
- currentLangId() : int|null
- Returns the current language id (for select captions etc.), null when unknown.
- frontPresenter() : BasePresenter|null
- Returns the front presenter the component is attached to (null outside the front end or when detached).
- getFormLanguages() : array<int, Language>
- Returns the languages for multilingual form fields (admin `LanguageManager`, constructor-injected).
- getTranslator() : ITranslator
- intOrNull() : int|null
- Converts a mixed form value to an int or null (an empty or zero value becomes null).
- setTemplateFile() : void
- setTranslator() : self
- str() : string
- Converts a mixed form value to a string; non-scalars become an empty string.
- strOrNull() : string|null
- Converts a mixed form value to a string or null (an empty string is stored as 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.
- buildBranchModalContent() : string
- 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).
- canManageBranches() : bool
- Branches can be managed only on an already saved tariff (the foreign key target must exist).
-
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.
- createMultiplierComponent() : Multiplier<string|int, IComponent>
- Creates a multiplier for the component.
- createNewComponentInstance() : IComponent|null
- Creates a new component instance without adding it to the presenter; used by the multiplier.
- createStandardComponent() : IComponent|null
- Creates a standard component (not a multiplier).
- 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".
- findBranch() : ShipperTariffBranch|null
- flashBranchGuardError() : void
- formatBranchAddress() : string
- 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.
- httpRequest() : IRequest
- Returns the HTTP request through the presenter; a control, unlike a presenter, has no `getHttpRequest()`.
- 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
- loadBranchRows() : array<int, array{id: int, name: string, address: string, active: bool}>
- Builds the branch cards, always filtered by `isManaged`: `false` is reserved for a future bulk sync of an external shipper network and is never listed in the admin.
- 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.
- redrawBranchesAfterMutation() : void
- 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.
- resolveEditedTariff() : ShipperTariff|null
- Loads the edited tariff, or returns null when adding.
- 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
- setBranchFormDefaults() : void
- setShipperTariffFormDefaults() : void
- shipperPresenter() : ShipperPresenter|null
- Returns the host presenter (the only consumer of this component), or null for any other.
- 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.
- showBranchModal() : void
- 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).
Constants
EDIT_INCLUDES
Canonical includes list, the single source of truth for loading the edited tariff.
public
array<int, string>
EDIT_INCLUDES
= [
'translations',
'shipper',
'shipperRegion',
'prices',
'prices.vat',
'paymentPrices',
'paymentPrices.paymentMethod',
// IMPORTANT: branches must be included even though they are saved by their own path
// (`BranchTrait::handleAddBranch()` etc., outside the main form submit); an owned
// collection with orphan removal would otherwise be deleted on every save of the
// main form.
'branches',
]
Properties
$container
public
Container
$container
Attributes
- #[Inject]
$routerDispatcher
public
RouterDispatcher
$routerDispatcher
$translator
public
ITranslator
$translator
Tags
$appContext
protected
AppContext
$appContext
$componentParameters
protected
array<string, mixed>
$componentParameters
= []
component parameters set by setComponentParameter()
$currencyContext
protected
CurrencyContext|null
$currencyContext
= NULL
$deviceDetector
protected
DeviceDetector|null
$deviceDetector
= NULL
$languageContext
protected
LanguageContext|null
$languageContext
= NULL
$localizationContext
protected
LocalizationContext|null
$localizationContext
= NULL
$settingContext
protected
SettingContext
$settingContext
$themeContext
protected
ThemeContext|null
$themeContext
= NULL
$translatorDomain
protected
string
$translatorDomain
= 'admin.eshop.presenters.shipperTariff'
$adminLanguageManager read-only
private
LanguageManager
$adminLanguageManager
$currencyManager read-only
private
CurrencyManager
$currencyManager
$editedShipperTariff
Edited tariff (null when adding); see {@see resolveEditedTariff()}.
private
ShipperTariff|null
$editedShipperTariff
$editingBranchId
Branch currently edited in the modal (`branchId`); null when adding a new one.
private
int|null
$editingBranchId
= null
$formActionsFactory read-only
private
FormActionsFactory
$formActionsFactory
$formNotices
Result-level messages of saving the tariff, rendered directly in the modal content.
private
array<int, array{type: string, key: string}>
$formNotices
= []
Per-request buffer.
IMPORTANT: presenter flashMessage() is not visible in a component template and the
page has no admin flashMessagesSnippet, so flashed messages would be lost.
$langNavFactory read-only
private
LangNavFactory
$langNavFactory
$paymentMethodManager read-only
private
PaymentMethodManager
$paymentMethodManager
$shipperId read-only
Edited shipper (server-side context, never taken from the form).
private
int
$shipperId
$shipperRegionManager read-only
private
ShipperRegionManager
$shipperRegionManager
$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
$shipperTariffCurrencies
private
array<int, Currency>
$shipperTariffCurrencies
= []
$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
$shipperTariffManager read-only
private
ShipperTariffManager
$shipperTariffManager
$shipperTariffPaymentMethods
private
array<int, PaymentMethod>
$shipperTariffPaymentMethods
= []
payment matrix axis, including unavailable methods (they can be enabled again)
$shipperTariffRegionOptions
private
array<int, NotTranslate>
$shipperTariffRegionOptions
= []
$shipperTariffSupplyKindOptions
private
array<int, string>
$shipperTariffSupplyKindOptions
= []
supply kinds (id => name from the DB; the select has the translator turned off)
$shipperTariffVatOptions
private
array<int, NotTranslate>
$shipperTariffVatOptions
= []
$supplyKindManager read-only
private
SupplyKindManager
$supplyKindManager
$tariffId read-only
private
int|null
$tariffId
$vatManager read-only
private
VatManager
$vatManager
Methods
__call()
Dispatches `renderXyz()` to `render('Xyz', ...$args)`.
public
__call(string $name, array<string|int, mixed> $args) : mixed
Called only when the component has no renderXyz() method of its own.
Parameters
- $name : string
- $args : array<string|int, mixed>
__construct()
public
__construct(ShipperTariffManager $shipperTariffManager, ShipperRegionManager $shipperRegionManager, CurrencyManager $currencyManager, VatManager $vatManager, PaymentMethodManager $paymentMethodManager, LanguageManager $adminLanguageManager, LangNavFactory $langNavFactory, FormActionsFactory $formActionsFactory, SupplyKindManager $supplyKindManager, int|null $tariffId, int $shipperId) : mixed
Parameters
- $shipperTariffManager : ShipperTariffManager
- $shipperRegionManager : ShipperRegionManager
- $currencyManager : CurrencyManager
- $vatManager : VatManager
- $paymentMethodManager : PaymentMethodManager
- $adminLanguageManager : LanguageManager
- $langNavFactory : LangNavFactory
- $formActionsFactory : FormActionsFactory
- $supplyKindManager : SupplyKindManager
- $tariffId : int|null
- $shipperId : int
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
boolcreateComponent()
public
createComponent(string $name) : IComponent|null
Parameters
- $name : string
Return values
IComponent|nullgetAppContext()
public
getAppContext() : AppContext
Return values
AppContextgetComponentParameter()
Returns a component parameter, or null when it is not set.
public
getComponentParameter(string $name) : mixed
Parameters
- $name : string
getContainer()
public
getContainer() : Container
Return values
ContainergetCurrencyContext()
public
getCurrencyContext() : CurrencyContext|null
Return values
CurrencyContext|nullgetLanguageContext()
public
getLanguageContext() : LanguageContext|null
Return values
LanguageContext|nullgetLocalizationContext()
public
getLocalizationContext() : LocalizationContext|null
Return values
LocalizationContext|nullgetRouterDispatcher()
public
getRouterDispatcher() : RouterDispatcher
Return values
RouterDispatchergetSettingContext()
public
getSettingContext() : SettingContext
Return values
SettingContextgetSettings()
public
getSettings() : array<int, array<string, mixed>>
Return values
array<int, array<string, mixed>>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
stringgetShipperTariffGenerationState()
Returns `current` (valid now), `scheduled` or `history`, for the badge and card color.
public
getShipperTariffGenerationState(Container $generation) : string
Parameters
- $generation : Container
Return values
stringgetShipperTariffGenerationSummary()
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}getThemeContext()
public
getThemeContext() : ThemeContext|null
Return values
ThemeContext|nullhandleAddBranch()
public
handleAddBranch() : void
handleDeleteBranch()
Deletes a branch over AJAX (no redirect, which would close the open tariff modal).
public
handleDeleteBranch(int $branchId) : void
The confirmation dialog comes from the template (data-grid-confirm); its JS handler is
delegated on document, so it works on any link.
Parameters
- $branchId : int
Attributes
- #[Requires]
- $methods: 'POST'
handleEditBranch()
public
handleEditBranch(int $branchId) : void
Parameters
- $branchId : int
hasServiceByType()
Returns whether the container has a service of the given type.
public
hasServiceByType(string $className) : bool
The name is composed dynamically (module plus component), so class_exists() runs first, and
a true result guarantees a valid type.
Parameters
- $className : string
Tags
Return values
boolinitializeAllContexts()
public
initializeAllContexts() : void
injectDeviceDetector()
public
injectDeviceDetector(DeviceDetector $detector) : void
Parameters
- $detector : DeviceDetector
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
boolisShipperTariffGenerationOpenByDefault()
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
boolisShipperTariffGenerationReadOnly()
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
boolonBranchFormSuccess()
public
onBranchFormSuccess(Form $form, ArrayHash<string|int, mixed> $values) : void
Parameters
- $form : Form
- $values : ArrayHash<string|int, mixed>
onCreate()
public
onCreate() : void
render()
public
render() : void
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
setAppContext()
public
setAppContext(AppContext $appContext) : $this
Parameters
- $appContext : AppContext
Return values
$thissetComponentParameter()
Sets a component parameter.
public
setComponentParameter(string $name, mixed $value) : void
Parameters
- $name : string
- $value : mixed
setCurrencyContext()
public
setCurrencyContext(CurrencyContext|null $currencyContext) : $this
Parameters
- $currencyContext : CurrencyContext|null
Return values
$thissetLanguageContext()
public
setLanguageContext(LanguageContext|null $languageContext) : $this
Parameters
- $languageContext : LanguageContext|null
Return values
$thissetLocalizationContext()
public
setLocalizationContext(LocalizationContext|null $localizationContext) : $this
Parameters
- $localizationContext : LocalizationContext|null
Return values
$thissetSettingContext()
public
setSettingContext(SettingContext $settingContext) : $this
Parameters
- $settingContext : SettingContext
Return values
$thissetThemeContext()
public
setThemeContext(ThemeContext|null $themeContext) : $this
Parameters
- $themeContext : ThemeContext|null
Return values
$thissetup()
public
setup(BasePresenter|BasePresenter $presenter) : void
Parameters
- $presenter : BasePresenter|BasePresenter
setupAppContext()
public
setupAppContext(AppContext $appContext) : void
Parameters
- $appContext : AppContext
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
booltypedComponent()
Returns a subcomponent with a verified type.
public
typedComponent(string $name, T> $type) : T
Use it instead of an inline @var above $this['x'] (which does not narrow the type) and
instead of the generic IComponent that $this['x'] returns. See
Form::typedComponent().
Parameters
- $name : string
- $type : T>
Tags
Return values
TcreateAdminComponentForm()
protected
createAdminComponentForm(callable(ArrayHash<string|int, mixed>, Form=): bool $processData[, callable(string): void|null $afterSave = null ]) : Form
Parameters
- $processData : callable(ArrayHash<string|int, mixed>, Form=): bool
-
Saves the data; returns success (handles its own flash).
- $afterSave : callable(string): void|null = null
-
When set, replaces the default backKey/redirect logic after a successful
$processData; the parameter is the clicked submit name (updateorsave). The hiddenbackKeystays in the form but is unused. For a component hosted in a modal shell, where a page redirect makes no sense (the modal is an AJAX shell over the presenter page).
Return values
FormcreateComponentAdminFormActions()
Creates the save / back buttons of the form.
protected
createComponentAdminFormActions() : FormActions
Return values
FormActionscreateComponentAdminLangNav()
Creates the language tabs of the multilingual fields.
protected
createComponentAdminLangNav() : LangNav
Return values
LangNavcreateComponentBranchForm()
protected
createComponentBranchForm() : Form
Return values
FormcreateComponentEditForm()
protected
createComponentEditForm() : Form
Return values
FormcurrentLangId()
Returns the current language id (for select captions etc.), null when unknown.
protected
currentLangId() : int|null
Return values
int|nullfrontPresenter()
Returns the front presenter the component is attached to (null outside the front end or when detached).
protected
frontPresenter() : BasePresenter|null
Return values
BasePresenter|nullgetFormLanguages()
Returns the languages for multilingual form fields (admin `LanguageManager`, constructor-injected).
protected
getFormLanguages() : array<int, Language>
Return values
array<int, Language>getTranslator()
protected
getTranslator() : ITranslator
Return values
ITranslatorintOrNull()
Converts a mixed form value to an int or null (an empty or zero value becomes null).
protected
intOrNull(mixed $value) : int|null
Parameters
- $value : mixed
Return values
int|nullsetTemplateFile()
protected
setTemplateFile(string $dir, string $filename) : void
Parameters
- $dir : string
- $filename : string
setTranslator()
protected
setTranslator(ITranslator $translator) : self
Parameters
- $translator : ITranslator
Return values
selfstr()
Converts a mixed form value to a string; non-scalars become an empty string.
protected
str(mixed $value) : string
Parameters
- $value : mixed
Return values
stringstrOrNull()
Converts a mixed form value to a string or null (an empty string is stored as null).
protected
strOrNull(mixed $value) : string|null
Parameters
- $value : mixed
Return values
string|nulladdShipperTariffBandControls()
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
callablebuildBranchModalContent()
private
buildBranchModalContent() : string
Return values
stringbuildShipperTariffBandDefaultRows()
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
Return values
ShipperTariffbuildShipperTariffGenerationDefaultRows()
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>canManageBranches()
Branches can be managed only on an already saved tariff (the foreign key target must exist).
private
canManageBranches() : bool
Return values
boolcollectShipperTariffBands()
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
Return values
array<int, array{weightFrom: string, weightTo: ?string, row: arraycreateMultiplierComponent()
Creates a multiplier for the component.
private
createMultiplierComponent(string $name) : Multiplier<string|int, IComponent>
Parameters
- $name : string
Return values
Multiplier<string|int, IComponent>createNewComponentInstance()
Creates a new component instance without adding it to the presenter; used by the multiplier.
private
createNewComponentInstance(string $baseName[, int|string|null $uniqueKey = null ]) : IComponent|null
Parameters
- $baseName : string
- $uniqueKey : int|string|null = null
Return values
IComponent|nullcreateStandardComponent()
Creates a standard component (not a multiplier).
private
createStandardComponent(string $name) : IComponent|null
Parameters
- $name : string
Return values
IComponent|nulldecimalOrNull()
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|nullduplicateShipperTariffGeneration()
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|nullentityReference()
Builds a thin shipper reference (the hydrator assembles the entity from the id).
private
entityReference(int $shipperId) : Shipper
Parameters
- $shipperId : int
Return values
ShipperfillShipperTariffGenerationContainer()
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>
findBranch()
private
findBranch(int $branchId) : ShipperTariffBranch|null
Parameters
- $branchId : int
Return values
ShipperTariffBranch|nullflashBranchGuardError()
private
flashBranchGuardError(string $messageKey) : void
Parameters
- $messageKey : string
formatBranchAddress()
private
formatBranchAddress(ShipperTariffBranch $branch) : string
Parameters
- $branch : ShipperTariffBranch
Return values
stringgetShipperTariffCurrentAxisDates()
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}httpRequest()
Returns the HTTP request through the presenter; a control, unlike a presenter, has no `getHttpRequest()`.
private
httpRequest() : IRequest
Return values
IRequestisOwnEditFormSubmit()
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
boolisShipperTariffGenerationEmpty()
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
boolisShipperTariffHistoric()
private
isShipperTariffHistoric(DateTime|null $dateFrom, DateTime $todayMidnight) : bool
Parameters
- $dateFrom : DateTime|null
- $todayMidnight : DateTime
Return values
boolloadBranchRows()
Builds the branch cards, always filtered by `isManaged`: `false` is reserved for a future bulk sync of an external shipper network and is never listed in the admin.
private
loadBranchRows() : array<int, array{id: int, name: string, address: string, active: bool}>
Return values
array<int, array{id: int, name: string, address: string, active: 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
redrawBranchesAfterMutation()
private
redrawBranchesAfterMutation() : void
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
resolveEditedTariff()
Loads the edited tariff, or returns null when adding.
private
resolveEditedTariff() : ShipperTariff|null
The shipper.id filter is the second layer of the ownership guard (the first is
ShipperPresenter::ownsTariff() before the modal opens): a forged foreign id is simply
not found.
Return values
ShipperTariff|nullresolveShipperTariffGenerationDate()
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
Return values
DateTime|nullresolveShipperTariffGenerationPrefill()
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: listresolveShipperTariffPrefillDate()
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|nullsaveShipperTariffForm()
private
saveShipperTariffForm(ArrayHash<string|int, mixed> $values, Form|null $form) : bool
Parameters
- $values : ArrayHash<string|int, mixed>
- $form : Form|null
Return values
boolsetBranchFormDefaults()
private
setBranchFormDefaults(Form $form) : void
Parameters
- $form : Form
setShipperTariffFormDefaults()
private
setShipperTariffFormDefaults(Form $form) : void
Parameters
- $form : Form
shipperPresenter()
Returns the host presenter (the only consumer of this component), or null for any other.
private
shipperPresenter() : ShipperPresenter|null
Return values
ShipperPresenter|nullshipperTariffBandContainers()
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
PaymentMethodshipperTariffValuesToArray()
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>showBranchModal()
private
showBranchModal() : void
translateShipperTariff()
private
translateShipperTariff(string $key[, array<string, string> $params = [] ]) : string
Parameters
- $key : string
- $params : array<string, string> = []
Return values
stringvalidateShipperTariffBandCoverage()
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