CoolCMS API

DataGrid extends BaseComponent
in package
uses InitializationTrait, FormTrait, HandleTrait, CsvExportTrait, TreeStateTrait, TreeMoveTrait

Generic admin datagrid: a table overview of the records of any Admin manager ({@see Manager}).

Reads data through findAll() (filtering, sorting and paging run in the Api layer via ApiBridge) and updates or deletes through updateColumns() / delete(). State (page, sort, search values) lives in persistent parameters, so it survives in the URL without depending on the presenter.

Usage (columns and actions are passed as ready objects; see PagePresenter):

$grid = $this->dataGridFactory->create();
$grid->setDataSource($this->pageManager)->setIncludes(['translations']);
$grid->addColumn(Column::create('name')->setProperty('translations.name')->setSortable());
$grid->addRowAction(RowAction::create('edit')->setLink(':Admin:System:Page:edit', ['id' => 'id']));

Table of Contents

Constants

CONFIRM_FIELD  : string = '_confirmed'
POST flag of a confirmed delete; the confirmation modal (`datagrid.js`) adds it, the server deletes nothing without it ({@see HandleTrait::requireDeleteConfirmation()}).
PER_PAGE_OPTIONS  : mixed = [25, 50, 100]
Page-size choices (header links; "Default" is null).
TREE_CHILDREN_LIMIT  : mixed = 500
Default cap of children of one parent in a tree; see {@see setTreeChildrenLimit()}.
TREE_FULL_LIMIT  : mixed = 500
A tree up to this many nodes (within the scope) opens fully expanded on first view, "Expand all" is refused above it, and a non-collapsible tree ({@see setTreeCollapsible()}) behaves as collapsible above it as a safeguard.
TREE_SESSION_MAX_IDS  : mixed = 5000
At most this many expanded node ids are kept in the session (guard against bloat).
VIEW_LIST  : mixed = 'list'
VIEW_TREE  : mixed = 'tree'
CSV_BATCH_SIZE  : int = 500
Batch size for reading `findAll()` incrementally.
CSV_DELIMITER  : string = ';'
Field delimiter: a semicolon (Czech Excel convention), not a comma.

Properties

$container  : Container
$dir  : string|null
Sort direction `asc`|`desc`.
$filters  : array<string, mixed>
Values of the search fields keyed by column name. Range stores `['from' => …, 'to' => …]`, multiselect an array of values.
$orderBy  : string|null
Column name the list is sorted by (click on the heading).
$page  : int
$perPage  : int|null
User override of rows per page; null means the default (`setItemsPerPage()`).
$reorder  : bool
"Reorder" mode: switches a tree grid from the flat table (arrows) to the nested drag & drop view ({@see isDragView()}). The user turns it on with a toolbar button; it applies only in the tree view.
$routerDispatcher  : RouterDispatcher
$translator  : ITranslator
$treeRoot  : int|null
Tree focus: the grid shows only the subtree of the node with this id (children are the first level) and a breadcrumb above it. Persistent so the URL can be shared; the expansion state is kept in the session instead ({@see TreeStateTrait}). null means the whole tree.
$view  : string|null
Tree grid view: `list` is the flat paged list with a "Path" column (default), `tree` the hierarchy with ▸/▾ and focus. The choice is remembered in the session per grid ({@see TreeStateTrait::isTreeViewChosen()}); null means session / default.
$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|null
$addDestination  : string|null
$addParams  : array<string, mixed>
$addPrivilege  : string|null
Privilege key of the "add" button; `null` derives it, `''` never hides. See {@see setAddLink()}.
$columns  : array<string, BaseColumn>
$csvExportEnabled  : bool
Whether the CSV export button is shown in the grid toolbar; off by default. Enabled by {@see enableCsvExport()}, served by {@see CsvExportTrait::handleCsvExport()}.
$csvExportFileName  : string|null
$dataSource  : Manager<BaseEntity, ServiceInterface<string|int, BaseEntity>>|null
$defaultFilters  : array<string|int, Filter>
$defaultOrder  : array<string, bool>
$defaultOrderCustomized  : bool
Whether the presenter already overrode the default order; see {@see self::setDefaultOrder()}.
$deleteMethod  : string
Name of the manager method called by the `delete!` signal ({@see HandleTrait::handleDelete()}) and the group action 'delete' ({@see FormTrait::processGroupAction()}). Defaults to `'delete'` (hard delete).
$dragDrop  : bool
Drag & drop move of tree nodes; enabled via {@see enableDragDrop()}.
$dragFlat  : bool
Flat drag mode: SortableJS runs only over the root list of siblings and nested lists (drop targets for changing the parent) are not initialized. For grids that may only reorder, not change the parent (e.g. main parameters).
$explainedDeleteFailures  : array<int, true>
Delete result codes whose message from the `results` domain is shown to the admin instead of the generic failure message, see {@see explainDeleteFailures()}.
$explainedUpdateFailures  : array<int, true>
Inline update (toggle, select) result codes whose message from the `results` domain is shown instead of the generic failure, see {@see explainUpdateFailures()}.
$filterControlNames  : array<string, string>|null
Column => name of its filter control; computed lazily once.
$groupActions  : array<string, GroupAction>
$highlightId  : int|null
Highlighted row, the target of the "Show in tree" action. The `highlight` parameter is one-shot (not persistent): only the action link carries it, other grid links do not, and the JS removes it from the URL after scrolling the row into view, so a reload does not highlight.
$includes  : array<string|int, string>
$initialized  : bool
$itemIdentifier  : string
$items  : array<int, object>
$itemsById  : array<int, object>
$itemsPerPage  : int
$moveNode  : object|null
Node being moved in this request (signal or modal submit).
$moveNotices  : array<int, array{key: string, type: string}>
Messages inside the modal; per request, not a session flash, which would resurface on the next open.
$pendingConfirmation  : array{message: ?string, actionLabel: ?string, ids: list, action: string, fields: list}|null
Delete waiting for confirmation (no flag in the POST): message of the action, record ids, the URL and the POST fields to repeat. `render()` then draws the confirmation page.
$pickerData  : array<string, string>
$pickerExcludeId  : int|null
Id of the record that cannot be picked (self-reference); its row gets no "Select".
$pickerExcludeSubtreeLft  : int|null
lft/rgt of the whole subtree that cannot be picked (moving a node under its descendant).
$pickerExcludeSubtreeRgt  : int|null
$pickerFactory  : PickerFactory|null
$pickerLabelCallback  : callable(object): string|null
$pickerLabelProperty  : string|null
$pickerMode  : bool
Picker mode: the grid serves as a record picker for a foreign form.
$pickerName  : string
$rowActions  : array<string|int, RowAction>
$rowDecorator  : callable(array<int, object> $items): void|null
Optional decorator of the loaded page of records. It is called once with the whole page (not per row), so it can run one batch query and write the values into `#[Transient]` entity properties via setters. For columns that cannot be computed from one entity (an aggregate over a foreign table, e.g. stock summed over warehouses) without the grid knowing JOIN/GROUP BY.
$totalCount  : int
$tree  : bool
$treeChildrenLimit  : int
$treeCollapsible  : bool
Collapsible tree (▸/▾, focus, session); `false` means always fully expanded (menu).
$treeDefaultView  : string
Default view of a tree grid until the user switches it.
$treeLimitLogged  : bool
The non-collapsible tree safeguard has already logged (render and signal in one request).
$treeMeta  : array<int, array{level: int, parentId: int, hasChildren: bool, expanded: bool, up: bool, down: bool}>
Metadata of the visible tree nodes ({@see TreeRowsBuilder}).
$treeMoreAfter  : array<int, array<int, array{parentId: int, count: int, level: int}>>
$treeNested  : array<int, array{id: int, children: array, more: int}>
$treeNodeCount  : int|null
$treeOrderProperty  : string
$treeParentProperty  : string
$treePaths  : array<int, array{full: string, short: string, segments: list}>
Paths of the rows of the current flat list page ({@see loadTreePaths()}).
$treePositionFactory  : TreePositionFactory|null
$treeRightProperty  : string|null
$treeRootMissing  : bool
The focused node from the URL does not exist (deleted or foreign scope); the template shows a notice.
$treeRootMore  : int
How many children of the view root did not fit under the cap.
$treeRootNode  : object|null
$treeRootResolved  : bool
$treeScope  : array<string, scalar|null>

Methods

