OrderByHelper
in package
Table of Contents
Constants
- CURRENT_PRICE_PATTERN : string = '/^currentPrice\[currencyId:(\d+)(?:,userGroupI...
- Sort key for the current price in a currency: `currentPrice[currencyId:3]` or `currentPrice[currencyId:3,userGroupId:1]`.
- LANGUAGE_SCOPED_PATTERN : string = '/^([A-Za-z_][A-Za-z0-9_]*)\[languageId:(\d+)\]...
- Sort key for a translation field in one language: `translations[languageId:2].name`.
Methods
- addOrderBys() : void
- currentPriceField() : string
- Builds the sort key for the current product set price in the display currency.
- parseCurrentPriceField() : array{currencyId: int, userGroupId: ?int}|null
- translatedField() : string
- Builds the sort key for a translated field in one language (e.g. the name in the page language).
- withIdTiebreak() : array<string, bool>
- Appends a unique tiebreak key (id) to the ordering unless it is already present.
- extractFieldName() : string
- joinLanguageScoped() : string
- Adds `LEFT JOIN root.relation alias WITH alias.languageId = N` and returns its alias.
- parseOrderByField() : array{type: "expression", field: string, path: string, expr: string}|array{type: "relation"|"simple", field: string, path: string, expr: null}
Constants
CURRENT_PRICE_PATTERN
Sort key for the current price in a currency: `currentPrice[currencyId:3]` or `currentPrice[currencyId:3,userGroupId:1]`.
private
string
CURRENT_PRICE_PATTERN
= '/^currentPrice\[currencyId:(\d+)(?:,userGroupId:(\d+))?\]$/'
LANGUAGE_SCOPED_PATTERN
Sort key for a translation field in one language: `translations[languageId:2].name`.
private
string
LANGUAGE_SCOPED_PATTERN
= '/^([A-Za-z_][A-Za-z0-9_]*)\[languageId:(\d+)\]\.([A-Za-z_][A-Za-z0-9_]*)$/'
Methods
addOrderBys()
public
static addOrderBys(QueryBuilder $qb, array<string|int, mixed> $orderBys, string $fromTableAlias[, string|null $textTableAlias = null ]) : void
Parameters
- $qb : QueryBuilder
- $orderBys : array<string|int, mixed>
- $fromTableAlias : string
- $textTableAlias : string|null = null
currentPriceField()
Builds the sort key for the current product set price in the display currency.
public
static currentPriceField(int $currencyId[, int|null $userGroupId = null ]) : string
IMPORTANT: the denormalized product_sets.price holds the price in the default currency
only, so sorting by it on a page in another currency would order by the wrong amounts.
The eshop Api repository (ProductSetRepository::applyOrdering()) turns this key into a
subquery over the current-price view; the Api manager supplies the default price group,
the front end does not know it.
Parameters
- $currencyId : int
- $userGroupId : int|null = null
Return values
stringparseCurrentPriceField()
public
static parseCurrentPriceField(string $field) : array{currencyId: int, userGroupId: ?int}|null
Parameters
- $field : string
Return values
array{currencyId: int, userGroupId: ?int}|nulltranslatedField()
Builds the sort key for a translated field in one language (e.g. the name in the page language).
public
static translatedField(string $relation, string $field, int|null $languageId) : string
IMPORTANT: a bare translations.name joins translations of all languages, so
SELECT DISTINCT id ... ORDER BY t.name sorts by the name in any of them, depending on
which row the database picks. addOrderBys() turns this key into a
LEFT JOIN ... WITH language = :id used for sorting only: nothing is filtered out (an entity
without a translation sorts among nulls), at most one row per entity, and translation
hydration is not affected.
A null language keeps the bare behavior (translations.name).
Parameters
- $relation : string
- $field : string
- $languageId : int|null
Return values
stringwithIdTiebreak()
Appends a unique tiebreak key (id) to the ordering unless it is already present.
public
static withIdTiebreak(array<string, bool> $orderBys[, string $idField = 'id' ]) : array<string, bool>
IMPORTANT: without it, rows with equal sort values (price 0, same date, same view count)
are ordered non-deterministically in MySQL/MariaDB, so LIMIT/OFFSET repeats some items
across pages and skips others.
The id direction copies the direction of the last key (descending order puts newer ids first). An empty ordering stays empty: the caller wants no ordering (e.g. Elasticsearch relevance).
Parameters
- $orderBys : array<string, bool>
-
field => ascending (true) / descending (false)
- $idField : string = 'id'
Return values
array<string, bool>extractFieldName()
private
static extractFieldName(string $path) : string
Parameters
- $path : string
Return values
stringjoinLanguageScoped()
Adds `LEFT JOIN root.relation alias WITH alias.languageId = N` and returns its alias.
private
static joinLanguageScoped(QueryBuilder $qb, string $fromTableAlias, string $relation, int $languageId) : string
The join has its own alias (not one from JoinHelper), so the language condition does
not narrow a join that other conditions (fulltext, parameters) filter through. Repeated
calls do not add the join again.
Parameters
- $qb : QueryBuilder
- $fromTableAlias : string
- $relation : string
- $languageId : int
Return values
stringparseOrderByField()
private
static parseOrderByField(string $field) : array{type: "expression", field: string, path: string, expr: string}|array{type: "relation"|"simple", field: string, path: string, expr: null}
Parameters
- $field : string