TreePathBuilder
in package
Builds the "Path" column of the flat list of a tree grid.
Knows neither entities nor the database: the ancestors query is built and run by TreeStateTrait; this class is pure logic, testable without a database:
- pickQueryBounds() picks the rows whose bounds form the query conditions; siblings share ancestors, so one row per parent is enough and roots have no ancestors,
- assign() assigns ancestors to rows by intervals (
a.lft < r.lft and a.rgt > r.rgt), - format() formats the path, shortening a long one in the middle.
IMPORTANT: an envelope lft < max(lft) and rgt > min(rgt) over the whole page is not enough
as the query. Search results are scattered across the tree, so the envelope would cover almost
the whole table. The query therefore ORs one condition per parent (at most the page size) and
adds the envelope only to narrow the index range.
Table of Contents
Constants
- ELLIPSIS : mixed = '…'
- MAX_LENGTH : mixed = 70
- A longer path text (characters) is shortened in the middle even with few segments.
- MAX_SEGMENTS : mixed = 3
- A path with more segments is shortened in the middle.
- SEPARATOR : mixed = ' › '
Methods
- assign() : array<int, array<int, string>>
- Returns the ancestors of each row from the root down to the parent (the row itself excluded).
-
format()
: array{full: string, short: string, segments: list
} - Returns the path text: the full one (for `title`) and the displayed one, where a long path is shortened in the middle and the first and last segments stay.
- pickQueryBounds() : array<int, array{lft: int, rgt: int}>
- Returns the bounds for the ancestors query: one row per parent (siblings share ancestors); roots and rows without valid bounds are left out.
Constants
ELLIPSIS
public
mixed
ELLIPSIS
= '…'
MAX_LENGTH
A longer path text (characters) is shortened in the middle even with few segments.
public
mixed
MAX_LENGTH
= 70
MAX_SEGMENTS
A path with more segments is shortened in the middle.
public
mixed
MAX_SEGMENTS
= 3
SEPARATOR
public
mixed
SEPARATOR
= ' › '
Methods
assign()
Returns the ancestors of each row from the root down to the parent (the row itself excluded).
public
static assign(array<int, array{id: int, lft: int, rgt: int}> $rows, array<int, array{id: int, lft: int, rgt: int, label: string}> $ancestors) : array<int, array<int, string>>
Parameters
- $rows : array<int, array{id: int, lft: int, rgt: int}>
- $ancestors : array<int, array{id: int, lft: int, rgt: int, label: string}>
-
query result (any order)
Return values
array<int, array<int, string>> —row id => ancestor labels; a row without ancestors gets an empty list
format()
Returns the path text: the full one (for `title`) and the displayed one, where a long path is shortened in the middle and the first and last segments stay.
public
static format(array<int, string> $labels) : array{full: string, short: string, segments: list}
segments are the displayed segments (including the ellipsis); the template renders them
unbreakable, so the line wraps only between them.
Parameters
- $labels : array<int, string>
Return values
array{full: string, short: string, segments: listpickQueryBounds()
Returns the bounds for the ancestors query: one row per parent (siblings share ancestors); roots and rows without valid bounds are left out.
public
static pickQueryBounds(array<int, array{id: int, parentId: int|null, lft: int, rgt: int}> $rows) : array<int, array{lft: int, rgt: int}>
Parameters
- $rows : array<int, array{id: int, parentId: int|null, lft: int, rgt: int}>