__call()  : mixed
Dispatches `renderXyz()` to `render('Xyz', ...$args)`.
__construct()  : mixed
addColumn()  : self
addDefaultFilter()  : self
Core filter applied on every load (grid scope).
addGroupAction()  : self
addRowAction()  : self
buildCellHref()  : string|null
Returns the href the cell content is wrapped in when the column has a link ({@see BaseColumn::setLink()}). Parameters are mapped from row properties. In picker mode links are suppressed because a selection must not leave the modal. When a required parameter ({@see BaseColumn::getLinkRequiredParams()}) is missing (null / ''), no link is generated, a guard against broken links and a crash on a missing id.
buildRowActionHref()  : string
Row action URL (a presenter link, or a grid signal with the record id).
buildShowInTreeHref()  : string
Builds the "Show in tree" link: cancels search, ordering and page, focuses the parent of the row (a root means no focus; a non-collapsible tree has no focus) and highlights the row once.
canMoveNodes()  : bool
Tells whether "Move to..." is offered; same gate as drag and drop (a flat drag must not change the parent).
canReorder()  : bool
Returns whether the "Reorder" view can be switched on. Drag & drop over a tree outside picker mode is enough; the button is available also with user sorting or a filter (flat table).
canSortChildren()  : bool
Tells whether "sort children alphabetically" is offered.
createComponent()  : IComponent|null
enableCsvExport()  : self
Enables the "Export CSV" button in the grid toolbar; opt-in, without the call the grid is unchanged and no export code runs. The export reads the current filter and sort state and all rows (no paging, in batches; see {@see CsvExportTrait}); columns are the visible grid columns (not actions).
enableDragDrop()  : self
Enables drag & drop move of nodes in a tree grid. Works only when {@see setTreeStructure()} is set and the manager implements {@see \App\Core\Traits\Api\Models\Managers\TreeTrait::moveSubtreeTo()}.
explainDeleteFailures()  : self
Opts in to showing domain reasons for a rejected delete to the admin (e.g. a job cannot be deleted because it contains invoiced work sheets).
explainUpdateFailures()  : self
Opts in to showing the domain reason of a refused inline update (e.g. the only default PDF layout cannot be turned off). Same rules as {@see explainDeleteFailures()}: each code needs a `results.<camelCase>` translation in cs/en/sk, generic codes do not belong here.
getAppContext()  : AppContext
getAttachedPresenter()  : Presenter
Presenter of the grid; the component is always attached during render and signals.
getBodySnippetNames()  : array{string, string}
Returns the whole body snippet and the area with `row-<id>` rows for the current view.
getColumn()  : BaseColumn|null
getComponentParameter()  : mixed
Returns a component parameter, or null when it is not set.
getContainer()  : Container
getCurrencyContext()  : CurrencyContext|null
getDataSource()  : Manager<BaseEntity, ServiceInterface<string|int, BaseEntity>>|null
getFilterControlName()  : string
Returns the form control name of the filter of the given column.
getHighlightId()  : int|null
getItemId()  : int
Record primary key.
getItemParentId()  : int
Parent id of a tree node (0 is the real root).
getItemsPerPage()  : int
Effective rows per page (user override, otherwise the default).
getLanguageContext()  : LanguageContext|null
getLocalizationContext()  : LocalizationContext|null
getMoveNotices()  : array<int, array{key: string, type: string}>
Returns the messages for the modal; the template translates them by the full grid domain key.
getNestedItems()  : array<int, array{item: object, children: array, more: int, meta: array}>
Returns the list items as a nested tree for the drag & drop template; SortableJS Nested Sortables needs genuine `<ul>/<li>` nesting, not a flat table. Built from the same data as the table ({@see \App\UI\Admin\System\Components\DataGridComponent\Utils\TreeRowsBuilder}); `more` is the number of children above the cap, `meta` the expansion / has-children state.
getPickerData()  : string
Row data for picking in picker mode; JSON `{key: value}` for `data-pick-data`.
getPickerLabel()  : string
Row label for picking in picker mode; returned to the opener (hidden + text).
getRouterDispatcher()  : RouterDispatcher
getRowLabel()  : string
Returns the accessible name of a row for the bulk-action checkbox: same source as {@see getPickerLabel()} (first non-id column / picker label property or callback) but with a different fallback: an empty label becomes "#<id>", never a bare anonymous `ids[]`.
getSettingContext()  : SettingContext
getSettings()  : array<int, array<string, mixed>>
getThemeContext()  : ThemeContext|null
getTreeLabel()  : string
Returns the node label for breadcrumbs: the value of the indented column, otherwise the picker label.
getTreePath()  : array{full: string, short: string, segments: list}|null
groupActionPrivilege()  : string|null
Returns the privilege that governs the given group action, or null when it has none.
handleCollapse()  : void
handleCollapseAll()  : void
Collapses everything, also outside the focus (nothing visible there is lost by collapsing).
handleCsvExport()  : void
handleDelete()  : void
handleDragDrop()  : void
Moves a node in the tree by drag and drop, changing the parent and the position among siblings.
handleExpand()  : void
handleExpandAll()  : void
Expands the whole current (focused) subtree, only up to {@see DataGrid::TREE_FULL_LIMIT} nodes in total; above it a "focus a smaller branch" message is shown and the state stays unchanged.
handleInlineUpdate()  : void
handleMoveDown()  : void
handleMoveModal()  : void
Opens the "Move to..." modal for a node (AJAX; without JS it just returns to the list).
handleMoveUp()  : void
handleRelationToggle()  : void
Toggles a join table link, a {@see RelationColumn} cell (a flag from a related collection picked by `scope`, e.g. a role in the RBAC matrix).
handleSortChildren()  : void
Sorts the direct children of a parent by label (current language collation) in one operation under the tree lock. `parentId` 0 is the root level of the view (the real roots without focus).
handleTreeRefresh()  : void
Only redraws the tree body; the JS calls it after a rejected move (`TREE_STALE`) or a parent change.
hasServiceByType()  : bool
Returns whether the container has a service of the given type.
initializeAllContexts()  : void
injectDeviceDetector()  : void
isActionAllowed()  : bool
Returns whether the user has the privilege for the given action (`del`, `export`…) in this list.
isCsvExportEnabled()  : bool
isDeleteAllowed()  : bool
Returns whether the user may delete in this list; one answer for the whole grid.
isDragDropEnabled()  : bool
isDragFlat()  : bool
Flat drag mode (reordering only, no parent change); see {@see enableDragDrop()}.
isDragView()  : bool
Returns whether the tree drag & drop view is active: a nested `<ul>/<li>` list with SortableJS Nested Sortables. It requires a tree ({@see canReorder()}) and the user having switched on "Reorder" (persistent `reorder`).
isPickerMode()  : bool
isPickerSelectable()  : bool
Whether the row can be picked in picker mode (false when excluded, e.g. self-reference or descendant).
isTreeCollapsible()  : bool
Tells whether the tree can be collapsed.
isTreePathVisible()  : bool
Tells whether the flat list shows the "Path" column and the "Show in tree" action: only a tree grid with a right bound (ancestors are found from `lft/rgt`) outside the tree view, where indentation and breadcrumbs carry the path.
isTreeViewChosen()  : bool
Tells whether the tree view is chosen: the `view` URL parameter (stored in the session), otherwise the session, otherwise the grid default. The picker modal (parent selection) and a tree without a right bound ("has children" cannot be told, so always whole) always use the tree.
loadState()  : void
Validates the persistent parameters from the URL.
onCreate()  : void
prepareCell()  : array{template: string, vars: array, link: ?string, linkTarget: ?string}
Prepares a cell: the column value plus renderer variables for the template `Templates/Default/Cells/<template>.latte`. `link` is the href the template wraps the cell content in ({@see BaseColumn::setLink()}), or null.
render()  : void
setAddLink()  : self
"Add" button above the table; not shown unless set.
setAppContext()  : $this
setComponentParameter()  : void
Sets a component parameter.
setCurrencyContext()  : $this
setDataSource()  : self
Manager the grid reads data from (`findAll()`) and saves changes to.
setDefaultOrder()  : self
Default list order. The first call drops the built-in `id DESC`, further calls add another level (`setDefaultOrder('type')->setDefaultOrder('name')`).
setDeleteMethod()  : self
Switches the delete signal and group action to another manager method; see {@see $deleteMethod}.
setIncludes()  : self
setItemIdentifier()  : self
Property with the record primary key (default `id`).
setItemsPerPage()  : self
Default rows per page; the user can override it with the 25/50/100 links.
setLanguageContext()  : $this
setLocalizationContext()  : $this
setPickerData()  : self
Further data carried by the "Select" button (`data-pick-data` JSON); JS spreads it into the opener's fields by the picker `fieldMap`. Fills several fields at once (not only the label), e.g. a user's e-mail and company.
setPickerExcludeId()  : self
Id of the record that cannot be picked in picker mode (self-reference); its row gets no "Select" button. 0 / null means no exclusion.
setPickerExcludeSubtree()  : self
lft/rgt range of the subtree that cannot be picked in picker mode. Excludes the root and all descendants (a node cannot be moved under its descendant). The entity must support `getLft()` (duck typing).
setPickerLabelCallback()  : self
Label for "Select" computed from the whole entity; use it when one property is not enough (empty for some records, or several fields must be combined). Takes precedence over {@see setPickerLabelProperty()}.
setPickerLabelProperty()  : self
Property for the "Select" button label (what is returned to the opener); defaults to the first non-id column.
setPickerMode()  : self
Picker mode: the grid serves as a record picker for a foreign form (a modal opened by {@see \App\UI\Admin\System\Components\PickerComponent\Picker}). Hides add, row checkboxes, edit/delete actions and group actions, and gives each row a "Select" action ({@see Templates/Default/Parts/_body.latte}). Filtering, sorting and paging stay; inside the modal they run via AJAX (`picker.js` swaps the dialog body) and the persistent parameter `picker` stays in links because the grid links to `this`.
setRowDecorator()  : self
Decorator called once after the current page is loaded (see {@see $rowDecorator}).
setSettingContext()  : $this
setThemeContext()  : $this
setTreeChildrenLimit()  : self
Cap of children of one parent (default {@see TREE_CHILDREN_LIMIT}). Above it the first N children and a row "… N more — use search" are rendered; in "Reorder" a node cannot be dropped at the end of the truncated list (the server would reject the position as TREE_STALE).
setTreeCollapsible()  : self
Collapsible tree (default `true`): ▸/▾ at the indented column, focus on a subtree, "Expand/Collapse all", expansion state in the session. Data is loaded per parent.
setTreeDefaultView()  : self
Default view of a tree grid ({@see self::VIEW_LIST} / {@see self::VIEW_TREE}) until the user switches; the choice is then kept in the session.
setTreeMoveFactories()  : self
Component factories of the modal, injected by {@see \App\UI\Admin\System\Components\DataGridComponent\DataGridFactory}.
setTreeScope()  : self
Tree scope filter for several trees in one table (e.g. menuItem.menuId). It is added to the list filters (only that tree) and to the move SQL queries (the lft/rgt recalculation does not touch other trees). Empty means a single tree (pages).
setTreeStructure()  : self
Records form a tree (page, menuItem, category…): the list is ordered depth-first by the order property, indented by level, and rows get arrows to move among siblings.
setup()  : void
setupAppContext()  : void
sortIdsByLabel()  : array<int, int>
Returns ids sorted by label using `Collator` (`strnatcasecmp` without intl). Equal labels keep their original order (stable sort), so sorting again changes nothing.
typedComponent()  : T
Returns a subcomponent with a verified type.
createComponentGridForm()  : Form
createComponentMoveForm()  : Form
createComponentMoveParentPicker()  : Picker
Parent in the modal: a suggest field with the path plus a modal with the same grid in picker mode (without the node and its subtree).
createComponentMovePosition()  : TreePosition
frontPresenter()  : BasePresenter|null
Returns the front presenter the component is attached to (null outside the front end or when detached).
getLangId()  : int|null
getTranslator()  : ITranslator
setTemplateFile()  : void
setTranslator()  : self
addFilterControls()  : void
addMoveNotice()  : void
buildMoveTargetParams()  : array<string, mixed>
Builds the redirect parameters after success so that the moved node is highlighted and visible.
buildNestedLevel()  : array<int, array{item: object, children: array, more: int, meta: array}>
buildParentFilter()  : Filter
Builds `parentId IS NULL` (roots) or `= focused node`, plus children of expanded nodes.
buildStateFilters()  : array<string|int, Filter>
Converts search field values into Core filters via the column filter definitions.
buildSubtreeFilters()  : array<string|int, Filter>
Returns filters of the focused node subtree (descendants have `lft` inside its bounds); empty without focus.
buildTreeConfig()  : TreeConfig
`TreeConfig` for the model layer (moves), from the tree configuration and scope.
buildTreeCrumbs()  : array<int, array{id: int|null, label: string}>
Returns the breadcrumbs of the focused node: ancestors from the bounds (`lft < x and rgt > x`, one query).
callDeleteMethod()  : Result
Calls the delete method of the manager configured via {@see setDeleteMethod()} (default `'delete'`); the only place that knows its name, shared by the `delete!` signal ({@see HandleTrait::handleDelete()}) and the group action 'delete' ({@see FormTrait::processGroupAction()}).
confirmDelete()  : bool
Server-side half of the delete confirmation: a delete runs only with the confirmation flag ({@see DataGrid::CONFIRM_FIELD}) in the POST.
countTreeNodes()  : int
Returns the number of tree nodes within the scope (one count query, cached per request).
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).
decorateItems()  : void
Calls {@see DataGrid::setRowDecorator()} on the current page when it is set.
deleteFlashType()  : string
Returns the flash color for {@see deleteResultKey()}; an explained success with a caveat carries the level of its code.
deleteResultKey()  : string
Returns the flash key for a delete result.
deleteTreeNodes()  : Result
Deletes nodes of a tree grid in bulk; each node is deleted with its subtree ({@see \App\Core\Traits\Api\Models\Services\TreeTrait::deleteTreeNode()}).
derivedAddPrivilege()  : string|null
`:Admin:<Module>:<Presenter>:<action>` from the attached presenter; `null` when it cannot be derived.
filterControlNames()  : array<string, string>
findMoveChildren()  : array<int, array{id: int, label: string}>
findMoveNode()  : object|null
findTreeParentIds()  : array<int, int>|null
Returns ids of nodes with children within the filters, or null when more than {@see DataGrid::TREE_FULL_LIMIT} nodes are in range (expanding all would render too much).
finishTreeSignal()  : void
Finishes a tree signal: AJAX outside picker redraws the body (plus flash); otherwise it redirects, which `picker.js` follows.
flashTranslated()  : void
Flashes a message by key; the admin layout translates `{_'//' . $flash->message}`, so the full path including the component domain is needed.
flattenPost()  : array<int, array{0: string, 1: string}>
Flattens POST data into `name => value` pairs for hidden fields (`ids[]` and nested arrays keep their bracket names); the confirmation flag itself is left out.
getNodeBounds()  : array{int, int}
getPageCount()  : int
getPaginationSteps()  : array<string|int, int>
Paging steps: the neighborhood of the current page plus evenly spread pages (like {@see \App\UI\Front\System\Components\PaginatorComponent\Paginator}).
getTreeSessionKey()  : string
State key: presenter, component and scope (each menu has its own).
getTreeSessionSection()  : SessionSection
hasFilterRow()  : bool
initializeData()  : void
isAddAllowed()  : bool
Returns whether the logged-in user may see the "add" button.
isExplainedDeleteOutcome()  : bool
isTreeView()  : bool
Tells whether the tree list applies: only in the chosen tree view ({@see TreeStateTrait::isTreeViewChosen()}) and until the user searches or sorts by a column, which breaks the hierarchy and switches the grid to the flat list. The default view is the flat paged list.
loadExpandedIds()  : array<int, int>|null
loadFlatData()  : void
loadTreeData()  : void
Loads the tree list by parents: one query `parentId IN (root or focused node + expanded)` ordered by `lft`, without paging.
loadTreePaths()  : void
Loads the ancestors of the flat list page rows in one query within the scope: `lft < max(lft) and rgt > min(rgt) and (lft < l1 and rgt > r1 or ...)`, one pair of bounds per parent ({@see TreePathBuilder::pickQueryBounds()}).
moveDialogErrorKey()  : string
moveNode()  : void
Moves a node up or down by delegating to the manager model layer ({@see \App\Core\Traits\Shared\Models\Managers\TreeTrait}). The tree configuration (lft/rgt/parent properties and scope) comes from {@see \App\UI\Admin\System\Components\DataGridComponent\DataGrid::buildTreeConfig()}.
moveResultKey()  : string
Returns the flash key of a move result. A rejected contract (`TREE_STALE`) and a lock (`TREE_LOCKED`) are not plain failures: the user should know to reload or wait a moment.
prepareTreePathTemplate()  : void
"Path" column and "In tree" action in the flat tree list: the path goes after the indented column (node name), without one after the last column. Row highlighting applies only in the tree.
prepareTreeTemplate()  : void
Tree variables for the template: row metadata, toggles, focus and breadcrumbs, URLs for JS.
processGroupAction()  : void
Handles a group action submit: passes the checkbox ids to the action callback; `delete` without a callback deletes through the manager.
processMoveForm()  : void
processSearch()  : void
Handles the search submit: stores field values in the persistent state and redirects.
reloadMoveNodeFromForm()  : void
requireDataSource()  : Manager<BaseEntity, ServiceInterface<string|int, BaseEntity>>
Returns the grid manager; signals and actions run after the presenter configured the grid, so a missing data source is a programmer error.
requireDeletePrivilege()  : void
IMPORTANT: server-side gate for bulk delete, key `…:del`.
requireEditPrivilege()  : void
IMPORTANT: server-side gate for writes in the grid: inline editing, relation toggles and tree moves.
requireGroupActionPrivilege()  : void
Gate for any group action; the action declares its own privilege ({@see GroupAction::setPrivilege()}), `delete` has it built in.
requireOfferedDeletion()  : void
IMPORTANT: server-side delete gate; responds 403 when the grid does not offer deletion in this request.
requireTreeMoveAllowed()  : void
resolveCollatorLocale()  : string
Returns the collation locale by the admin language (`cs` to `cs_CZ`), Czech by default.
resolveExpandedIds()  : array<int, int>
Returns the expanded nodes: the session, otherwise the default state (a small tree means all nodes with children).
resolveMoveNode()  : object|null
Returns the node being moved: from the form value (submit) or from the signal parameter (open).
resolveMoveParentLabel()  : string|null
resolveOrderBys()  : array<string, bool>
Returns the ordering for `findAll()`; user ordering takes precedence over the default.
resolveRowLabel()  : string
Shared core of {@see getPickerLabel()} and {@see getRowLabel()}: the first meaningful text of the row.
resolveTreeLabelProperty()  : string|null
Returns the property of the indented column (node name), which the parent suggest searches by.
resolveTreeParentId()  : int|null
resolveTreeRootNode()  : object|null
Returns the focused node (`treeRoot`) as an entity, or null for the whole tree.
rowDeleteConfirmText()  : string|null
Confirmation text of the row delete action (the same the modal shows).
showMoveModal()  : void
Fills and opens the shared modal with the current form state (idempotent).
slugifyColumnName()  : string
stateToString()  : string
Converts a persistent state value (mixed, from the URL) to a string for form defaults.
storeExpandedIds()  : void
stringify()  : string
suggestMoveParents()  : array<int, array{id: int, label: string}>
Suggests parents: LIKE over the name column property, without the node and its subtree, with the path in the label so that equal names can be told apart.
t()  : string
Translates a key in the component domain.
updateResultKey()  : string
Returns the flash key for an inline update result; an explained refusal carries the message of its code (absolute key into the `results` domain).

