CoolCMS API

PageFormTrait

Add/edit form of a front-end page.

The skeleton comes from createForm(); fields are split into addXxxFields(), labels use tree translation keys via $t = $form->getTranslateFnc(). Saving goes through manager->save() and then flash plus PRG redirect.

The relation field parentId is a hidden form field rendered by Picker (see pickers() in the presenter). The route multiselect is filled through RouteManager and saved via the M:N Page::$routes. The css/layout file selects are plain text inputs when the theme offers no files.

Table of Contents

Constants

CHANGEFREQ_VALUES  : mixed = ['always', 'hourly', 'daily', 'weekly', 'monthl...
Allowed `changefreq` (sitemap) values; translated in the template through options.

Methods

createComponentEditForm()  : Form
addBehaviorFields()  : void
Visibility and behavior switches of the page.
addCssField()  : void
CSS files of the page: multiselect of theme CSS files ({@see \App\UI\Admin\System\Models\Managers\PageManager::scanTemplateCssFiles()}), stored as a comma-separated list of names. Degrades to a text input without files.
addLayoutField()  : void
Layout field: select of layout files of the active front-end theme ({@see \App\UI\Admin\System\Models\Managers\PageManager::scanTemplateLayoutFiles()}).
addNavigationFields()  : void
Navigation and structure: parent page (picker) and theme layout files.
addRouteFields()  : void
Routes assigned to the page: multiselect filled through {@see \App\UI\Admin\System\Models\Managers\RouteManager}.
addSeoFields()  : void
SEO: update frequency and sitemap priority.
addTechnicalFields()  : void
Technical settings: CSS files (multiselect), HTML class, internal notes.
addTranslationFields()  : void
Multilingual fields: one set per language (`<field>_<langId>`), active by checkbox.
applyRoutes()  : void
Overwrites the M:N relation of the page to routes by the ids selected in the multiselect.
buildPageEntity()  : Page
buildRouteMenuProblemMessage()  : string
Builds the finished message text (no translation key); {@see BaseControl::addError()} receives it with `translate: false`.
collectRouteIds()  : array<int, int>
Returns ids of routes assigned to the page (to prefill the multiselect on edit).
collectRouteMenuProblems()  : array<int, array{route: string, params: list, lang: string|null}>
Decides, for every selected route, what exactly would break the menu link.
cssToString()  : string
Converts the CSS field value to the stored string: the multiselect returns a name array (joined by commas), the text input a plain string.
findPageByHref()  : Page|null
Returns a page with the same `href` in the given language (other than the edited one).
getFormLanguages()  : array<int, Language>
Returns languages for the multilingual form fields (admin `LanguageManager`).
languageLabel()  : string
Short language code for the message (`cs`, `en`), not the full name: technical context of the route choice.
pageIsInMenu()  : bool
Tells whether the page `$pageId` is linked in any menu. Only existence, not the item: `cms_system_menu_items.cms_system_pages_page_id` filtered through the `page.id` association ({@see EqualFilter} auto-joins the dotted path, like `CategoryManager::findAll()` does for `'translations.href'`).
pageTitleForLang()  : string
Returns the colliding page label for the message: title, else name, else `#id`.
prepareCssOptions()  : array<string, string>
CSS multiselect options: theme files plus names stored on the page (on edit), even when the file has disappeared.
prepareLayoutOptions()  : array<string, string>
Layout select options: theme files plus the values stored on the page (on edit), even when the file has disappeared, so the select can still be prefilled.
prepareRouteOptions()  : array<int, string>
Options of the route multiselect: `id => "module presenter:action"`, alphabetical.
reportCustomAssetTabFailure()  : bool
Adds a danger flash (and an optional log entry) and returns false; shared by all failed tab-save results.
reportCustomAssetTabSuccess()  : bool
Adds a success flash plus `savedEntityId` (for `apply`) and returns true.
saveEditForm()  : bool
Saves the form data. The redirect is done by {@see \App\Core\Base\Admin\BasePresenter::createForm()} according to the pressed button.
savePageWithCustomAssets()  : bool
Saves the page and then its own custom code set (the "custom code" tab). The decision logic (what to call, in which order, how to react to failure) lives in {@see CustomAssetTabSaveTrait::persistPageCustomAssetsTab()}; here the result is only mapped to flash messages.
setCustomAssetTabDefaults()  : void
Defaults of the custom code tab: set on the whole form (`setDefaults`), not `setValues` on the multiplier container. Edit = codes assigned to the page; add = codes with `addToNewPages = 1`. Without the `assign` privilege the field does not exist in the form ({@see CustomAssetTabTrait::addCustomAssetTab()}), so `setDefaults()` silently skips the key.
setEditFormDefaults()  : void
splitCss()  : array<int, string>
Splits the stored comma-separated CSS string into file names.
str()  : string
Safely converts a mixed form value to string (NEON/ArrayHash).
tr()  : string
Translates a key in the form domain to a finished string (for fields with `setTranslator(null)`).
validateHrefUniqueness()  : bool
Requires the `href` to be unique within one language.
validateRouteMenuCompatibility()  : bool
Blocks a route whose mask needs a parameter the menu cannot fill.

Constants

CHANGEFREQ_VALUES

Allowed `changefreq` (sitemap) values; translated in the template through options.

private mixed CHANGEFREQ_VALUES = ['always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never']

Methods

addBehaviorFields()

Visibility and behavior switches of the page.

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

addCssField()

CSS files of the page: multiselect of theme CSS files ({@see \App\UI\Admin\System\Models\Managers\PageManager::scanTemplateCssFiles()}), stored as a comma-separated list of names. Degrades to a text input without files.

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

addLayoutField()

Layout field: select of layout files of the active front-end theme ({@see \App\UI\Admin\System\Models\Managers\PageManager::scanTemplateLayoutFiles()}).

private addLayoutField(Form $form, string $name, bool $required) : void

Options are file names, so the control translator is off and the label is translated by hand. Degrades to a text input when the theme offers no file, so the form stays usable.

Parameters
$form : Form
$name : string
$required : bool

addNavigationFields()

Navigation and structure: parent page (picker) and theme layout files.

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

addRouteFields()

Routes assigned to the page: multiselect filled through {@see \App\UI\Admin\System\Models\Managers\RouteManager}.

private addRouteFields(Form $form) : void

Options are technical strings (module + presenter:action), so the control translator is off and the label is translated by hand.

Parameters
$form : Form

addSeoFields()

SEO: update frequency and sitemap priority.

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

addTechnicalFields()

Technical settings: CSS files (multiselect), HTML class, internal notes.

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

addTranslationFields()

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

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

applyRoutes()

Overwrites the M:N relation of the page to routes by the ids selected in the multiselect.

private applyRoutes(Page $page, ArrayHash<string|int, mixed> $values) : void

Routes are loaded through RouteManager (InFilter) so that real references are stored (Doctrine synchronizes the join table cms_system_page_route_rel).

Parameters
$page : Page
$values : ArrayHash<string|int, mixed>

buildPageEntity()

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

buildRouteMenuProblemMessage()

Builds the finished message text (no translation key); {@see BaseControl::addError()} receives it with `translate: false`.

private buildRouteMenuProblemMessage(array<int, array{route: string, params: list, lang: string|null}> $problems) : string
Parameters
$problems : array<int, array{route: string, params: list, lang: string|null}>
Return values
string

collectRouteIds()

Returns ids of routes assigned to the page (to prefill the multiselect on edit).

private collectRouteIds(Page $page) : array<int, int>
Parameters
$page : Page
Return values
array<int, int>

collectRouteMenuProblems()

Decides, for every selected route, what exactly would break the menu link.

private collectRouteMenuProblems(array<int, Route> $routes, ArrayHash<string|int, mixed> $values) : array<int, array{route: string, params: list, lang: string|null}>

Unsatisfiable non-slug parameters (name, id, order_id, ...) are always a problem because the menu never supplies them. A missing slug is a problem only for languages whose href_<langId> is empty in the submitted form; all form languages are checked, not only those with the active checkbox, because Link.latte reads href regardless of active.

Parameters
$routes : array<int, Route>
$values : ArrayHash<string|int, mixed>
Return values
array<int, array{route: string, params: list, lang: string|null}>

cssToString()

Converts the CSS field value to the stored string: the multiselect returns a name array (joined by commas), the text input a plain string.

private cssToString(mixed $value) : string
Parameters
$value : mixed
Return values
string

findPageByHref()

Returns a page with the same `href` in the given language (other than the edited one).

private findPageByHref(string $href, int $langId, int|null $excludeId) : Page|null

The translations.href filter matches pages having the address in any language (the dotted path is auto-joined, see pageIsInMenu()), so the language match is confirmed on the loaded translations; two filters over one collection would not guarantee the same row.

Parameters
$href : string
$langId : int
$excludeId : int|null
Return values
Page|null

getFormLanguages()

Returns languages for the multilingual form fields (admin `LanguageManager`).

private getFormLanguages() : array<int, Language>
Return values
array<int, Language>

languageLabel()

Short language code for the message (`cs`, `en`), not the full name: technical context of the route choice.

private languageLabel(Language $language) : string
Parameters
$language : Language
Return values
string

pageIsInMenu()

Tells whether the page `$pageId` is linked in any menu. Only existence, not the item: `cms_system_menu_items.cms_system_pages_page_id` filtered through the `page.id` association ({@see EqualFilter} auto-joins the dotted path, like `CategoryManager::findAll()` does for `'translations.href'`).

private pageIsInMenu(int $pageId) : bool
Parameters
$pageId : int
Return values
bool

pageTitleForLang()

Returns the colliding page label for the message: title, else name, else `#id`.

private pageTitleForLang(Page $page, int $langId) : string
Parameters
$page : Page
$langId : int
Return values
string

prepareCssOptions()

CSS multiselect options: theme files plus names stored on the page (on edit), even when the file has disappeared.

private prepareCssOptions() : array<string, string>
Return values
array<string, string>

prepareLayoutOptions()

Layout select options: theme files plus the values stored on the page (on edit), even when the file has disappeared, so the select can still be prefilled.

private prepareLayoutOptions() : array<string, string>
Return values
array<string, string>

prepareRouteOptions()

Options of the route multiselect: `id => "module presenter:action"`, alphabetical.

private prepareRouteOptions() : array<int, string>
Return values
array<int, string>

reportCustomAssetTabFailure()

Adds a danger flash (and an optional log entry) and returns false; shared by all failed tab-save results.

private reportCustomAssetTabFailure(string $messageKey[, string|null $logMessage = null ]) : bool
Parameters
$messageKey : string
$logMessage : string|null = null
Return values
bool

reportCustomAssetTabSuccess()

Adds a success flash plus `savedEntityId` (for `apply`) and returns true.

private reportCustomAssetTabSuccess(Page $page) : bool
Parameters
$page : Page
Return values
bool

saveEditForm()

Saves the form data. The redirect is done by {@see \App\Core\Base\Admin\BasePresenter::createForm()} according to the pressed button.

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

A parentId change of an existing page is reported by the Api through meta['moveSubtreeToParentId'], so the lft/rgt/level recalculation of the whole subtree runs in the same transaction as the parent_id write.

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

true when the page was saved

savePageWithCustomAssets()

Saves the page and then its own custom code set (the "custom code" tab). The decision logic (what to call, in which order, how to react to failure) lives in {@see CustomAssetTabSaveTrait::persistPageCustomAssetsTab()}; here the result is only mapped to flash messages.

private savePageWithCustomAssets(ArrayHash<string|int, mixed> $values, Page $page, array<string, mixed> $meta, bool $isInsert) : bool
Parameters
$values : ArrayHash<string|int, mixed>
$page : Page
$meta : array<string, mixed>
$isInsert : bool

true when the page was created in this request

Return values
bool

setCustomAssetTabDefaults()

Defaults of the custom code tab: set on the whole form (`setDefaults`), not `setValues` on the multiplier container. Edit = codes assigned to the page; add = codes with `addToNewPages = 1`. Without the `assign` privilege the field does not exist in the form ({@see CustomAssetTabTrait::addCustomAssetTab()}), so `setDefaults()` silently skips the key.

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

splitCss()

Splits the stored comma-separated CSS string into file names.

private splitCss(string|null $css) : array<int, string>
Parameters
$css : string|null
Return values
array<int, string>

str()

Safely converts a mixed form value to string (NEON/ArrayHash).

private str(mixed $value) : string
Parameters
$value : mixed
Return values
string

tr()

Translates a key in the form domain to a finished string (for fields with `setTranslator(null)`).

private tr(string $key) : string
Parameters
$key : string
Return values
string

validateHrefUniqueness()

Requires the `href` to be unique within one language.

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

IMPORTANT: the router derives the page id from the slug through slugToId[language][href] = pageId (PageSlugTranslator). On a collision the last written page overrides the previous one, which becomes unreachable on the website, while idToSlug still generates the same address for both: a redirect after an action leads to the wrong page and no error appears.

The check is global on purpose (across modules and tree branches) because the router map is one per language. An empty href is not checked; such a page is not in the map.

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

validateRouteMenuCompatibility()

Blocks a route whose mask needs a parameter the menu cannot fill.

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

A page placed in the menu (cms_system_menu_items) gets such a route, and the menu would crash: MenuComponent passes only slug (from the page translation href) to safeLink() (\App\UI\Front\System\Components\MenuComponent\Templates\Default\parts\Link.latte). SafeLinkExtension would degrade the link to '#', but that is a safety net, not a goal.

IMPORTANT: the boundary is "the page is in the menu", not "the route has parameters". Parametric routes (for example article detail with name and id) are legitimate: the list component supplies the parameters and no link is generated from the menu context. A general "route has an unsatisfiable parameter" check would forbid that widely used pattern. A new page ($this->editedPage === null) cannot be in the menu, because the menu links an existing page_id (MenuItemFormTrait), so the check is skipped on add.

Every selected route is checked, not only getRoutes()->first() that the menu really uses: the order of the stored collection is not the order of the multiselect selection.

Parameters
$values : ArrayHash<string|int, mixed>
Return values
bool
On this page

Search results