CoolCMS API

RegionHrefBuilder
in package

FinalYes

Computes region slugs (`href`) as the path of the parents.

Pure computation without I/O: the single implementation of the rule, shared by the Api rebuild hook (RegionManager::rebuildSubtreeHrefs()) and the import bin/geo-import-regions.php (which calls the same manager after writing). The repository supplies the data.

Everything is per language, from the parent hrefs and the name in the same language:

  • country (type = country) and root: href entered manually (empty falls back to the name slug), descendants inherit it,
  • district: href(region)-okres-slug(name without the district prefix), e.g. cr-stredocesky-kraj-okres-nymburk, cr-hlavni-mesto-praha-okres-praha-1,
  • municipality, region and untyped node: href(parent)-slug(name), e.g. ...-okres-nymburk-nymburk (repetition is deliberately not skipped: one uniform rule without exceptions),
  • collision within a language: -{official_code}, otherwise -{region_id}; the bare href stays with the node closest to the root, a tie on the same level puts the suffix on all of them.

Steps (between them the repository fetches the colliding rows from the whole table):

  1. buildBaseHrefs() - hrefs without collision handling, top down,
  2. buildBaseLookupValues() - bare hrefs to query for collisions,
  3. buildSuffixLookupValues() - suffixes of the colliding nodes to query (occupancy),
  4. resolveHrefs() - collision to suffix.

Node shape: array{id: int, parentId: ?int, type: ?string, officialCode: ?string, texts: array<int, array{name: string, href: string}>} (the texts key is the language id).

Tags
phpstan-type

RegionHrefNode array{id: int, parentId: ?int, type: ?string, officialCode: ?string, texts: array<int, array{name: string, href: string}>}

RegionHrefOutsideRow array{id: int, languageId: int, level: int, href: string, base: string}

Table of Contents

Constants

DISTRICT_NAME_PREFIX  : string = 'Okres '
District name prefix (as stored in the DB) that the slug replaces with the {@see DISTRICT_SEGMENT} marker.
DISTRICT_SEGMENT  : string = 'okres'
District marker in the path: `...-okres-nymburk`.
TYPE_COUNTRY  : string = 'country'
TYPE_DISTRICT  : string = 'district'
TYPE_MUNICIPALITY  : string = 'municipality'

Properties

$slugCache  : array<string, string>

Methods

buildBaseHrefs()  : array<int, array<int, string>>
Step 1: subtree node hrefs without collision handling.
buildBaseLookupValues()  : array<int, string>
Step 2: bare subtree hrefs (all languages together, one table pass per batch).
buildSuffixLookupValues()  : array<int, string>
Step 3: suffixes (`-{official_code}`, `-{region_id}`) only for nodes that collide according to the rows from step 2; the repository uses them to verify that the suffix is not taken.
isManualNode()  : bool
A manual node is a country or a tree root (also one added by hand without a type): a person enters its href.
resolveHrefs()  : array<int, array<int, string>>
Step 4: collision to suffix.
buildPathHref()  : string
buildSegment()  : string
Slug of the own name; without a name in the language it falls back to the region id (the href must not be empty).
buildSubtreeIdSet()  : array<int, int>
buildSuffixCandidates()  : array<int, string>
Suffixes in order of preference: `-{official_code}`, then `-{region_id}`.
computeDepths()  : array<int, int>
Depth of the subtree nodes (tree root = 1, same as the `level` column), computed from the number of ancestors and not from the column: a newly inserted node gets `level` only after `afterSave`.
findSuffixedNodes()  : array<int, RegionHrefNode, 1: int, 2: string}>
Subtree nodes that must receive a suffix (see {@see resolveHrefs()}).
joinSegments()  : string
slug()  : string
`Strings::webalize()` is expensive (transliteration) and district names repeat for every municipality.

Constants

DISTRICT_NAME_PREFIX

District name prefix (as stored in the DB) that the slug replaces with the {@see DISTRICT_SEGMENT} marker.

public string DISTRICT_NAME_PREFIX = 'Okres '

DISTRICT_SEGMENT

District marker in the path: `...-okres-nymburk`.

public string DISTRICT_SEGMENT = 'okres'

Properties

Methods

buildBaseHrefs()

Step 1: subtree node hrefs without collision handling.

public buildBaseHrefs(array<int, RegionHrefNode> $ancestors, array<int, RegionHrefNode> $subtree[, array<int, string> $rootHrefs = [] ]) : array<int, array<int, string>>

$ancestors are the ancestors of the subtree root (from the tree root); their href is taken from the DB as is. $subtree is the subtree root plus descendants ordered so that a parent precedes its child (nested set by lft). $rootHrefs is the manual subtree root href per language (CLI country abbreviation setting); used only for a manual node (country / root).

Parameters
$ancestors : array<int, RegionHrefNode>
$subtree : array<int, RegionHrefNode>
$rootHrefs : array<int, string> = []

languageId => href

Return values
array<int, array<int, string>> —

regionId => languageId => href

buildBaseLookupValues()