Constants

CONFIRM_FIELD

POST flag of a confirmed delete; the confirmation modal (`datagrid.js`) adds it, the server deletes nothing without it ({@see HandleTrait::requireDeleteConfirmation()}).

public string CONFIRM_FIELD = '_confirmed'

PER_PAGE_OPTIONS

Page-size choices (header links; "Default" is null).

public mixed PER_PAGE_OPTIONS = [25, 50, 100]

TREE_CHILDREN_LIMIT

Default cap of children of one parent in a tree; see {@see setTreeChildrenLimit()}.

public mixed TREE_CHILDREN_LIMIT = 500

TREE_FULL_LIMIT

A tree up to this many nodes (within the scope) opens fully expanded on first view, "Expand all" is refused above it, and a non-collapsible tree ({@see setTreeCollapsible()}) behaves as collapsible above it as a safeguard.

public mixed TREE_FULL_LIMIT = 500

TREE_SESSION_MAX_IDS

At most this many expanded node ids are kept in the session (guard against bloat).

public mixed TREE_SESSION_MAX_IDS = 5000

VIEW_LIST

public mixed VIEW_LIST = 'list'

VIEW_TREE

public mixed VIEW_TREE = 'tree'

CSV_BATCH_SIZE

Batch size for reading `findAll()` incrementally.

