CoolCMS API

ProductCategoryFormTrait

Edit/add form of an eshop category, modeled on {@see \App\UI\Admin\Blog\Presenters\Traits\Forms\CategoryFormTrait}.

Multilingual fields (name, URL, editor info, meta*); untranslated: parent category (tree), icon CSS class and main photo. Unlike the Blog category it has no active/forFree/topedFirst, so no header toggles. Nested-set indexes (lft/rgt/level) are handled by the Api: save() (insertTreeNode) for a new category, moveSubtree() on a parent change. The skeleton comes from BasePresenter::createForm().

Category parameters section: targeting rows (parameterRels) chosen per row. The checkbox "use default parameters" (useDefaultParameters) sits above it and gates both the save (rels are not overwritten for defaults) and the consumer (Api ProductCategoryManager::fetchParametersForProduct()).

Feed category names section: one text field feedCategoryName_<feedId> per feed (addCategoryFeedFields()), written by the category-scoped bridge action (FeedManager::saveCategoryRels()) outside the object-graph save of the category.

Table of Contents

Properties

$categoryFeedList  : array<int, Feed>|null

Methods

createComponentEditForm()  : Form
parameterRowPicker()  : PickerConfig
Parameter picker for a `parameterRows` multiplier row; like `ParameterFieldsTrait::parameterRowPicker()` but without `submitButton` (the category has no dependent typed field to render after a choice, unlike set parameters). The closest precedent is `ProductCategoryPickerTrait::productCategoryMultiPicker()`, a plain M:N without a submit button.
addCategoryFeedFields()  : void
One optional text field per feed. The label is the real feed name from the DB, not a translation key, hence `NotTranslate` (otherwise `PrefixedTranslator` would try to translate it and render the raw string with the domain; see `InvoiceFormTrait`).
addCategoryParameterFields()  : void
Section "category parameters": multiplier `parameterRows` (hidden `parameterId` + text `parameterName`, filled by the Picker) and add/remove buttons with an AJAX redraw of the `categoryParameters` snippet (a literal name; Latte snippet names must be literals).
addCategoryUseDefaultParametersField()  : void
Checkbox "use default parameters", above the parameters section (modeled on the Bazaar `CategoryFormTrait::addCategoryParameterFields()`). Checked (the default, also the DB default) means the category contributes the global default set to the parameter aggregation and the targeting editor (`categoryParametersWrapper`) is hidden (Nette `toggle()`, netteForms.js). Unchecked means own targeting and the editor is visible. Saved as a scalar by the object-graph save ({@see buildProductCategoryEntity()}); unlike `parameterRows` (meta channel) it is not part of `$meta`.
addStructureFields()  : void
Structure: parent category (tree), icon CSS class and main photo.
addTranslationFields()  : void
Multilingual fields: one set per language (`<field>_<langId>`), active per checkbox.
applyCategoryFeedDefaults()  : void
GET prefill from {@see \App\UI\Admin\Eshop\Models\Managers\FeedManager::getCategoryRels()} (category-scoped read), not via the `Feed::$categoryRels` collection: the category does not map that collection at all (see {@see saveCategoryFeedRels()}).
applyCategoryParameterDefaults()  : void
GET defaults of the parameter rows via its own fetch {@see \App\UI\Admin\Eshop\Models\Managers\ProductCategoryManager::fetchParameterRelsForCategory()}, not via the non-owned collection `parameterRels` (sync runs through the meta channel and the collection is in Api `defaultSkipFields`). Ordered by the stored `order`; parameter names are looked up in a batch (one query, not N).
buildCategoryParameterRelsMeta()  : array<int, array{parameterId: int, order: int}>
Builds `meta['parameterRels']` from the multiplier rows; called only for own targeting (`useDefaultParameters` unchecked, see the caller {@see saveProductCategoryForm()}). An empty array means remove-all (the last own-targeting row was removed), same as for set parameters and the Bazaar category.
buildProductCategoryEntity()  : ProductCategory
categoryParameterDisplayName()  : string
Parameter name in the current language (falls back to the first non-empty one).
categoryRowField()  : mixed
Safely reads a field from a multiplier row (ArrayHash|array).
categoryRowInt()  : int
Row field as a positive int (0 when missing or non-numeric).
collectImageMeta()  : array<string, mixed>
Builds `$meta` for the save: a new image (base64) and/or the delete flag.
extractSubmittedCategoryParameterIds()  : array<int, int>
Ids of parameters from the submitted multiplier rows (`parameterRows[*][parameterId]`), deduplicated and positive. Non-row multiplier keys are skipped.
isHrefUnique()  : bool
Validates href uniqueness in the given language against other categories (the edited category is not counted on edit). An empty href (nullable) is not checked.
loadCategoryFeeds()  : array<int, Feed>
Feeds as the section axis, memoized so form build, prefill and `render()` hit the bridge once.
loadCategoryParameterNames()  : array<int, string>
resolveCategoryParameterLabel()  : string|null
saveCategoryFeedRels()  : bool
Saves the category feed names through the category-scoped bridge action ({@see \App\UI\Admin\Eshop\Models\Managers\FeedManager::saveCategoryRels()}), whose delete removes only `category_id = :categoryId`.
saveProductCategoryForm()  : bool
setProductCategoryFormDefaults()  : void
suggestCategoryParameters()  : array<int, array{id: int, label: string}>
Suggests root active parameters by name, skipping rows already chosen (the picker suggest AJAX call carries the whole current form state in a POST, so `parameterRows` reflects the live rows, not just the stored state).