Step 2: bare subtree hrefs (all languages together, one table pass per batch).

public buildBaseLookupValues(array<int, array<int, string>> $bases) : array<int, string>
Parameters
$bases : array<int, array<int, string>>

regionId => languageId => href

Return values
array<int, string>

buildSuffixLookupValues()

Step 3: suffixes (`-{official_code}`, `-{region_id}`) only for nodes that collide according to the rows from step 2; the repository uses them to verify that the suffix is not taken.

public buildSuffixLookupValues(array<int, array<int, string>> $bases, array<int, RegionHrefNode> $ancestors, array<int, RegionHrefNode> $subtree, array<int, RegionHrefOutsideRow> $outsideRows) : array<int, string>
Parameters
$bases : array<int, array<int, string>>
$ancestors : array<int, RegionHrefNode>
$subtree : array<int, RegionHrefNode>
$outsideRows : array<int, RegionHrefOutsideRow>
Return values
array<int, string>

isManualNode()

A manual node is a country or a tree root (also one added by hand without a type): a person enters its href.

public isManualNode(RegionHrefNode $node) : bool
Parameters
$node : RegionHrefNode
Return values
bool

resolveHrefs()

Step 4: collision to suffix.

public resolveHrefs(array<int, array<int, string>> $bases, array<int, RegionHrefNode> $ancestors, array<int, RegionHrefNode> $subtree, array<int, RegionHrefOutsideRow> $outsideRows) : array<int, array<int, string>>

Candidates for a bare href within a language: subtree nodes with the same href and rows outside the subtree with the same href or the same base (base = href without its own -{official_code} / -{region_id} suffix, computed by the repository). The bare href stays with the single candidate on the highest level (smallest depth); other subtree nodes get a suffix. A subtree node never receives an href exactly occupied by a row outside the subtree (a foreign row is not rewritten, uniqueness wins). Only the set of candidates and their level decide, not the processing order, so rebuilding one municipality gives the same result as rebuilding the whole country.

Manual nodes (country / root) are never renamed because a person entered them; they only occupy their href.

Parameters
$bases : array<int, array<int, string>>

regionId => languageId => href

$ancestors : array<int, RegionHrefNode>
$subtree : array<int, RegionHrefNode>
$outsideRows : array<int, RegionHrefOutsideRow>

rows from the whole table (subtree rows are ignored)

Return values
array<int, array<int, string>> —

regionId => languageId => href

buildPathHref()

private buildPathHref(RegionHrefNode $node, int $languageId, array<int, RegionHrefNode> $nodes, array<int, array<int, string>> $hrefs) : string
Parameters
$node : RegionHrefNode
$languageId : int
$nodes : array<int, RegionHrefNode>
$hrefs : array<int, array<int, string>>

hrefs already computed (ancestors from the DB, subtree top down)

Return values
string

buildSegment()

Slug of the own name; without a name in the language it falls back to the region id (the href must not be empty).

private buildSegment(RegionHrefNode $node, int $languageId) : string
Parameters
$node : RegionHrefNode
$languageId : int
Return values
string

buildSubtreeIdSet()

private buildSubtreeIdSet(array<int, RegionHrefNode> $subtree) : array<int, int>
Parameters
$subtree : array<int, RegionHrefNode>
Return values
array<int, int>

buildSuffixCandidates()

Suffixes in order of preference: `-{official_code}`, then `-{region_id}`.

private buildSuffixCandidates(RegionHrefNode $node, string $base) : array<int, string>
Parameters
$node : RegionHrefNode
$base : string
Return values
array<int, string>

computeDepths()

Depth of the subtree nodes (tree root = 1, same as the `level` column), computed from the number of ancestors and not from the column: a newly inserted node gets `level` only after `afterSave`.

private computeDepths(array<int, RegionHrefNode> $ancestors, array<int, RegionHrefNode> $subtree) : array<int, int>
Parameters
$ancestors : array<int, RegionHrefNode>
$subtree : array<int, RegionHrefNode>
Return values
array<int, int> —

regionId => depth

findSuffixedNodes()

Subtree nodes that must receive a suffix (see {@see resolveHrefs()}).

private findSuffixedNodes(array<int, array<int, string>> $bases, array<int, RegionHrefNode> $ancestors, array<int, RegionHrefNode> $subtree, array<int, RegionHrefOutsideRow> $outsideRows) : array<int, RegionHrefNode, 1: int, 2: string}>
Parameters
$bases : array<int, array<int, string>>
$ancestors : array<int, RegionHrefNode>
$subtree : array<int, RegionHrefNode>
$outsideRows : array<int, RegionHrefOutsideRow>
Return values
array<int, RegionHrefNode, 1: int, 2: string}> —

[node, language, bare href]

joinSegments()

private joinSegments(string ...$segments) : string
Parameters
$segments : string
Return values
string

slug()

`Strings::webalize()` is expensive (transliteration) and district names repeat for every municipality.

private slug(string $value) : string
Parameters
$value : string
Return values
string
On this page

Search results