private int CSV_BATCH_SIZE = 500

CSV_DELIMITER

Field delimiter: a semicolon (Czech Excel convention), not a comma.

private string CSV_DELIMITER = ';'

Properties

$dir

Sort direction `asc`|`desc`.

public string|null $dir = null
Attributes
#[Persistent]

$filters

Values of the search fields keyed by column name. Range stores `['from' => …, 'to' => …]`, multiselect an array of values.

public array<string, mixed> $filters = []
Attributes
#[Persistent]

$orderBy

Column name the list is sorted by (click on the heading).

public string|null $orderBy = null
Attributes
#[Persistent]

$page

public int $page = 1
Attributes
#[Persistent]

$perPage

User override of rows per page; null means the default (`setItemsPerPage()`).

public int|null $perPage = null
Attributes
#[Persistent]

$reorder

"Reorder" mode: switches a tree grid from the flat table (arrows) to the nested drag & drop view ({@see isDragView()}). The user turns it on with a toolbar button; it applies only in the tree view.

public bool $reorder = false
Attributes
#[Persistent]

$treeRoot

Tree focus: the grid shows only the subtree of the node with this id (children are the first level) and a breadcrumb above it. Persistent so the URL can be shared; the expansion state is kept in the session instead ({@see TreeStateTrait}). null means the whole tree.

public int|null $treeRoot = null
Attributes
#[Persistent]

$view

Tree grid view: `list` is the flat paged list with a "Path" column (default), `tree` the hierarchy with ▸/▾ and focus. The choice is remembered in the session per grid ({@see TreeStateTrait::isTreeViewChosen()}); null means session / default.

public string|null $view = null

"Reorder" and the picker modal always load the tree.

Attributes
#[Persistent]

$componentParameters

protected array<string, mixed> $componentParameters = []

component parameters set by setComponentParameter()

$translatorDomain

protected string|null $translatorDomain = 'admin.system.components.dataGrid'

$addDestination

private string|null $addDestination = null

$addParams

private array<string, mixed> $addParams = []

$addPrivilege

Privilege key of the "add" button; `null` derives it, `''` never hides. See {@see setAddLink()}.

private string|null $addPrivilege = null

$csvExportEnabled

Whether the CSV export button is shown in the grid toolbar; off by default. Enabled by {@see enableCsvExport()}, served by {@see CsvExportTrait::handleCsvExport()}.

private bool $csvExportEnabled = false

$csvExportFileName

private string|null $csvExportFileName = null

$defaultFilters

private array<string|int, Filter> $defaultFilters = []

filters always applied (grid scope, e.g. menuId)

$defaultOrder

private array<string, bool> $defaultOrder = ['id' => false]

property path => true (asc) / false (desc)

$defaultOrderCustomized

Whether the presenter already overrode the default order; see {@see self::setDefaultOrder()}.

private bool $defaultOrderCustomized = false

$deleteMethod

Name of the manager method called by the `delete!` signal ({@see HandleTrait::handleDelete()}) and the group action 'delete' ({@see FormTrait::processGroupAction()}). Defaults to `'delete'` (hard delete).

private string $deleteMethod = 'delete'

Shop grids (Product/ProductSet) switch to 'softDelete': the manager sets deleted=1 instead of DELETE, so the data stays for old orders. The method must have the same signature as Manager::delete() (int|array $id): Result).

$dragDrop

Drag & drop move of tree nodes; enabled via {@see enableDragDrop()}.

private bool $dragDrop = false

$dragFlat

Flat drag mode: SortableJS runs only over the root list of siblings and nested lists (drop targets for changing the parent) are not initialized. For grids that may only reorder, not change the parent (e.g. main parameters).

private bool $dragFlat = false

$explainedDeleteFailures

Delete result codes whose message from the `results` domain is shown to the admin instead of the generic failure message, see {@see explainDeleteFailures()}.

private array<int, true> $explainedDeleteFailures = []

ResultCode->value => true

$explainedUpdateFailures

Inline update (toggle, select) result codes whose message from the `results` domain is shown instead of the generic failure, see {@see explainUpdateFailures()}.

private array<int, true> $explainedUpdateFailures = []

ResultCode->value => true

$filterControlNames

Column => name of its filter control; computed lazily once.

private array<string, string>|null $filterControlNames = null

$highlightId

Highlighted row, the target of the "Show in tree" action. The `highlight` parameter is one-shot (not persistent): only the action link carries it, other grid links do not, and the JS removes it from the URL after scrolling the row into view, so a reload does not highlight.

private int|null $highlightId = null

$includes

private array<string|int, string> $includes = []

include paths for findAll (e.g. ['translations'])

$itemIdentifier

private string $itemIdentifier = 'id'

$itemsById

private array<int, object> $itemsById = []

id => entity of the loaded tree

$itemsPerPage

private int $itemsPerPage = 20

$moveNode

Node being moved in this request (signal or modal submit).

private object|null $moveNode = null

$moveNotices

Messages inside the modal; per request, not a session flash, which would resurface on the next open.

private array<int, array{key: string, type: string}> $moveNotices = []

$pendingConfirmation

Delete waiting for confirmation (no flag in the POST): message of the action, record ids, the URL and the POST fields to repeat. `render()` then draws the confirmation page.

private array{message: ?string, actionLabel: ?string, ids: list, action: string, fields: list}|null $pendingConfirmation = null

$pickerData

private array<string, string> $pickerData = []

data key => property path (fills further fields of the opener)

$pickerExcludeId

Id of the record that cannot be picked (self-reference); its row gets no "Select".

private int|null $pickerExcludeId = null

$pickerExcludeSubtreeLft

lft/rgt of the whole subtree that cannot be picked (moving a node under its descendant).

private int|null $pickerExcludeSubtreeLft = null

$pickerExcludeSubtreeRgt

private int|null $pickerExcludeSubtreeRgt = null

$pickerLabelCallback

private callable(object): string|null $pickerLabelCallback = null

label computed from the entity (takes precedence over the property)

$pickerLabelProperty

private string|null $pickerLabelProperty = null

$pickerMode

Picker mode: the grid serves as a record picker for a foreign form.

private bool $pickerMode = false

$pickerName

private string $pickerName = ''

$rowDecorator

Optional decorator of the loaded page of records. It is called once with the whole page (not per row), so it can run one batch query and write the values into `#[Transient]` entity properties via setters. For columns that cannot be computed from one entity (an aggregate over a foreign table, e.g. stock summed over warehouses) without the grid knowing JOIN/GROUP BY.

private callable(array<int, object> $items): void|null $rowDecorator = null

$treeChildrenLimit

private int $treeChildrenLimit = self::TREE_CHILDREN_LIMIT

$treeCollapsible

Collapsible tree (▸/▾, focus, session); `false` means always fully expanded (menu).

private bool $treeCollapsible = true

$treeDefaultView

Default view of a tree grid until the user switches it.

private string $treeDefaultView = self::VIEW_LIST

$treeLimitLogged

The non-collapsible tree safeguard has already logged (render and signal in one request).

private bool $treeLimitLogged = false

$treeMeta

Metadata of the visible tree nodes ({@see TreeRowsBuilder}).

private array<int, array{level: int, parentId: int, hasChildren: bool, expanded: bool, up: bool, down: bool}> $treeMeta = []

$treeMoreAfter

private array<int, array<int, array{parentId: int, count: int, level: int}>> $treeMoreAfter = []

row id => "N more" rows after its subtree

$treeNested

private array<int, array{id: int, children: array, more: int}> $treeNested = []

nesting for the sort view

$treeOrderProperty

private string $treeOrderProperty = 'lft'

$treeParentProperty

private string $treeParentProperty = 'parentId'

$treePaths

Paths of the rows of the current flat list page ({@see loadTreePaths()}).

private array<int, array{full: string, short: string, segments: list}> $treePaths = []

$treeRightProperty

private string|null $treeRightProperty = 'rgt'

$treeRootMissing

The focused node from the URL does not exist (deleted or foreign scope); the template shows a notice.

private bool $treeRootMissing = false

$treeRootMore

How many children of the view root did not fit under the cap.

private int $treeRootMore = 0

$treeScope

private array<string, scalar|null> $treeScope = []

tree scope filter (property => value); separates trees in one table

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>

addDefaultFilter()

Core filter applied on every load (grid scope).

public addDefaultFilter(Filter $filter) : self
Parameters
$filter : Filter
Return values
self

buildCellHref()

Returns the href the cell content is wrapped in when the column has a link ({@see BaseColumn::setLink()}). Parameters are mapped from row properties. In picker mode links are suppressed because a selection must not leave the modal. When a required parameter ({@see BaseColumn::getLinkRequiredParams()}) is missing (null / ''), no link is generated, a guard against broken links and a crash on a missing id.

public buildCellHref(BaseColumn $column, object $entity) : string|null
Parameters
$column : BaseColumn
$entity : object
Return values
string|null

buildRowActionHref()

Row action URL (a presenter link, or a grid signal with the record id).

public buildRowActionHref(RowAction $action, object $entity) : string
Parameters
$action : RowAction
$entity : object
Return values
string

buildShowInTreeHref()

Builds the "Show in tree" link: cancels search, ordering and page, focuses the parent of the row (a root means no focus; a non-collapsible tree has no focus) and highlights the row once.

public buildShowInTreeHref(object $entity) : string

In the picker modal it is a plain link that picker.js handles by swapping the modal, like breadcrumbs.

Parameters
$entity : object
Return values
string

canMoveNodes()

Tells whether "Move to..." is offered; same gate as drag and drop (a flat drag must not change the parent).