Properties

$categoryFeedList

private array<int, Feed>|null $categoryFeedList = null

memoized feeds (the section axis), read by the form build and the template

Methods

parameterRowPicker()

Parameter picker for a `parameterRows` multiplier row; like `ParameterFieldsTrait::parameterRowPicker()` but without `submitButton` (the category has no dependent typed field to render after a choice, unlike set parameters). The closest precedent is `ProductCategoryPickerTrait::productCategoryMultiPicker()`, a plain M:N without a submit button.

protected parameterRowPicker() : PickerConfig

Registered in pickers() of the presenter (ProductCategoryPresenter).

Return values
PickerConfig

addCategoryFeedFields()

One optional text field per feed. The label is the real feed name from the DB, not a translation key, hence `NotTranslate` (otherwise `PrefixedTranslator` would try to translate it and render the raw string with the domain; see `InvoiceFormTrait`).

private addCategoryFeedFields(Form $form) : void

NOTE: setTranslator(null) on the label is not enough: Nette BaseControl::getLabel() always takes the translator from the form ($this->getForm()->getTranslator()), not from the per-control override (which only affects select items). It must be NotTranslate.

Parameters
$form : Form

addCategoryParameterFields()

Section "category parameters": multiplier `parameterRows` (hidden `parameterId` + text `parameterName`, filled by the Picker) and add/remove buttons with an AJAX redraw of the `categoryParameters` snippet (a literal name; Latte snippet names must be literals).

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

addCategoryUseDefaultParametersField()

Checkbox "use default parameters", above the parameters section (modeled on the Bazaar `CategoryFormTrait::addCategoryParameterFields()`). Checked (the default, also the DB default) means the category contributes the global default set to the parameter aggregation and the targeting editor (`categoryParametersWrapper`) is hidden (Nette `toggle()`, netteForms.js). Unchecked means own targeting and the editor is visible. Saved as a scalar by the object-graph save ({@see buildProductCategoryEntity()}); unlike `parameterRows` (meta channel) it is not part of `$meta`.

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

addStructureFields()

Structure: parent category (tree), icon CSS class and main photo.

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

addTranslationFields()

Multilingual fields: one set per language (`<field>_<langId>`), active per checkbox.

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

applyCategoryFeedDefaults()

GET prefill from {@see \App\UI\Admin\Eshop\Models\Managers\FeedManager::getCategoryRels()} (category-scoped read), not via the `Feed::$categoryRels` collection: the category does not map that collection at all (see {@see saveCategoryFeedRels()}).

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

applyCategoryParameterDefaults()

GET defaults of the parameter rows via its own fetch {@see \App\UI\Admin\Eshop\Models\Managers\ProductCategoryManager::fetchParameterRelsForCategory()}, not via the non-owned collection `parameterRels` (sync runs through the meta channel and the collection is in Api `defaultSkipFields`). Ordered by the stored `order`; parameter names are looked up in a batch (one query, not N).

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

