CoolCMS API

TreePathBuilder
in package

FinalYes

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

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

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: list}

pickQueryBounds()

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}>
Return values
array<int, array{lft: int, rgt: int}>
On this page

Search results