public canMoveNodes() : bool
Return values
bool

canReorder()

Returns whether the "Reorder" view can be switched on. Drag & drop over a tree outside picker mode is enough; the button is available also with user sorting or a filter (flat table).

public canReorder() : bool

Clicking it resets sorting and filter and switches to the clean tree drag view (render() reorderOnHref).

Return values
bool

canSortChildren()

Tells whether "sort children alphabetically" is offered.

public canSortChildren() : bool
Return values
bool

createComponent()

public createComponent(string $name) : IComponent|null
Parameters
$name : string
Return values
IComponent|null

enableCsvExport()

Enables the "Export CSV" button in the grid toolbar; opt-in, without the call the grid is unchanged and no export code runs. The export reads the current filter and sort state and all rows (no paging, in batches; see {@see CsvExportTrait}); columns are the visible grid columns (not actions).

public enableCsvExport(string $fileName) : self
Parameters
$fileName : string

name of the downloaded file (e.g. 'jobs-2026-08-24.csv')

Return values
self

enableDragDrop()

Enables drag & drop move of nodes in a tree grid. Works only when {@see setTreeStructure()} is set and the manager implements {@see \App\Core\Traits\Api\Models\Managers\TreeTrait::moveSubtreeTo()}.

public enableDragDrop([bool $flat = false ]) : self

The JS logic is in components/tree-drag.js.

Parameters
$flat : bool = false

true is flat mode (reordering siblings only, no parent change): SortableJS runs only over the root list and nested drop targets stay inactive. For single-level lists (e.g. main parameters) where the parent must not change.

Return values
self

explainDeleteFailures()

Opts in to showing domain reasons for a rejected delete to the admin (e.g. a job cannot be deleted because it contains invoiced work sheets).

public explainDeleteFailures(ResultCode ...$codes) : self

Each code needs a translation results.<camelCase> in cs/en/sk. Without the call the grid shows the generic message. Generic codes (database or API error) do not belong here, their text tells the admin nothing. It also applies to a success with a caveat (e.g. PRODUCT_DELETE_HIDDEN, where records were only hidden): the message of the code is shown in the color of its ResultCode::level() instead of the plain success message.

Parameters
$codes : ResultCode
Return values
self

explainUpdateFailures()

Opts in to showing the domain reason of a refused inline update (e.g. the only default PDF layout cannot be turned off). Same rules as {@see explainDeleteFailures()}: each code needs a `results.<camelCase>` translation in cs/en/sk, generic codes do not belong here.

public explainUpdateFailures(ResultCode ...$codes) : self
Parameters
$codes : ResultCode
Return values
self

getAttachedPresenter()

Presenter of the grid; the component is always attached during render and signals.

public getAttachedPresenter() : Presenter
Return values
Presenter

getBodySnippetNames()

Returns the whole body snippet and the area with `row-<id>` rows for the current view.

public getBodySnippetNames() : array{string, string}

The table and the sort view have separate names in DataGrid.latte (Latte does not allow the same name in two branches). IMPORTANT: invalidate only what is drawn; otherwise SnippetRuntime would also render a block from the branch that is not rendered.

Return values
array{string, string} —

[body snippet, rows area]

getComponentParameter()

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
Container

getFilterControlName()

Returns the form control name of the filter of the given column.

public getFilterControlName(string $column) : string

Nette allows only [a-zA-Z0-9_] in a component name while a column can be a dotted relation path (status.id), so other characters are replaced by an underscore. A collision after the conversion (status.id vs status_id) is resolved by a numeric suffix, which keeps the name unique within the grid.

Parameters
$column : string
Return values
string

getHighlightId()

public getHighlightId() : int|null
Return values
int|null

getItemId()

Record primary key.

public getItemId(object $entity) : int
Parameters
$entity : object
Return values
int

getItemParentId()

Parent id of a tree node (0 is the real root).

public getItemParentId(object $entity) : int
Parameters
$entity : object
Return values
int

getItemsPerPage()

Effective rows per page (user override, otherwise the default).

public getItemsPerPage() : int
Return values
int

getMoveNotices()

Returns the messages for the modal; the template translates them by the full grid domain key.

public getMoveNotices() : array<int, array{key: string, type: string}>
Return values
array<int, array{key: string, type: string}>

getNestedItems()

Returns the list items as a nested tree for the drag & drop template; SortableJS Nested Sortables needs genuine `<ul>/<li>` nesting, not a flat table. Built from the same data as the table ({@see \App\UI\Admin\System\Components\DataGridComponent\Utils\TreeRowsBuilder}); `more` is the number of children above the cap, `meta` the expansion / has-children state.

public getNestedItems() : array<int, array{item: object, children: array, more: int, meta: array}>
Return values
array<int, array{item: object, children: array, more: int, meta: array}>

getPickerData()

Row data for picking in picker mode; JSON `{key: value}` for `data-pick-data`.

public getPickerData(object $entity) : string
Parameters
$entity : object
Return values
string

getPickerLabel()

Row label for picking in picker mode; returned to the opener (hidden + text).

public getPickerLabel(object $entity) : string
Parameters
$entity : object
Return values
string

getRowLabel()

Returns the accessible name of a row for the bulk-action checkbox: same source as {@see getPickerLabel()} (first non-id column / picker label property or callback) but with a different fallback: an empty label becomes "#<id>", never a bare anonymous `ids[]`.

public getRowLabel(object $entity) : string
Parameters
$entity : object
Return values
string

getSettings()

public getSettings() : array<int, array<string, mixed>>
Return values
array<int, array<string, mixed>>

getTreeLabel()

Returns the node label for breadcrumbs: the value of the indented column, otherwise the picker label.

public getTreeLabel(object $entity) : string
Parameters
$entity : object
Return values
string

getTreePath()

public getTreePath(object $entity) : array{full: string, short: string, segments: list}|null
Parameters
$entity : object
Return values
array{full: string, short: string, segments: list}|null —

row path; null for a root (no ancestors)

groupActionPrivilege()

Returns the privilege that governs the given group action, or null when it has none.

public groupActionPrivilege(GroupAction $action) : string|null

delete has del built in (deleting is deleting, whoever registers it); other actions declare theirs via GroupAction::setPrivilege(). An action without a privilege is guarded only by registration and CSRF.

Parameters
$action : GroupAction
Return values
string|null

handleCollapse()

public handleCollapse(int $id) : void
Parameters
$id : int

handleCollapseAll()

Collapses everything, also outside the focus (nothing visible there is lost by collapsing).

public handleCollapseAll() : void

handleDelete()

public handleDelete(int $id) : void
Parameters
$id : int
Attributes
#[Requires]
$methods: 'POST'

handleDragDrop()

Moves a node in the tree by drag and drop, changing the parent and the position among siblings.

public handleDragDrop(int $dragId, int|null $newParentId, int $afterId[, int|null $oldParentId = null ][, int|null $prevId = null ][, int|null $nextId = null ]) : void

afterId: -1 inserts as the first child of newParent, 0 as the last child, >0 after the sibling with that id.

Neighbor contract: when the client sends prevId/nextId (and oldParentId, 0 for a root), the server verifies under the tree lock that the node is still under oldParentId and that prevId/nextId are the current neighbors under newParentId. The position is then derived from prevId and afterId is ignored: prevId -1 means the start, 0 the end without neighbor verification (collapsed target), >0 after that node; nextId 0 means nothing after it, >0 before that node. Without them afterId applies.

The AJAX response is {success: true} or {success: false, code: '<ResultCode name>'} (TREE_STALE when the tree changed meanwhile, TREE_LOCKED on a concurrent operation); the JS shows a message by the code and reloads the list. Non-AJAX uses a redirect with a flash.

Calls TreeTrait::moveSubtreeTo().

Parameters
$dragId : int
$newParentId : int|null
$afterId : int
$oldParentId : int|null = null
$prevId : int|null = null
$nextId : int|null = null
Attributes
#[Requires]
$methods: 'POST'

handleExpand()

public handleExpand(int $id) : void
Parameters
$id : int

handleExpandAll()

Expands the whole current (focused) subtree, only up to {@see DataGrid::TREE_FULL_LIMIT} nodes in total; above it a "focus a smaller branch" message is shown and the state stays unchanged.

public handleExpandAll() : void

handleInlineUpdate()

public handleInlineUpdate(int $id, string $column, string $value) : void
Parameters
$id : int
$column : string
$value : string
Attributes
#[Requires]
$methods: 'POST'

handleMoveDown()

public handleMoveDown(int $id) : void
Parameters
$id : int
Attributes
#[Requires]
$methods: 'POST'

handleMoveModal()

Opens the "Move to..." modal for a node (AJAX; without JS it just returns to the list).

public handleMoveModal(int $id) : void
Parameters
$id : int

handleMoveUp()

public handleMoveUp(int $id) : void
Parameters
$id : int
Attributes
#[Requires]
$methods: 'POST'

handleRelationToggle()

Toggles a join table link, a {@see RelationColumn} cell (a flag from a related collection picked by `scope`, e.g. a role in the RBAC matrix).

public handleRelationToggle(int $id, string $scope, string $column, string $value) : void

The value cannot be stored via updateColumns() (it would write a row column, not the join row with a composite key), so it delegates to a data source implementing RelationTogglable.

Parameters
$id : int
$scope : string
$column : string
$value : string
Attributes
#[Requires]
$methods: 'POST'

handleSortChildren()

Sorts the direct children of a parent by label (current language collation) in one operation under the tree lock. `parentId` 0 is the root level of the view (the real roots without focus).

public handleSortChildren([int $parentId = 0 ]) : void
Parameters
$parentId : int = 0
Attributes
#[Requires]
$methods: 'POST'

handleTreeRefresh()

Only redraws the tree body; the JS calls it after a rejected move (`TREE_STALE`) or a parent change.