buildCategoryParameterRelsMeta()

Builds `meta['parameterRels']` from the multiplier rows; called only for own targeting (`useDefaultParameters` unchecked, see the caller {@see saveProductCategoryForm()}). An empty array means remove-all (the last own-targeting row was removed), same as for set parameters and the Bazaar category.

private buildCategoryParameterRelsMeta(ArrayHash<string|int, mixed> $values) : array<int, array{parameterId: int, order: int}>

order is the row order in the form. required/useInSearch/group are not exposed in the UI; the Api sync trait defaults them to false/false/null.

Parameters
$values : ArrayHash<string|int, mixed>
Return values
array<int, array{parameterId: int, order: int}>

categoryParameterDisplayName()

Parameter name in the current language (falls back to the first non-empty one).

private categoryParameterDisplayName(Parameter $parameter) : string
Parameters
$parameter : Parameter
Return values
string

categoryRowField()

Safely reads a field from a multiplier row (ArrayHash|array).

private categoryRowField(mixed $row, string $key) : mixed
Parameters
$row : mixed
$key : string

categoryRowInt()

Row field as a positive int (0 when missing or non-numeric).

private categoryRowInt(mixed $row, string $key) : int
Parameters
$row : mixed
$key : string
Return values
int

collectImageMeta()

Builds `$meta` for the save: a new image (base64) and/or the delete flag.

private collectImageMeta(ArrayHash<string|int, mixed> $values) : array<string, mixed>

The Api makes an Asset (variants) from it and sets the FK to the main image.

Parameters
$values : ArrayHash<string|int, mixed>
Return values
array<string, mixed>

extractSubmittedCategoryParameterIds()

Ids of parameters from the submitted multiplier rows (`parameterRows[*][parameterId]`), deduplicated and positive. Non-row multiplier keys are skipped.

private extractSubmittedCategoryParameterIds() : array<int, int>
Return values
array<int, int>

isHrefUnique()

Validates href uniqueness in the given language against other categories (the edited category is not counted on edit). An empty href (nullable) is not checked.

private isHrefUnique(TextInput $input, int $langId) : bool
Parameters
$input : TextInput
$langId : int
Return values
bool

loadCategoryFeeds()

Feeds as the section axis, memoized so form build, prefill and `render()` hit the bridge once.

private loadCategoryFeeds() : array<int, Feed>
Return values
array<int, Feed>

loadCategoryParameterNames()

private loadCategoryParameterNames(array<int, int> $parameterIds) : array<int, string>
Parameters
$parameterIds : array<int, int>
Return values
array<int, string> —

id to name

resolveCategoryParameterLabel()

private resolveCategoryParameterLabel(int $id) : string|null
Parameters
$id : int
Return values
string|null

saveCategoryFeedRels()

Saves the category feed names through the category-scoped bridge action ({@see \App\UI\Admin\Eshop\Models\Managers\FeedManager::saveCategoryRels()}), whose delete removes only `category_id = :categoryId`.

private saveCategoryFeedRels(int $categoryId, ArrayHash<string|int, mixed> $values) : bool

IMPORTANT: deliberately outside the object-graph save of the category. Mapping FeedProductCategoryRel as an owned collection of ProductCategory would make every category save without the matching includes (subtree move, grid actions, other forms) delete the mappings via orphanRemoval. The dedicated action does not depend on the caller's includes.

An empty field means no mapping for that feed (the row disappears).

Parameters
$categoryId : int
$values : ArrayHash<string|int, mixed>
Return values
bool

saveProductCategoryForm()

private saveProductCategoryForm(ArrayHash<string|int, mixed> $values) : bool
Parameters
$values : ArrayHash<string|int, mixed>
Return values
bool

suggestCategoryParameters()

Suggests root active parameters by name, skipping rows already chosen (the picker suggest AJAX call carries the whole current form state in a POST, so `parameterRows` reflects the live rows, not just the stored state).

private suggestCategoryParameters(string $query) : array<int, array{id: int, label: string}>
Parameters
$query : string
Return values
array<int, array{id: int, label: string}>
On this page

Search results