public handleTreeRefresh() : void

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
phpstan-assert-if-true

class-string $className

Return values
bool

isActionAllowed()

Returns whether the user has the privilege for the given action (`del`, `export`…) in this list.

public isActionAllowed(string $action) : bool

The key is built from the presenter, :Admin:<Module>:<Presenter>:<action>, the same convention as everywhere in the admin.

IMPORTANT: uses lookup(..., false), not getPresenter(): an unattached component would get InvalidStateException instead of an answer. Without a presenter the key cannot be derived and the answer is true, same as outside the admin branch; the gate check stays fail-closed.

Parameters
$action : string
Return values
bool

isCsvExportEnabled()

public isCsvExportEnabled() : bool
Return values
bool

isDeleteAllowed()

Returns whether the user may delete in this list; one answer for the whole grid.

public isDeleteAllowed() : bool

Used in three places so they cannot contradict each other:

  • the row action delete is not rendered without the privilege,
  • the group action delete is not offered without it,
  • HandleTrait::requireOfferedDeletion() returns 403 without it, which covers deleting a single row too, not only bulk.

Replaces a manual condition on the key :Admin:<Module>:<Presenter>:del around action registration, which most presenters lacked and so offered deleting to anyone.

IMPORTANT: it cannot be decided at registration (addRowAction()): the grid is not yet attached to the presenter (Nette attaches it after createComponent*() returns) and getPresenter() would throw. It is asked at render time and in the gate.

IMPORTANT: fail-open outside the admin branch: the derived key would not exist there and would lock deleting for everyone. The gate is the real protection; this is only one of its three checks.

Return values
bool

isDragDropEnabled()

public isDragDropEnabled() : bool
Return values
bool

isDragFlat()

Flat drag mode (reordering only, no parent change); see {@see enableDragDrop()}.

public isDragFlat() : bool
Return values
bool

isDragView()

Returns whether the tree drag & drop view is active: a nested `<ul>/<li>` list with SortableJS Nested Sortables. It requires a tree ({@see canReorder()}) and the user having switched on "Reorder" (persistent `reorder`).

public isDragView() : bool
Return values
bool

isPickerMode()

public isPickerMode() : bool
Return values
bool

isPickerSelectable()

Whether the row can be picked in picker mode (false when excluded, e.g. self-reference or descendant).

public isPickerSelectable(object $entity) : bool
Parameters
$entity : object
Return values
bool

isTreeCollapsible()

Tells whether the tree can be collapsed.

public isTreeCollapsible() : bool

A non-collapsible grid (menu) behaves as collapsible once it outgrows the limit, otherwise it would silently render thousands of rows. Without a right bound (rgt) "has children" cannot be told without loading the children, so the whole tree is always shown.

Return values
bool

isTreePathVisible()

Tells whether the flat list shows the "Path" column and the "Show in tree" action: only a tree grid with a right bound (ancestors are found from `lft/rgt`) outside the tree view, where indentation and breadcrumbs carry the path.

public isTreePathVisible() : bool
Return values
bool

isTreeViewChosen()

Tells whether the tree view is chosen: the `view` URL parameter (stored in the session), otherwise the session, otherwise the grid default. The picker modal (parent selection) and a tree without a right bound ("has children" cannot be told, so always whole) always use the tree.

public isTreeViewChosen() : bool
Return values
bool

loadState()

Validates the persistent parameters from the URL.

public loadState(array<string, mixed> $params) : void
Parameters
$params : array<string, mixed>

prepareCell()

Prepares a cell: the column value plus renderer variables for the template `Templates/Default/Cells/<template>.latte`. `link` is the href the template wraps the cell content in ({@see BaseColumn::setLink()}), or null.

public prepareCell(BaseColumn $column, object $entity) : array{template: string, vars: array, link: ?string, linkTarget: ?string}
Parameters
$column : BaseColumn
$entity : object
Return values
array{template: string, vars: array, link: ?string, linkTarget: ?string}

"Add" button above the table; not shown unless set.

public setAddLink(string $destination[, array<string, mixed> $params = [] ][, string|null $privilege = null ]) : self

IMPORTANT: the button is hidden also for users without the privilege to create. The key is derived from the presenter and the target action (:Admin:<Module>:<Presenter>:add) the same way as PrivilegeCheckTrait::checkCurrentPrivilege(), so grids need no manual conditions. It is derived only for a relative action ('add'); an absolute destination (':Admin:Other:Module:add') points to a foreign screen where the derived key would not fit and would hide the button wrongly, so nothing is hidden there.

Parameters
$destination : string
$params : array<string, mixed> = []
$privilege : string|null = null

custom key instead of the derived one; '' turns the derivation off (for grids that create something other than the presenter name says)

Return values
self

setComponentParameter()

Sets a component parameter.

public setComponentParameter(string $name, mixed $value) : void
Parameters
$name : string
$value : mixed

setDefaultOrder()

Default list order. The first call drops the built-in `id DESC`, further calls add another level (`setDefaultOrder('type')->setDefaultOrder('name')`).

public setDefaultOrder(string $property[, string $direction = 'asc' ]) : self

IMPORTANT: without dropping it id DESC would stay first and sorting by any other column would have no visible effect; the setting would silently do nothing.

Parameters
$property : string
$direction : string = 'asc'
Return values
self

setDeleteMethod()

Switches the delete signal and group action to another manager method; see {@see $deleteMethod}.

public setDeleteMethod(string $method) : self

Opt-in: without the call 'delete' (hard delete) stays and no other grid changes. Shop grids call setDeleteMethod('softDelete').

Parameters
$method : string
Return values
self

setIncludes()

public setIncludes(array<string|int, string> $includes) : self
Parameters
$includes : array<string|int, string>

relations for findAll (['translations', 'user.role'])

Return values
self

setItemIdentifier()

Property with the record primary key (default `id`).

public setItemIdentifier(string $itemIdentifier) : self
Parameters
$itemIdentifier : string
Return values
self

setItemsPerPage()

Default rows per page; the user can override it with the 25/50/100 links.

public setItemsPerPage(int $itemsPerPage) : self
Parameters
$itemsPerPage : int
Return values
self

setPickerData()

Further data carried by the "Select" button (`data-pick-data` JSON); JS spreads it into the opener's fields by the picker `fieldMap`. Fills several fields at once (not only the label), e.g. a user's e-mail and company.

public setPickerData(array<string, string> $properties) : self
Parameters
$properties : array<string, string>

data key => entity property path

Return values
self

setPickerExcludeId()

Id of the record that cannot be picked in picker mode (self-reference); its row gets no "Select" button. 0 / null means no exclusion.

public setPickerExcludeId(int|null $id) : self
Parameters
$id : int|null
Return values
self

setPickerExcludeSubtree()

lft/rgt range of the subtree that cannot be picked in picker mode. Excludes the root and all descendants (a node cannot be moved under its descendant). The entity must support `getLft()` (duck typing).

public setPickerExcludeSubtree(int|null $lft, int|null $rgt) : self
Parameters
$lft : int|null
$rgt : int|null
Return values
self

setPickerLabelCallback()

Label for "Select" computed from the whole entity; use it when one property is not enough (empty for some records, or several fields must be combined). Takes precedence over {@see setPickerLabelProperty()}.

public setPickerLabelCallback(callable(object): string $callback) : self

IMPORTANT: the label must match labelResolver / the autocomplete of the corresponding PickerConfig, otherwise the user sees a different text in the modal than after the selection in the input. Share one formatting function (like PaymentPickerLabel).

Parameters
$callback : callable(object): string
Return values
self

setPickerLabelProperty()

Property for the "Select" button label (what is returned to the opener); defaults to the first non-id column.

public setPickerLabelProperty(string $property) : self
Parameters
$property : string
Return values
self

setPickerMode()

Picker mode: the grid serves as a record picker for a foreign form (a modal opened by {@see \App\UI\Admin\System\Components\PickerComponent\Picker}). Hides add, row checkboxes, edit/delete actions and group actions, and gives each row a "Select" action ({@see Templates/Default/Parts/_body.latte}). Filtering, sorting and paging stay; inside the modal they run via AJAX (`picker.js` swaps the dialog body) and the persistent parameter `picker` stays in links because the grid links to `this`.

public setPickerMode(string $pickerName) : self

The presenter turns it on in createComponent…Grid() by the persistent parameter picker (BasePresenter::$picker).

Parameters
$pickerName : string

name of the opener's target field (returned on selection)

Return values
self

setRowDecorator()

Decorator called once after the current page is loaded (see {@see $rowDecorator}).

public setRowDecorator(callable(array<int, object> $items): void $decorator) : self
Parameters
$decorator : callable(array<int, object> $items): void
Return values
self

setTreeChildrenLimit()

Cap of children of one parent (default {@see TREE_CHILDREN_LIMIT}). Above it the first N children and a row "… N more — use search" are rendered; in "Reorder" a node cannot be dropped at the end of the truncated list (the server would reject the position as TREE_STALE).

public setTreeChildrenLimit(int $limit) : self
Parameters
$limit : int
Return values
self

setTreeCollapsible()

Collapsible tree (default `true`): ▸/▾ at the indented column, focus on a subtree, "Expand/Collapse all", expansion state in the session. Data is loaded per parent.

public setTreeCollapsible([bool $collapsible = true ]) : self

false means an always fully expanded tree without toggles, focus and session, for small trees dragged across the whole tree (menu). The data path, move contract and lock stay the same. Safeguard: a tree that grows past TREE_FULL_LIMIT nodes behaves as collapsible and logs a warning.

Parameters
$collapsible : bool = true
Return values
self

setTreeDefaultView()

Default view of a tree grid ({@see self::VIEW_LIST} / {@see self::VIEW_TREE}) until the user switches; the choice is then kept in the session.

public setTreeDefaultView(string $view) : self
Parameters
$view : string
Return values
self

setTreeScope()

Tree scope filter for several trees in one table (e.g. menuItem.menuId). It is added to the list filters (only that tree) and to the move SQL queries (the lft/rgt recalculation does not touch other trees). Empty means a single tree (pages).

public setTreeScope(array<string, scalar|null> $scope) : self
Parameters
$scope : array<string, scalar|null>

property => value

Return values
self

setTreeStructure()

Records form a tree (page, menuItem, category…): the list is ordered depth-first by the order property, indented by level, and rows get arrows to move among siblings.

public setTreeStructure([string $parentProperty = 'parentId' ][, string $orderProperty = 'lft' ][, string|null $rightProperty = 'rgt' ]) : self

Moving and deleting are done by the model layer (TreeTrait): a set-based nested-set swap in the database (lft + rgt, whole subtrees) plus Redis invalidation; deleting removes the whole subtree and closes the gap. The grid only calls manager->moveUp/moveDown/deleteNode with buildTreeConfig().

Parameters
$parentProperty : string = 'parentId'

property with the parent id

$orderProperty : string = 'lft'

order property among siblings (lft)

$rightProperty : string|null = 'rgt'

right nested-set bound (rgt), null for none

Return values
self

sortIdsByLabel()

Returns ids sorted by label using `Collator` (`strnatcasecmp` without intl). Equal labels keep their original order (stable sort), so sorting again changes nothing.

public static sortIdsByLabel(array<int, string> $labels[, string $locale = 'cs_CZ' ]) : array<int, int>
Parameters
$labels : array<int, string>

id => label in the current order

$locale : string = 'cs_CZ'
Return values
array<int, int>

typedComponent()

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
template
Return values
T

createComponentGridForm()

protected createComponentGridForm() : Form
Return values
Form

createComponentMoveParentPicker()

Parent in the modal: a suggest field with the path plus a modal with the same grid in picker mode (without the node and its subtree).

protected createComponentMoveParentPicker() : Picker
Return values
Picker

frontPresenter()

Returns the front presenter the component is attached to (null outside the front end or when detached).

protected frontPresenter() : BasePresenter|null
Return values
BasePresenter|null

getLangId()

protected getLangId() : int|null
Return values
int|null

getTranslator()

protected getTranslator() : ITranslator
Return values
ITranslator

setTemplateFile()

protected setTemplateFile(string $dir, string $filename) : void
Parameters
$dir : string
$filename : string

setTranslator()

protected setTranslator(ITranslator $translator) : self
Parameters
$translator : ITranslator
Return values
self

addFilterControls()

private addFilterControls(Form $form, string $name, ColumnFilter $filter) : void
Parameters
$form : Form
$name : string
$filter : ColumnFilter

addMoveNotice()

private addMoveNotice(string $key, string $type) : void
Parameters
$key : string
$type : string

buildMoveTargetParams()

Builds the redirect parameters after success so that the moved node is highlighted and visible.

private buildMoveTargetParams(int $id, int|null $newParentId) : array<string, mixed>

In a tree the path to the new parent is expanded; when it lies outside the focused subtree, the new parent is focused. A flat list (search) stays as it is.

Parameters
$id : int
$newParentId : int|null
Return values
array<string, mixed>

buildNestedLevel()

private buildNestedLevel(array<string|int, mixed> $level) : array<int, array{item: object, children: array, more: int, meta: array}>
Parameters
$level : array<string|int, mixed>

nodes from TreeRowsBuilder (id, children, more), recursive

Return values
array<int, array{item: object, children: array, more: int, meta: array}>

buildParentFilter()

Builds `parentId IS NULL` (roots) or `= focused node`, plus children of expanded nodes.

private buildParentFilter(object|null $rootNode, array<int, int> $expandedIds) : Filter
Parameters
$rootNode : object|null
$expandedIds : array<int, int>
Return values
Filter

buildStateFilters()

Converts search field values into Core filters via the column filter definitions.

private buildStateFilters() : array<string|int, Filter>
Return values
array<string|int, Filter>

buildSubtreeFilters()

Returns filters of the focused node subtree (descendants have `lft` inside its bounds); empty without focus.

private buildSubtreeFilters(object|null $rootNode) : array<string|int, Filter>
Parameters
$rootNode : object|null
Return values
array<string|int, Filter>

buildTreeConfig()

`TreeConfig` for the model layer (moves), from the tree configuration and scope.

private buildTreeConfig() : TreeConfig
Return values
TreeConfig

buildTreeCrumbs()

Returns the breadcrumbs of the focused node: ancestors from the bounds (`lft < x and rgt > x`, one query).

private buildTreeCrumbs(object $rootNode) : array<int, array{id: int|null, label: string}>
Parameters
$rootNode : object
Return values
array<int, array{id: int|null, label: string}> —

from the root down to the parent (the node itself excluded)

callDeleteMethod()

Calls the delete method of the manager configured via {@see setDeleteMethod()} (default `'delete'`); the only place that knows its name, shared by the `delete!` signal ({@see HandleTrait::handleDelete()}) and the group action 'delete' ({@see FormTrait::processGroupAction()}).

private callDeleteMethod(Manager<BaseEntity, ServiceInterface<string|int, BaseEntity>> $manager, int|array<int, int> $id) : Result
Parameters
$manager : Manager<BaseEntity, ServiceInterface<string|int, BaseEntity>>
$id : int|array<int, int>
Return values
Result

confirmDelete()

Server-side half of the delete confirmation: a delete runs only with the confirmation flag ({@see DataGrid::CONFIRM_FIELD}) in the POST.

private confirmDelete(string|null $message, array<int, int> $ids[, string|null $actionLabel = null ]) : bool

The modal (datagrid.js) sets the flag after "Delete". Before the bundle initialized (a large page still loading), without JavaScript, or from a hand-built request, the button submitted the delete with no question at all (admin walkthrough A18). Without the flag nothing is deleted; the grid renders a confirmation page instead ("Do you really want to delete these records?"), which repeats the same request with the flag. An AJAX request gets a warning and a redirect (the modal never sends one unconfirmed).

Parameters
$message : string|null
$ids : array<int, int>
$actionLabel : string|null = null

label of a non-delete bulk action that asks first (null = delete)

Return values
bool —

true = confirmed, run it; false = the confirmation page renders instead

countTreeNodes()

Returns the number of tree nodes within the scope (one count query, cached per request).

private countTreeNodes() : int
Return values
int

createMultiplierComponent()

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|null

createStandardComponent()

Creates a standard component (not a multiplier).

private createStandardComponent(string $name) : IComponent|null
Parameters
$name : string
Return values
IComponent|null

decorateItems()

Calls {@see DataGrid::setRowDecorator()} on the current page when it is set.

private decorateItems() : void

deleteFlashType()

Returns the flash color for {@see deleteResultKey()}; an explained success with a caveat carries the level of its code.

private deleteFlashType(Result $result) : string
Parameters
$result : Result
Return values
string

deleteResultKey()

Returns the flash key for a delete result.

private deleteResultKey(Result $result) : string

A permission denial and a database failure get different messages, so the admin can tell whether to fix permissions or report an error. The bridge preserves the result code.

Parameters
$result : Result
Return values
string

deleteTreeNodes()

Deletes nodes of a tree grid in bulk; each node is deleted with its subtree ({@see \App\Core\Traits\Api\Models\Services\TreeTrait::deleteTreeNode()}).

private deleteTreeNodes(array<string|int, int> $ids) : Result

An id that vanished meanwhile (a descendant of an already deleted node) is skipped.

Parameters
$ids : array<string|int, int>
Return values
Result

derivedAddPrivilege()

`:Admin:<Module>:<Presenter>:<action>` from the attached presenter; `null` when it cannot be derived.

private derivedAddPrivilege() : string|null
Return values
string|null

filterControlNames()

private filterControlNames() : array<string, string>
Return values
array<string, string> —

column => control name

findMoveChildren()

private findMoveChildren(int|null $parentId) : array<int, array{id: int, label: string}>
Parameters
$parentId : int|null
Return values
array<int, array{id: int, label: string}> —

children of the parent in lft order (grid scope)

findMoveNode()

private findMoveNode(int $id) : object|null
Parameters
$id : int
Return values
object|null

findTreeParentIds()

Returns ids of nodes with children within the filters, or null when more than {@see DataGrid::TREE_FULL_LIMIT} nodes are in range (expanding all would render too much).

private findTreeParentIds(array<string|int, Filter> $extraFilters) : array<int, int>|null
Parameters
$extraFilters : array<string|int, Filter>
Return values
array<int, int>|null

finishTreeSignal()

Finishes a tree signal: AJAX outside picker redraws the body (plus flash); otherwise it redirects, which `picker.js` follows.

private finishTreeSignal([bool $withFlash = false ]) : void
Parameters
$withFlash : bool = false

flashTranslated()

Flashes a message by key; the admin layout translates `{_'//' . $flash->message}`, so the full path including the component domain is needed.

private flashTranslated(string $key, string $type) : void
Parameters
$key : string
$type : string

flattenPost()

Flattens POST data into `name => value` pairs for hidden fields (`ids[]` and nested arrays keep their bracket names); the confirmation flag itself is left out.

private static flattenPost(array<string|int, mixed> $data[, string $prefix = '' ]) : array<int, array{0: string, 1: string}>
Parameters
$data : array<string|int, mixed>
$prefix : string = ''
Return values
array<int, array{0: string, 1: string}>

getNodeBounds()

private getNodeBounds(object $node) : array{int, int}
Parameters
$node : object
Return values
array{int, int} —

[lft, rgt]

getPageCount()

private getPageCount() : int
Return values
int

getPaginationSteps()

Paging steps: the neighborhood of the current page plus evenly spread pages (like {@see \App\UI\Front\System\Components\PaginatorComponent\Paginator}).

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

getTreeSessionKey()

State key: presenter, component and scope (each menu has its own).

private getTreeSessionKey() : string
Return values
string

getTreeSessionSection()

private getTreeSessionSection() : SessionSection
Return values
SessionSection

hasFilterRow()

private hasFilterRow() : bool
Return values
bool

isAddAllowed()

Returns whether the logged-in user may see the "add" button.

private isAddAllowed() : bool

Returns true (behavior unchanged) when the key is unknown (absolute destination, derivation turned off, presenter outside the admin branch). Hiding only complements the server gate in actionAdd(); if the derivation missed, it must not hide the button by mistake because the presenter holds the real protection.

Return values
bool

isTreeView()

Tells whether the tree list applies: only in the chosen tree view ({@see TreeStateTrait::isTreeViewChosen()}) and until the user searches or sorts by a column, which breaks the hierarchy and switches the grid to the flat list. The default view is the flat paged list.

private isTreeView() : bool
Return values
bool

loadExpandedIds()

private loadExpandedIds() : array<int, int>|null
Return values
array<int, int>|null —

null when the user has not changed the state yet (the default applies)

loadTreeData()

Loads the tree list by parents: one query `parentId IN (root or focused node + expanded)` ordered by `lft`, without paging.

private loadTreeData(array<string|int, Filter> $coreFilters) : void

The default state (the user has not collapsed anything) and a non-collapsible tree (menu) mean "everything expanded". For a tree up to DataGrid::TREE_FULL_LIMIT nodes that equals a query without the parent filter (limited to the subtree under focus), so the whole tree is loaded at once. TreeRowsBuilder handles visibility, arrows and the children cap over the same data.

Parameters
$coreFilters : array<string|int, Filter>

loadTreePaths()

Loads the ancestors of the flat list page rows in one query within the scope: `lft < max(lft) and rgt > min(rgt) and (lft < l1 and rgt > r1 or ...)`, one pair of bounds per parent ({@see TreePathBuilder::pickQueryBounds()}).

private loadTreePaths(array<int, object> $items) : void

The envelope alone would return almost the whole tree for scattered search results; the OR conditions return exactly the ancestors. Assigning them to rows by intervals happens in PHP.

Parameters
$items : array<int, object>

moveDialogErrorKey()

private moveDialogErrorKey(Result $result) : string
Parameters
$result : Result
Return values
string

moveNode()

Moves a node up or down by delegating to the manager model layer ({@see \App\Core\Traits\Shared\Models\Managers\TreeTrait}). The tree configuration (lft/rgt/parent properties and scope) comes from {@see \App\UI\Admin\System\Components\DataGridComponent\DataGrid::buildTreeConfig()}.

private moveNode(int $id, bool $up) : void
Parameters
$id : int
$up : bool

moveResultKey()

Returns the flash key of a move result. A rejected contract (`TREE_STALE`) and a lock (`TREE_LOCKED`) are not plain failures: the user should know to reload or wait a moment.

private moveResultKey(Result $result) : string

tree-drag.js reads the same texts from grid data attributes (AJAX branch).

Parameters
$result : Result
Return values
string

prepareTreePathTemplate()

"Path" column and "In tree" action in the flat tree list: the path goes after the indented column (node name), without one after the last column. Row highlighting applies only in the tree.

private prepareTreePathTemplate(array<string, BaseColumn> $columns) : void
Parameters
$columns : array<string, BaseColumn>

columns that are actually rendered

prepareTreeTemplate()

Tree variables for the template: row metadata, toggles, focus and breadcrumbs, URLs for JS.

private prepareTreeTemplate(bool $isTreeUi) : void
Parameters
$isTreeUi : bool

processGroupAction()

Handles a group action submit: passes the checkbox ids to the action callback; `delete` without a callback deletes through the manager.

private processGroupAction(GroupAction $action, Form $form) : void
Parameters
$action : GroupAction
$form : Form

processMoveForm()

private processMoveForm(ArrayHash $values) : void
Parameters
$values : ArrayHash

processSearch()

Handles the search submit: stores field values in the persistent state and redirects.

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

reloadMoveNodeFromForm()

private reloadMoveNodeFromForm() : void

requireDeletePrivilege()

IMPORTANT: server-side gate for bulk delete, key `…:del`.

private requireDeletePrivilege() : void

Without it a logged-in user without the delete right could delete in bulk, because the registered action and CSRF protect only against a foreign site. Every screen with bulk delete must have the key :Admin:<Module>:<Presenter>:del allowed for the admin role, otherwise this fail-closed gate would lock even the administrator out.

NOTE: outside the admin branch (a grid in another module, a component without a presenter) it is not enforced, as in requireEditPrivilege(); the derived key would not exist there and would lock the action for everyone.

requireEditPrivilege()

IMPORTANT: server-side gate for writes in the grid: inline editing, relation toggles and tree moves.

private requireEditPrivilege() : void

These signals changed data without asking for any right, so anyone inside the admin could flip any switch in any grid by a hand-built URL. The input validations (column exists, is inline editable, value is in options) check the shape of the input, not permission.

The key is derived from the attached presenter as :Admin:<Module>:<Presenter>:edit, by the same rule as PrivilegeCheckTrait::checkCurrentPrivilege() and the add button in DataGrid::setAddLink(). Inline editing is editing, so edit fits, and no per-grid registration is needed. Every screen with inline, relation or tree writes must have the edit key allowed for admin.

NOTE: when the key cannot be derived (a grid outside an admin presenter) the gate lets the call through. Failing closed would break a foreign context that does not follow the admin naming convention; the real gate remains checkAdminAccess() in startup(), which everyone has to pass.

requireGroupActionPrivilege()

Gate for any group action; the action declares its own privilege ({@see GroupAction::setPrivilege()}), `delete` has it built in.

private requireGroupActionPrivilege(GroupAction $action) : void

NOTE: it mirrors the condition the button is rendered by; whoever sees the action must pass, and vice versa.

Parameters
$action : GroupAction

requireOfferedDeletion()

IMPORTANT: server-side delete gate; responds 403 when the grid does not offer deletion in this request.

private requireOfferedDeletion() : void

Presenters add the delete action conditionally:

if ($this->isAllowed(':Admin:System:UserGroup:del')) {
    $grid->addRowAction(RowAction::create('delete')->setSignal('delete'));
}

A hidden button is no protection: without this gate the delete! signal could be called by a hand-built URL even without the right. The gate has no key of its own; it mirrors the condition the UI already uses (the component is rebuilt in the signal request too), so it cannot lock out anyone who sees the button. The presenter condition is therefore authoritative: to tighten a grid, wrap addRowAction() and addGroupAction() in isAllowed().

NOTE: per-row visibility (RowAction::setVisibleWhen()) is not handled here; it mirrors entity state (e.g. a closed work sheet) and the model guards it in beforeDelete().

requireTreeMoveAllowed()

private requireTreeMoveAllowed() : void

resolveCollatorLocale()

Returns the collation locale by the admin language (`cs` to `cs_CZ`), Czech by default.

private resolveCollatorLocale() : string
Return values
string

resolveExpandedIds()

Returns the expanded nodes: the session, otherwise the default state (a small tree means all nodes with children).

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

resolveMoveNode()

Returns the node being moved: from the form value (submit) or from the signal parameter (open).

private resolveMoveNode() : object|null
Return values
object|null

resolveMoveParentLabel()

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

resolveOrderBys()

Returns the ordering for `findAll()`; user ordering takes precedence over the default.

private resolveOrderBys() : array<string, bool>
Return values
array<string, bool> —

property path => true (asc) / false (desc)

resolveRowLabel()

Shared core of {@see getPickerLabel()} and {@see getRowLabel()}: the first meaningful text of the row.

private resolveRowLabel(object $entity) : string
Parameters
$entity : object
Return values
string

resolveTreeLabelProperty()

Returns the property of the indented column (node name), which the parent suggest searches by.

private resolveTreeLabelProperty() : string|null
Return values
string|null

resolveTreeParentId()

private resolveTreeParentId(object $entity) : int|null
Parameters
$entity : object
Return values
int|null

resolveTreeRootNode()

Returns the focused node (`treeRoot`) as an entity, or null for the whole tree.

private resolveTreeRootNode() : object|null

A missing or foreign node resets the parameter and raises a notice flag. A 404 would break the picker modal (picker.js inserts the response into the dialog) and a shared link to a deleted node; the right reaction is to show the whole tree and say why.

Return values
object|null

rowDeleteConfirmText()

Confirmation text of the row delete action (the same the modal shows).

private rowDeleteConfirmText() : string|null
Return values
string|null

showMoveModal()

Fills and opens the shared modal with the current form state (idempotent).

private showMoveModal() : void

slugifyColumnName()

private slugifyColumnName(string $column) : string
Parameters
$column : string
Return values
string

stateToString()

Converts a persistent state value (mixed, from the URL) to a string for form defaults.

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

storeExpandedIds()

private storeExpandedIds(array<int, int> $ids) : void
Parameters
$ids : array<int, int>

stringify()

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

suggestMoveParents()

Suggests parents: LIKE over the name column property, without the node and its subtree, with the path in the label so that equal names can be told apart.

private suggestMoveParents(string $query, int|null $nodeId, int|null $lft, int|null $rgt) : array<int, array{id: int, label: string}>
Parameters
$query : string
$nodeId : int|null
$lft : int|null
$rgt : int|null
Return values
array<int, array{id: int, label: string}>

t()

Translates a key in the component domain.

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

updateResultKey()

Returns the flash key for an inline update result; an explained refusal carries the message of its code (absolute key into the `results` domain).

private updateResultKey(Result $result) : string
Parameters
$result : Result
Return values
string
On this page

Search results