ListQueryTrait uses trait:short, trait:short, \oihana\models\traits\ConditionsTrait, trait:short, trait:short, trait:short, trait:short, trait:short, trait:short, trait:short
Provides an ArangoDB query to list retrieval capabilities for document collections.
This trait combines multiple AQL-building sub-traits to construct flexible, feature-rich queries for retrieving documents from ArangoDB collections. It supports filtering, searching, sorting, pagination, and field selection.
Tags
Table of Contents
Constants
- BOUNDS : string = 'bounds'
- The 'bounds' parameter constant.
- EDGE_SUFFIX : string = '_e'
- The suffix used for edge fields in queries.
- FACETS : string = 'facets'
- The 'facets' parameter constant.
- FIELDS : string = 'fields'
- The 'fields' key for initialization arrays.
- FILTERS : string = 'filters'
- The 'filters' parameter constant.
- JOIN_SUFFIX : string = '_j'
- The suffix used for join fields in queries.
- SEARCHABLE : string = 'searchable'
- The 'searchable' parameter key.
- UNIQUE_SUFFIX : string = '_u'
- The suffix used for unique fields in queries.
- NORMALIZED_MARKERS : array<string|int, mixed> = [\oihana\arango\enums\Field::ALTERS, \oihana\ar...
- The scalar `Field::` markers copied **verbatim** from the raw field options into the normalized definition produced by {@see normalizeFieldDefinition()}.
Properties
- $activable : bool
- $bounds : array<string|int, mixed>|null
- The bounds whitelist (`field => true | definition`), or `null` when nothing is boundable.
- $facets : array<string|int, mixed>|null
- The facet settings.
- $fields : array<string, mixed>
- The fields definitions to return in get/list methods.
- $filters : array<string|int, mixed>|null
- Defines all valid filtering conditions for queries used in the list() and count() methods.
- $groupable : array<string, string>|null
- Optional whitelist/mapping of groupable dimensions: `urlKey => fieldPath`.
- $searchable : array<string|int, mixed>|null
- The searchable fields swept by the classic `?search=` `LIKE` (see {@see prepareSearch()}). A list of field names; an entry may instead be an array carrying its name under {@see Search::KEY} plus options such as {@see Search::REQUIRES} to gate the field by permission:
- $searchOperator : string
- The default operator combining the words of a `?search=` term **within a field** during the classic `LIKE` sweep ({@see prepareSearch()}): {@see \oihana\arango\db\enums\Logic::AND} (every word must be found in the field, order-independent) or {@see \oihana\arango\db\enums\Logic::OR} (the whole term matched as one substring — the default, backward-compatible).
- $searchSeparators : string
- The extra characters (beyond whitespace) that split a `?search=` term into words for the `AND` operator of the classic `LIKE` sweep ({@see prepareSearch()}).
- $skinFields : array<string, array<string, mixed>>
- Optional per-skin alternative projections for the model's own fields.
- $sortable : array<string|int, mixed>|null
- The collection (map) of all the sortable fields.
- $view : array<string|int, mixed>|null
- The model-level ArangoSearch declaration (`AQL::VIEW` block, see {@see Search}).
Methods
- buildListQuery() : string
- Builds an AQL query for listing documents with comprehensive filtering, sorting, and pagination.
- getViewLinks() : array<string, ArangoSearchLink>
- Returns the desired per-collection link map of the declared View — the model's collection linked with {@see buildViewLink()} — or an empty map when the model has no collection.
- getViewName() : string|null
- Returns the name of the declared View ({@see Search::NAME} of the `AQL::VIEW` block), or `null` when the model declares none.
- hasViewSearch() : bool
- Indicates whether the View search is active: the model declares a named View (`AQL::VIEW` block) with at least one searched field, **and** the request carries a non-empty search term.
- initializeActivable() : static
- Initialize the activable flag to check if the documents are 'active' or not.
- initializeBounds() : static
- Initialize the 'bounds' property.
- initializeFacets() : static
- Initialize the 'facets' property.
- initializeFields() : static
- Initialize fields definitions from an associative array.
- initializeFilters() : static
- Initialize the 'filters' property.
- initializeGroupable() : static
- Initializes the {@see GroupTrait::$groupable} whitelist from the model options.
- initializeSearchable() : static
- Initialize the 'searchable' property.
- initializeSearchOperator() : static
- Initialize the `LIKE` sweep operator ({@see $searchOperator}) from the `Search::OPERATOR` init key. An explicit value is normalized to {@see Logic::AND} / {@see Logic::OR}; an absent key keeps the default ({@see Logic::OR}, backward-compatible).
- initializeSearchSeparators() : static
- Initialize the `LIKE` sweep word separators ({@see $searchSeparators}) from the `Search::SEPARATORS` init key. Accepts a string of characters or a list of characters (joined to a string); an absent key keeps the default (the hyphen). Only meaningful with the `AND` operator. See {@see Search::SEPARATORS}.
- initializeSkinFields() : static
- Initialize the per-skin projections registry from an associative array.
- initializeSortable() : $this
- Initialize the sortable array definition.
- initializeView() : static
- Initialize the model-level ArangoSearch declaration (`AQL::VIEW` block) and lazily provision the View, mirroring the collection provisioning of `initializeCollection()`: when the model is lazy and the declared View does not exist, it is created from the declaration — the searched fields (dotted paths supported) are linked on the model's collection with the declared {@see Search::ANALYZER}. An existing View is never altered — inspect and resynchronize explicitly with {@see viewDiff()} / {@see viewSync()} (or the `views` action of the `arangodb` command).
- prepareActive() : string|null
- Prepare the 'active' variable.
- prepareCollect() : array<string|int, mixed>
- Resolves the `COLLECT` spec for a list query.
- prepareFilter() : string|null
- Prepare the AQL query filtering with specific definitions.
- prepareGroupSort() : string|null
- Builds the `SORT` clause applied to a grouped result, from {@see Group::SORT}.
- prepareQueryFields() : array<string, array<string|int, mixed>>|null
- Prepares query fields based on internal definitions and optional skin filter.
- prepareSearch() : string|null
- Prepare the searchable AQL conditions — the classic `?search=` `LIKE` sweep, a parenthesized `OR` of case-insensitive `LIKE()` predicates over every (permitted) searchable field, used when no View search is active.
- prepareSort() : string|null
- Prepare the AQL `SORT` expression from the `?sort=` grammar and, optionally, the `?near=` anchor.
- prepareViewSearch() : string|null
- Prepare the relevance-ranked `SEARCH` expression of an active View search, or `null` when the View search is inactive (no `AQL::VIEW` declaration, no searched fields, or no search term) — the caller then falls back to the classic `LIKE` sweep of {@see prepareSearch()}.
- returnFields() : string
- Generates an AQL document expression or LET statement with the selected fields.
- viewDiff() : DiffReport
- Compares the model's View declaration with the server state and reports the differences, without touching anything.
- viewSync() : DiffReport
- Reconciles the model's View with its declaration: creates it when missing, repairs a drift with `updateProperties()` (the View stays available while the inverted index rebuilds in the background), and leaves {@see DiffStatus::IN_SYNC}, {@see DiffStatus::INVALID} or {@see DiffStatus::UNREACHABLE} reports untouched.
- alterFilterKey() : string
- Apply the key-side (left) `alt` transformation to a key expression.
- buildFilteredScope() : array{0: string, 1: ?string}
- Builds the `FOR` segment and the conjunctive `FILTER` clause shared by the list-family queries.
- buildViewLink() : ArangoSearchLink
- Builds the View link of the model's collection from the `AQL::VIEW` declaration: every searched field (dotted paths become nested fields) is indexed with its resolved Analyzer — the per-field {@see Search::ANALYZER} when declared, otherwise the View-level one.
- buildViewSearchGroups() : array<string, array<string|int, string>>
- Builds the per-Analyzer expression groups of the View search under the historical `OR` grammar : each comma-separated term is bound whole and matched in one shot per field (`doc.<field> IN TOKENS(@search_N, …)`, whose `IN` semantics already `OR` the term's tokens), plus the optional phrase and fuzzy branches. This is the exact grammar emitted when no field opts into {@see Search::OPERATOR} `AND` — see {@see prepareViewSearch()}.
- buildViewSearchGroupsWithOperator() : array<string, array<string|int, string>>
- Builds the per-Analyzer expression groups when at least one field opts into {@see Search::OPERATOR} `AND`. Each comma-separated term is split into words (whitespace) ; a field then combines those words with its resolved operator :
- getSearchableSpecs() : array<string, array<string, mixed>>
- Normalizes the model's `AQL::SEARCHABLE` list into a per-field specification map `field => [ (Search::REQUIRES => …)? ]`, the single source consumed by {@see prepareSearch()} (the `LIKE` sweep) and by the `searchable` fallback of {@see getViewFieldSpecs()}.
- getViewFieldSpecs() : array<string, array<string, mixed>>
- Normalizes the searched fields of the `AQL::VIEW` declaration into a per-field specification map `field => [ Search::BOOST => float, … ]` — the single source of truth from which {@see getViewSearchFields()} derives the boost map and {@see prepareViewSearch()} resolves the per-field options.
- getViewSearchFields() : array<string, float>
- Normalizes the searched fields into a `field => boost` map — a boost-only façade over {@see getViewFieldSpecs()}, used by {@see buildViewLink()} and {@see viewDiff()} which only care about the field paths and their weights.
- ngramMatch() : string
- Builds the `NGRAM_MATCH(doc.<field>, @term [, threshold], "<analyzer>")` core of a {@see Search::NGRAM} branch (without the surrounding boost). The threshold is inlined only when the field declares one, else the server default applies. Shared by the whole-term and the per-word emissions.
- prepareFacets() : string|null
- Prepare the query with AQL facets definitions.
- prepareFilterBetween() : string
- Prepares an inclusive `between` (range) clause: `key >= @min && key <= @max`.
- prepareFilterComparator() : string
- Prepares the filter clause with a specific operator.
- prepareFilterKey() : string
- Prepares the filter clause with a specific key and document, with optional function transformations via 'alt' parameter.
- prepareFilterValue() : string
- Prepare the filter clause with a specific value to evaluates.
- prepareNear() : string|null
- Build the `DISTANCE(...)` expression for a `?near=` anchor and bind its coordinates.
- pushWholeTermField() : void
- Pushes the whole-term match of one field onto the Analyzer groups — the base `doc.<field> IN TOKENS(@term, …)` (boosted when the field weight is not `1`), the optional exact-phrase bonus and the optional fuzzy branch, plus the {@see Search::NGRAM} branch when declared. This is the `OR`-grammar emission, shared by {@see buildViewSearchGroups()} (every field) and by the `OR` fields of {@see buildViewSearchGroupsWithOperator()}.
- resolveFieldSearchSpec() : array{0: string[], 1: float, 2: int, 3: bool, 4: string}
- Resolves the per-field search facets shared by both group builders : the Analyzers indexing the field (a per-field {@see Search::ANALYZER} overrides the View-level one, a single Analyzer normalized to a one-element list), the boost, the fuzzy tolerance and phrase bonus (a per-field value overrides the View-level default), and the `doc.<field>` accessor (with the `[*]` array marker stripped — the flat path already matches any element of the indexed array, and the `SEARCH` grammar rejects the expansion form).
- splitSearchTermWords() : array<string|int, string>
- Splits an `AND`-operator search term into its words, on whitespace plus the given extra separator characters ({@see Search::SEPARATORS}). Whitespace always splits; `$separators` adds literal characters (a string, or a list of characters joined to one), `null` falls back to the hyphen default, and an empty value splits on whitespace only. The extra characters are regex-escaped, so any punctuation is safe. Empty words are dropped.
- authorizeSortKey() : string|null
- Resolve a whitelisted sort entry to its AQL field expression, gated by permission.
- collectAggregate() : array<string|int, mixed>
- Builds the `AQL::AGGREGATE` map from {@see Group::AGG}.
- collectAssign() : array<string|int, mixed>
- Builds the `AQL::ASSIGN` map from {@see Group::BY} and {@see Group::ALT}.
- collectMatchFields() : array<int, string>
- Collects the field names referenced by a `match` payload, for the permission gate. Mirrors the shape read by {@see \oihana\arango\db\helpers\buildCombinedInlineFilter()}: the explicit `all` / `any` / `none` lists expose their field under `key`, while the simple object form (`{ propertyID: …, value: … }`) uses its keys directly.
- filterFieldsBySkin() : array<string, mixed>
- Filters fields based on an optional skin.
- generateUniqueKey() : string|null
- Generates a unique key for special filters like edges, joins, or unique names.
- isSortAuthorized() : bool
- Decide whether a sort/near field is granted for the request.
- normalizeAggregate() : array{0: ?string, 1: ?string}
- Normalizes an aggregate definition into a `[ code, field ]` pair.
- normalizeFieldDefinition() : array<string, mixed>|null
- Normalize a field definition into a structured array for queries.
- normalizeGroupFields() : array<string, string>
- Normalizes {@see Group::BY} into a `[ varName => field ]` map.
- resolveSortEntry() : array{0: mixed, 1: mixed}
- Resolve a whitelisted sort entry to its `[ fieldPath, requires ]` pair.
Constants
BOUNDS
The 'bounds' parameter constant.
public
string
BOUNDS
= 'bounds'
EDGE_SUFFIX
The suffix used for edge fields in queries.
public
string
EDGE_SUFFIX
= '_e'
FACETS
The 'facets' parameter constant.
public
string
FACETS
= 'facets'
FIELDS
The 'fields' key for initialization arrays.
public
string
FIELDS
= 'fields'
FILTERS
The 'filters' parameter constant.
public
string
FILTERS
= 'filters'
JOIN_SUFFIX
The suffix used for join fields in queries.
public
string
JOIN_SUFFIX
= '_j'
SEARCHABLE
The 'searchable' parameter key.
public
string
SEARCHABLE
= 'searchable'
UNIQUE_SUFFIX
The suffix used for unique fields in queries.
public
string
UNIQUE_SUFFIX
= '_u'
NORMALIZED_MARKERS
The scalar `Field::` markers copied **verbatim** from the raw field options into the normalized definition produced by {@see normalizeFieldDefinition()}.
private
array<string|int, mixed>
NORMALIZED_MARKERS
= [\oihana\arango\enums\Field::ALTERS, \oihana\arango\enums\Field::DEFAULT, \oihana\arango\enums\Field::ELSE, \oihana\arango\enums\Field::FORMAT, \oihana\arango\enums\Field::NAME, \oihana\arango\enums\Field::NULLABLE, \oihana\arango\enums\Field::PATH, \oihana\arango\enums\Field::PATHS, \oihana\arango\enums\Field::PROPERTY, \oihana\arango\enums\Field::QUOTED, \oihana\arango\enums\Field::RAW, \oihana\arango\enums\Field::REQUIRES, \oihana\arango\enums\Field::SELF_REQUIRES, \oihana\arango\enums\Field::SCOPE, \oihana\arango\enums\Field::WHEN, \oihana\arango\enums\Field::WHERE]
⚠️ Single source of truth — register every new marker here. A scalar
Field:: marker absent from this list is silently stripped during projection
normalization, so it never reaches the query builders nor the permission gates
(this is exactly how Field::SELF_REQUIRES was first lost). The structural
markers are built separately and must NOT be added here: Field::FILTER (seeded
from the already-resolved filter), Field::FIELDS / Field::EDGES /
Field::JOINS (sub-projections attached after the recursive walk),
Field::UNIQUE (generated), and the skin buckets (AQL::SKIN_FIELDS).
Field::DEFAULT is intentionally kept even though it resolves to null
(Field::DEFAULT === null), so the copy is byte-for-byte identical to the
historical literal table.
Properties
$activable
public
bool
$activable
= false
$bounds
The bounds whitelist (`field => true | definition`), or `null` when nothing is boundable.
public
array<string|int, mixed>|null
$bounds
= []
$facets
The facet settings.
public
array<string|int, mixed>|null
$facets
= []
$fields
The fields definitions to return in get/list methods.
public
array<string, mixed>
$fields
= []
Keys are field names, values are either a Filter constant, a definition array, or null.
Tags
$filters
Defines all valid filtering conditions for queries used in the list() and count() methods.
public
array<string|int, mixed>|null
$filters
= []
$groupable
Optional whitelist/mapping of groupable dimensions: `urlKey => fieldPath`.
public
array<string, string>|null
$groupable
= null
When set, only whitelisted Group::BY keys are allowed and each
resolves to its real field path (decoupling the public group key from the
internal attribute, like SortTrait::$sortable). The gate is
fail-closed: null (no whitelist) means nothing is groupable — a
client key never reaches doc.<key>. A whitelisted dimension is further
permission-gated (Field::REQUIRES inherited from the projection), so a
field hidden from reading cannot be grouped on (no group-by oracle).
$searchable
The searchable fields swept by the classic `?search=` `LIKE` (see {@see prepareSearch()}). A list of field names; an entry may instead be an array carrying its name under {@see Search::KEY} plus options such as {@see Search::REQUIRES} to gate the field by permission:
public
array<string|int, mixed>|null
$searchable
= []
AQL::SEARCHABLE =>
[
'name' , // public
[ Search::KEY => 'salary' , Search::REQUIRES => 'hr:salary' ], // gated
]
$searchOperator
The default operator combining the words of a `?search=` term **within a field** during the classic `LIKE` sweep ({@see prepareSearch()}): {@see \oihana\arango\db\enums\Logic::AND} (every word must be found in the field, order-independent) or {@see \oihana\arango\db\enums\Logic::OR} (the whole term matched as one substring — the default, backward-compatible).
public
string
$searchOperator
= \oihana\arango\db\enums\Logic::OR
Set once per model through the Search::OPERATOR init key. The View search
carries its own operator inside the AQL::VIEW block (per field), see
Search::OPERATOR.
$searchSeparators
The extra characters (beyond whitespace) that split a `?search=` term into words for the `AND` operator of the classic `LIKE` sweep ({@see prepareSearch()}).
public
string
$searchSeparators
= \oihana\enums\Char::HYPHEN
A string of characters; set once per model through the Search::SEPARATORS
init key (a list of characters is normalized to a string at init). The
default is the hyphen (-) so « Jean-Marc » splits like « Jean Marc »; an
empty string keeps hyphenated codes whole. Only used in AND mode. See
Search::SEPARATORS.
$skinFields
Optional per-skin alternative projections for the model's own fields.
public
array<string, array<string, mixed>>
$skinFields
= []
A skin => fields table with the exact same semantics as the
AQL::SKIN_FIELDS key of an edge/join definition : each bucket is a
complete fields array (same shape as $fields), the resolution
order is [$skin] → ['*'] → $fields → null, and the selected
bucket fully replaces the others (no merging). An edge/join that
declares no projection of its own inherits the target model's buckets,
since it prepares the model fields with the request skin.
An empty registry (default) keeps the legacy single-projection behavior, byte-for-byte.
Tags
$sortable
The collection (map) of all the sortable fields.
public
array<string|int, mixed>|null
$sortable
= null
$view
The model-level ArangoSearch declaration (`AQL::VIEW` block, see {@see Search}).
public
array<string|int, mixed>|null
$view
= null
When present (with a Search::NAME), the ?search= parameter switches
from the simple LIKE sweep to an index-accelerated, relevance-ranked
SEARCH against the declared View.
Methods
buildListQuery()
Builds an AQL query for listing documents with comprehensive filtering, sorting, and pagination.
public
buildListQuery([array<string|int, mixed> $init = [] ][, array<string|int, mixed> &$bindVars = [] ]) : string
This method orchestrates the construction of a complete AQL query by combining various query components (FOR, FILTER, SORT, LIMIT, RETURN) based on the provided initialization parameters. It delegates to specialized methods for each query aspect (filtering, sorting, etc.) and compiles them into a single executable AQL statement.
Generated Query Structure:
FOR doc IN @@collection
[LET variables...]
FILTER doc.active == [1|0] [&& facets] [&& filter] [&& search] [&& conditions]
SORT field1 ASC, field2 DESC
LIMIT offset, limit
RETURN { ...fields }
Query Building Process:
- Extract configuration parameters (limit, offset, variables, debug)
- Build FOR clause with collection binding
- Construct FILTER clause combining active, facets, filter, and search
- Generate SORT clause from sort criteria
- Add LIMIT/OFFSET for pagination
- Define RETURN clause with field selection
- Compile all components into final query
- Optionally debug the generated query
Usage Example:
$bindVars = [];
$query = $model->buildListQuery([
'active' => true,
'filter' => ['status' => 'published'],
'sort' => ['createdAt' => 'DESC'],
'limit' => 50,
'offset' => 0,
'fields' => ['_key', 'title', 'author'],
'debug' => true
], $bindVars);
// Returns: "FOR doc IN @@collection FILTER doc.active == 1 && ..."
// $bindVars now contains: ['@collection' => 'myCollection', ...]
Parameters
- $init : array<string|int, mixed> = []
-
Configuration array with optional parameters:
Query Variables:*
variables(array, optional) Additional AQL LET statements to declare variables in the query. Example:['total = LENGTH(doc.items)', 'avg = SUM(doc.prices) / total']Default:[]
Pagination:*
-
limit(int, optional) Maximum number of documents to return. Set to0for no limit. Example:50Default:0 -
offset(int, optional) Number of documents to skip before returning results. Useful for pagination when combined withlimit. Example:100(skip first 100 documents) Default:0
Filtering:*
-
active(?bool, optional) Filter by document active status.truefor active only,falsefor inactive only,nullto ignore this filter. Processed byprepareActive(). Default:null -
facets(?array, optional) Array of facet-based filter conditions. Facets are typically used for categorical filtering (categories, tags, types, etc.). Processed byprepareFacets(). Example:['category' => 'electronics', 'brand' => 'Apple']Default:null -
conditions(?array, optional) Array of custom AQL filter conditions. When provided, this completely overrides the automatic combination of active/facets/filter/search. Use this for complex custom filtering logic. Example:['doc.price > 100', 'doc.stock > 0']Default:null -
filter(?array, optional) Array of general filter conditions applied as key-value pairs. Processed byprepareFilter(). Example:['status' => 'published', 'author.verified' => true]Default:null -
search(?array, optional) Array of search conditions for text-based filtering. Typically used for full-text or partial string matching. Processed byprepareSearch(). Example:['title' => 'laptop', 'description' => 'gaming']Default:null
Sorting:*
sort(?array, optional) Array defining sort criteria. Keys are field names (support dot notation), values are 'ASC' or 'DESC'. Multiple fields create compound sorting. Processed byprepareSort(). Example:['priority' => 'DESC', 'createdAt' => 'ASC']Default:null
Field Selection:*
fields(?array<string>, optional) Array of field names to include in returned documents. Supports dot notation for nested fields. If not provided, all document fields are returned. Processed byreturnFields(). Example:['_key', 'title', 'author.name', 'metadata.tags']Default:null(returns all fields)
Output Transformation:*
skin(?string, optional) Name of the skin/transformation to apply to result documents. Applied during thealter()phase after query execution. Example:'summary','detailed','api'Default:null
Query Binding:*
binds(array<string, mixed>, optional) Additional AQL bind variables to include in the query. Merged with auto-generated bind variables. Example:['minPrice' => 100, 'category' => 'books']Default:[]
Debugging:*
debug(bool, optional) Enable query debugging. Whentrue, the generated AQL query and bind variables are logged viadebugQuery()before returning. Default:false
- $bindVars : array<string|int, mixed> = []
-
Reference to an array where bind variables will be collected. This array is populated during query construction with all necessary bind variables (collection name, filter values, search terms, etc.). After the method returns, this array contains all variables needed to execute the query.
Example of populated bindVars:*
[ '@collection' => 'products', 'active' => 1, 'status' => 'published', 'minPrice' => 100 ]
Tags
Return values
string —The compiled AQL query string ready for execution.
The query is a complete, executable AQL statement that can be
passed to ArangoDB along with the populated $bindVars.
Example Output:*
FOR doc IN @@collection
FILTER doc.active == @active && doc.status == @status
SORT doc.createdAt DESC
LIMIT 0, 50
RETURN { _key: doc._key, title: doc.title, price: doc.price }
getViewLinks()
Returns the desired per-collection link map of the declared View — the model's collection linked with {@see buildViewLink()} — or an empty map when the model has no collection.
public
getViewLinks() : array<string, ArangoSearchLink>
Tags
Return values
array<string, ArangoSearchLink>getViewName()
Returns the name of the declared View ({@see Search::NAME} of the `AQL::VIEW` block), or `null` when the model declares none.
public
getViewName() : string|null
Return values
string|nullhasViewSearch()
Indicates whether the View search is active: the model declares a named View (`AQL::VIEW` block) with at least one searched field, **and** the request carries a non-empty search term.
public
hasViewSearch([array<string|int, mixed>|string|null $search = [] ]) : bool
Parameters
- $search : array<string|int, mixed>|string|null = []
-
The
$initarray (readsArango::SEARCH) or the search term itself.
Tags
Return values
boolinitializeActivable()
Initialize the activable flag to check if the documents are 'active' or not.
public
initializeActivable([array<string|int, mixed> $init = [] ]) : static
Parameters
- $init : array<string|int, mixed> = []
Return values
staticinitializeBounds()
Initialize the 'bounds' property.
public
initializeBounds([array<string|int, mixed> $init = [] ]) : static
Parameters
- $init : array<string|int, mixed> = []
Return values
staticinitializeFacets()
Initialize the 'facets' property.
public
initializeFacets([array<string|int, mixed> $init = [] ]) : static
Parameters
- $init : array<string|int, mixed> = []
Return values
staticinitializeFields()
Initialize fields definitions from an associative array.
public
initializeFields([array<string, mixed> $init = [] ]) : static
Parameters
- $init : array<string, mixed> = []
-
Optional initialization array containing a 'fields' key.
Return values
staticinitializeFilters()
Initialize the 'filters' property.
public
initializeFilters([array<string|int, mixed> $init = [] ]) : static
Parameters
- $init : array<string|int, mixed> = []
Return values
staticinitializeGroupable()
Initializes the {@see GroupTrait::$groupable} whitelist from the model options.
public
initializeGroupable([array<string|int, mixed> $init = [] ]) : static
Parameters
- $init : array<string|int, mixed> = []
-
The model options (
Arango::GROUPABLE).
Return values
staticinitializeSearchable()
Initialize the 'searchable' property.
public
initializeSearchable([array<string|int, mixed> $init = [] ]) : static
Parameters
- $init : array<string|int, mixed> = []
Return values
staticinitializeSearchOperator()
Initialize the `LIKE` sweep operator ({@see $searchOperator}) from the `Search::OPERATOR` init key. An explicit value is normalized to {@see Logic::AND} / {@see Logic::OR}; an absent key keeps the default ({@see Logic::OR}, backward-compatible).
public
initializeSearchOperator([array<string|int, mixed> $init = [] ]) : static
Parameters
- $init : array<string|int, mixed> = []
Return values
staticinitializeSearchSeparators()
Initialize the `LIKE` sweep word separators ({@see $searchSeparators}) from the `Search::SEPARATORS` init key. Accepts a string of characters or a list of characters (joined to a string); an absent key keeps the default (the hyphen). Only meaningful with the `AND` operator. See {@see Search::SEPARATORS}.
public
initializeSearchSeparators([array<string|int, mixed> $init = [] ]) : static
Parameters
- $init : array<string|int, mixed> = []
Return values
staticinitializeSkinFields()
Initialize the per-skin projections registry from an associative array.
public
initializeSkinFields([array<string, mixed> $init = [] ]) : static
Parameters
- $init : array<string, mixed> = []
-
Optional initialization array containing an
AQL::SKIN_FIELDSkey.
Return values
staticinitializeSortable()
Initialize the sortable array definition.
public
initializeSortable([array<string|int, mixed> $init = [] ]) : $this
The raw definition (from the AQL::SORTABLE init key, or the property default)
is normalised through normalizeSortable() into the canonical
urlKey => fieldPath map. Three interchangeable notations are accepted and may
be mixed: the legacy associative urlKey => fieldPath, the indexed shorthand
fieldName (token equals field), and the indexed alias [ urlKey => fieldPath ].
null is preserved and means fail-closed (no whitelist → nothing client
sorts). The normalisation is idempotent.
Parameters
- $init : array<string|int, mixed> = []
Return values
$thisinitializeView()
Initialize the model-level ArangoSearch declaration (`AQL::VIEW` block) and lazily provision the View, mirroring the collection provisioning of `initializeCollection()`: when the model is lazy and the declared View does not exist, it is created from the declaration — the searched fields (dotted paths supported) are linked on the model's collection with the declared {@see Search::ANALYZER}. An existing View is never altered — inspect and resynchronize explicitly with {@see viewDiff()} / {@see viewSync()} (or the `views` action of the `arangodb` command).
public
initializeView([array<string|int, mixed> $init = [] ]) : static
Parameters
- $init : array<string|int, mixed> = []
Tags
Return values
staticprepareActive()
Prepare the 'active' variable.
public
prepareActive([array<string|int, mixed> $init = [] ][, array<string|int, mixed>|null &$binds = null ][, string $docRef = AQL::DOC ]) : string|null
Parameters
- $init : array<string|int, mixed> = []
- $binds : array<string|int, mixed>|null = null
- $docRef : string = AQL::DOC
Tags
Return values
string|nullprepareCollect()
Resolves the `COLLECT` spec for a list query.
public
prepareCollect([array<string|int, mixed> $init = [] ][, string $docRef = AQL::DOC ]) : array<string|int, mixed>
Translates a friendly Arango::GROUP spec (Group::BY, Group::AGG, Group::COUNT, Group::ALT) into the raw aqlCollect() keys. Falls back to the raw Arango::COLLECT spec (or an empty array) when no group is requested.
Parameters
- $init : array<string|int, mixed> = []
-
The list query options.
- $docRef : string = AQL::DOC
-
The document reference grouping fields are read from.
Tags
Return values
array<string|int, mixed> —The raw COLLECT spec (AQL::ASSIGN, AQL::AGGREGATE, AQL::WITH_COUNT).
prepareFilter()
Prepare the AQL query filtering with specific definitions.
public
prepareFilter([array<string|int, mixed>|null $init = [] ][, array<string|int, mixed>|null &$binds = null ][, string $docRef = AQL::DOC ][, array<string|int, mixed> $auth = [] ]) : string|null
Parameters
- $init : array<string|int, mixed>|null = []
- $binds : array<string|int, mixed>|null = null
- $docRef : string = AQL::DOC
- $auth : array<string|int, mixed> = []
Tags
Return values
string|nullprepareGroupSort()
Builds the `SORT` clause applied to a grouped result, from {@see Group::SORT}.
public
prepareGroupSort([array<string|int, mixed> $init = [] ][, array<string|int, mixed>|null $availableVars = null ]) : string|null
The sort operates on group/aggregate variable names (never on doc, which
is out of scope after COLLECT): a CSV with a leading - for descending,
e.g. '-count' → count DESC, 'category,-total' → category ASC, total DESC.
Parameters
- $init : array<string|int, mixed> = []
-
The list query options.
- $availableVars : array<string|int, mixed>|null = null
Return values
string|null —The inner sort expression, or null when none.
prepareQueryFields()
Prepares query fields based on internal definitions and optional skin filter.
public
prepareQueryFields([array<string|int, mixed>|null $fields = null ][, string|null $skin = null ][, string|null $parentKey = null ][, string|array<string|int, mixed>|null $in = null ]) : array<string, array<string|int, mixed>>|null
Converts string filters to array format, applies skins, and normalizes each field.
When $fields is null and the model declares a $skinFields registry, the
projection is resolved per skin first ([$skin] → ['*'] → $fields — the
same order as an edge/join AQL::SKIN_FIELDS).
The skin filter applies at every nesting level : the sub-fields of a WRAP,
DOCUMENT or MAP definition are prepared with the same skin, so a nested
Field::SKINS marker is honored in depth. A structural field whose declared
sub-fields are all removed by the skin — or whose own AQL::SKIN_FIELDS
table resolves to nothing for the requested skin — is dropped from the result.
Parameters
- $fields : array<string|int, mixed>|null = null
-
Optional custom fields to process (defaults to $this->fields).
- $skin : string|null = null
-
Optional skin to filter applicable fields.
- $parentKey : string|null = null
-
Optional parent key definition.
- $in : string|array<string|int, mixed>|null = null
-
Optional field or list of fields to filter the final fields definitions.
Tags
Return values
array<string, array<string|int, mixed>>|null —Normalized fields ready for query, or null if none.
prepareSearch()
Prepare the searchable AQL conditions — the classic `?search=` `LIKE` sweep, a parenthesized `OR` of case-insensitive `LIKE()` predicates over every (permitted) searchable field, used when no View search is active.
public
prepareSearch([array<string|int, mixed>|string|null $search = [] ][, array<string|int, mixed>|null &$binds = null ][, array<string|int, mixed>|null $searchable = null ][, string $docRef = AQL::DOC ]) : string|null
The comma-separated terms and the fields are always OR-ed. How the words
of a single term combine within a field follows the model's
$searchOperator (Search::OPERATOR init key):
- Logic::OR (default) matches the whole term as one substring
(
LIKE(doc.name, "%marc fourcade%")), so it needs the words adjacent and in order — the historical, byte-for-byte grammar; - Logic::AND splits the term on whitespace and requires every word in
the same field (
( LIKE(doc.name, "%marc%") && LIKE(doc.name, "%fourcade%") )), order-independent.
Parameters
- $search : array<string|int, mixed>|string|null = []
- $binds : array<string|int, mixed>|null = null
- $searchable : array<string|int, mixed>|null = null
- $docRef : string = AQL::DOC
Tags
Return values
string|nullprepareSort()
Prepare the AQL `SORT` expression from the `?sort=` grammar and, optionally, the `?near=` anchor.
public
prepareSort([array<string|int, mixed> $init = [] ][, array<string|int, mixed>|null $sortable = null ][, string $docRef = AQL::DOC ][, array<string|int, mixed>|null &$binds = null ]) : string|null
Each comma-separated criterion in Arango::SORT is resolved against $sortable
(URL key → AQL field path); a leading - makes it descending. The synthetic
distance key (Schema::DISTANCE) is resolved from Arango::NEAR and only
honored when $binds is provided (so the reference point can be bound).
Parameters
- $init : array<string|int, mixed> = []
-
Per-call parameters. Reads
Arango::SORT(grammar) andArango::NEAR(geo anchor). - $sortable : array<string|int, mixed>|null = null
-
URL-key → field-path whitelist. Defaults to
$this->sortable. - $docRef : string = AQL::DOC
-
The document variable the fields hang off (default
doc). - $binds : array<string|int, mixed>|null = null
-
Bind variables, populated by reference. Required to enable
distance/?near=sorting.
Tags
Return values
string|null —The SORT body (without the SORT keyword), or an empty string when nothing sorts.
prepareViewSearch()
Prepare the relevance-ranked `SEARCH` expression of an active View search, or `null` when the View search is inactive (no `AQL::VIEW` declaration, no searched fields, or no search term) — the caller then falls back to the classic `LIKE` sweep of {@see prepareSearch()}.
public
prepareViewSearch([array<string|int, mixed>|string|null $search = [] ][, array<string|int, mixed>|null &$binds = null ][, string $docRef = AQL::DOC ]) : string|null
The grammar keeps the ?search= contract (comma-separated terms, OR
everywhere, values bound — never inlined). Per term and per field:
- the base match
doc.<field> IN TOKENS(@search_N, "<analyzer>")(both sides analyzed), weighted byBOOST(…, <boost>)when the field boost differs from1; a field reaching into an array of objects has its[*]expansion marker stripped here (doc.contactPoints.email IN …, notdoc.contactPoints[*].email): theSEARCHgrammar rejects array expansion, and the flat path already matches any element of the indexed array — see buildViewLink(); - with a per-field or View-level Search::PHRASE, an exact-phrase
bonus
BOOST(PHRASE(doc.<field>, @search_N), <boost × 2>); a field may override the View-level flag (an explicitfalseopts that field out); - with a per-field or View-level Search::FUZZY
> 0, a typo-tolerantLEVENSHTEIN_MATCH(doc.<field>, @search_N, <fuzzy>); a field may override the View-level tolerance — an explicit0opts that field out while the rest stays fuzzy.
Field expressions are grouped by their resolved Analyzer (a field may
override the View-level Search::ANALYZER) and each group is wrapped
in its own ANALYZER(…, "<analyzer>"), the groups being OR-ed together.
With a single Analyzer the output is a single ANALYZER(…) wrap, byte for
byte the classic form.
Search::REQUIRES gates the search by the request authorizer
(Arango::AUTHORIZER, see isAuthorized()) at two levels: on the
AQL::VIEW block it gates the whole search, inside a field entry it gates
that field; the two combine with AND (fail-open without an authorizer).
If the View-level gate is denied, or permissions remove every field, the
expression is false — the search matches nothing and never falls back
to searching everything.
When the request carries an active language (Arango::LANG, the ?lang=
parameter), localized fields (those declaring Search::LANG) join
the SEARCH only when their locale matches; locale-agnostic fields always
do. An active language matching no field is ignored — the SEARCH is
never emptied (within the permitted set).
Parameters
- $search : array<string|int, mixed>|string|null = []
-
The
$initarray (readsArango::SEARCH) or the search term itself. - $binds : array<string|int, mixed>|null = null
-
Bind variables, populated by reference.
- $docRef : string = AQL::DOC
-
The document variable the fields hang off.
Tags
Return values
string|null —The SEARCH expression, or null when the View search is inactive.
returnFields()
Generates an AQL document expression or LET statement with the selected fields.
public
returnFields([array<string, mixed> $init = [] ][, array<string|int, mixed> &$variables = [] ][, bool $isVariable = false ]) : string
Supports edges, joins, skins, and query fields.
Parameters
- $init : array<string, mixed> = []
-
Options to customize the query:
- string|array $fields: comma-separated list or array of field names
- ?array $queryFields: prepared query fields (overrides internal $fields)
- ?string $lang: optional language key
- string $docRef: document reference name
- bool $isResult: whether to assign to result variable
- $variables : array<string|int, mixed> = []
- $isVariable : bool = false
-
Whether to generate a LET statement instead of RETURN
Tags
Return values
string —Compiled AQL query fragment
viewDiff()
Compares the model's View declaration with the server state and reports the differences, without touching anything.
public
viewDiff() : DiffReport
On top of the field/analyzer drift detected by ViewManagementTrait::viewDiff(), the model-level report validates the coherence of the declaration itself: a missing Search::NAME, no searched field, no collection, an analyzer or a collection unknown to the server all resolve to DiffStatus::INVALID — such a View is never created nor synchronized automatically.
Tags
Return values
DiffReportviewSync()
Reconciles the model's View with its declaration: creates it when missing, repairs a drift with `updateProperties()` (the View stays available while the inverted index rebuilds in the background), and leaves {@see DiffStatus::IN_SYNC}, {@see DiffStatus::INVALID} or {@see DiffStatus::UNREACHABLE} reports untouched.
public
viewSync() : DiffReport
Tags
Return values
DiffReport —The viewDiff() report, with $applied set when the View has been created or updated.
alterFilterKey()
Apply the key-side (left) `alt` transformation to a key expression.
protected
alterFilterKey(string $key[, array<string|int, mixed> $init = [] ]) : string
Thin wrapper over static::alterExpression(): it resolves the alt
parameter into its key/value sides via static::resolveAltSides() and
applies the key-side chain. The three legacy alt forms (string, list of
functions, function-with-params) keep transforming the key only, unchanged.
Parameters
- $key : string
-
The key expression to transform.
- $init : array<string|int, mixed> = []
-
Filter initialization array containing the 'alt' parameter.
Tags
Return values
string —The transformed key expression.
buildFilteredScope()
Builds the `FOR` segment and the conjunctive `FILTER` clause shared by the list-family queries.
protected
buildFilteredScope([array<string|int, mixed> $init = [] ][, array<string|int, mixed> &$bindVars = [] ]) : array{0: string, 1: ?string}
Parameters
- $init : array<string|int, mixed> = []
-
The query options.
- $bindVars : array<string|int, mixed> = []
-
The bind variables, populated by reference.
Tags
Return values
array{0: string, 1: ?string} —The [ $for, $filter ] pair.
buildViewLink()
Builds the View link of the model's collection from the `AQL::VIEW` declaration: every searched field (dotted paths become nested fields) is indexed with its resolved Analyzer — the per-field {@see Search::ANALYZER} when declared, otherwise the View-level one.
protected
buildViewLink() : ArangoSearchLink
A field may reach a sub-field of an array of objects with the [*]
expansion marker (e.g. contactPoints[*].email). The marker is stripped
here (stripArrayExpansion()) so the link declares the flat nested
path (contactPoints → email): ArangoSearch (Community) descends into
the array on its own — no Enterprise nested flag is needed for this
(non-correlated) search. The matching query strips the marker too — the
SEARCH grammar rejects array expansion, see prepareViewSearch().
The stripped path is validated (assertAttributeName()) to reject a
malformed declaration early.
A field whose resolved Analyzer equals the link-level default is emitted
as an empty node (no analyzers key) rather than spelling the default
out: the server normalizes a field whose analyzers equal the link default
to } (the redundant mention is dropped), so spelling it out would make
the declared form differ forever from the stored one and viewDiff()
would report a permanent false drift. The link carries no link-level
analyzers, so its default is the server default (identity) — computed
here rather than hard-coded so the elimination stays correct if a
link-level analyzer is introduced later.
Tags
Return values
ArangoSearchLinkbuildViewSearchGroups()
Builds the per-Analyzer expression groups of the View search under the historical `OR` grammar : each comma-separated term is bound whole and matched in one shot per field (`doc.<field> IN TOKENS(@search_N, …)`, whose `IN` semantics already `OR` the term's tokens), plus the optional phrase and fuzzy branches. This is the exact grammar emitted when no field opts into {@see Search::OPERATOR} `AND` — see {@see prepareViewSearch()}.
protected
buildViewSearchGroups(string $search, array<string|int, mixed>|null &$binds, string $docRef, array<string|int, mixed> $fields, string $modelAnalyzer, bool $globalPhrase, int $globalFuzzy) : array<string, array<string|int, string>>
Parameters
- $search : string
-
The raw
?search=term string (comma-separated). - $binds : array<string|int, mixed>|null
-
Bind variables, populated by reference.
- $docRef : string
-
The document variable the fields hang off.
- $fields : array<string|int, mixed>
-
The resolved, gated per-field specs.
- $modelAnalyzer : string
-
The View-level Analyzer (a per-field override is respected).
- $globalPhrase : bool
-
The View-level phrase-bonus default.
- $globalFuzzy : int
-
The View-level Levenshtein tolerance default.
Tags
Return values
array<string, array<string|int, string>> —Analyzer name => list of expressions, in first-seen order.
buildViewSearchGroupsWithOperator()
Builds the per-Analyzer expression groups when at least one field opts into {@see Search::OPERATOR} `AND`. Each comma-separated term is split into words (whitespace) ; a field then combines those words with its resolved operator :
protected
buildViewSearchGroupsWithOperator(string $search, array<string|int, mixed>|null &$binds, string $docRef, array<string|int, mixed> $fields, string $modelAnalyzer, bool $globalPhrase, int $globalFuzzy, string $globalOperator[, string|array<string|int, mixed>|null $separators = null ]) : array<string, array<string|int, string>>
OR(default) reproduces the whole-term match (pushWholeTermField()), so a mixed View keeps its loose fields loose ;ANDrequires every word in the same field (( doc.<field> IN TOKENS(@w0, …) && doc.<field> IN TOKENS(@w1, …) )), the fuzzy branch (when enabled) widening each word (( … IN TOKENS(@w, …) || LEVENSHTEIN_MATCH(…, @w, …) )), and the phrase bonus (when enabled) kept on the whole term as a ranking boostOR-ed on top — an adjacency match implies the words, so the matched set is unchanged.
The whole-term bind is materialized only when a field needs it (an OR
field, or an AND field carrying the phrase bonus), never left dangling.
Groups are OR-ed between fields and between terms by prepareViewSearch().
Parameters
- $search : string
-
The raw
?search=term string (comma-separated). - $binds : array<string|int, mixed>|null
-
Bind variables, populated by reference.
- $docRef : string
-
The document variable the fields hang off.
- $fields : array<string|int, mixed>
-
The resolved, gated per-field specs.
- $modelAnalyzer : string
-
The View-level Analyzer (a per-field override is respected).
- $globalPhrase : bool
-
The View-level phrase-bonus default.
- $globalFuzzy : int
-
The View-level Levenshtein tolerance default.
- $globalOperator : string
-
The View-level operator default (Logic::AND / Logic::OR).
- $separators : string|array<string|int, mixed>|null = null
-
The extra AND word separators (Search::SEPARATORS); null = the hyphen default.
Tags
Return values
array<string, array<string|int, string>> —Analyzer name => list of expressions, in first-seen order.
getSearchableSpecs()
Normalizes the model's `AQL::SEARCHABLE` list into a per-field specification map `field => [ (Search::REQUIRES => …)? ]`, the single source consumed by {@see prepareSearch()} (the `LIKE` sweep) and by the `searchable` fallback of {@see getViewFieldSpecs()}.
protected
getSearchableSpecs([array<string|int, mixed>|null $searchable = null ]) : array<string, array<string, mixed>>
Each entry of the list is either:
- a plain field name (string) → a public field, no options;
- an array carrying the field name under Search::KEY plus its
options (e.g. Search::REQUIRES) → keeps the list homogeneous
(no mixed numeric/string keys). The map form
field => [ … ]is also tolerated (the field falls back to the entry key).
Parameters
- $searchable : array<string|int, mixed>|null = null
-
An explicit list overriding the model's
searchableproperty.
Return values
array<string, array<string, mixed>>getViewFieldSpecs()
Normalizes the searched fields of the `AQL::VIEW` declaration into a per-field specification map `field => [ Search::BOOST => float, … ]` — the single source of truth from which {@see getViewSearchFields()} derives the boost map and {@see prepareViewSearch()} resolves the per-field options.
protected
getViewFieldSpecs() : array<string, array<string, mixed>>
Search::FIELDS entries accept a numeric boost shorthand or an
array carrying Search::BOOST, Search::FUZZY,
Search::ANALYZER, Search::LANG, Search::PHRASE and
Search::REQUIRES;
when the declaration has no fields, the model's searchable list is used with a
neutral boost. A per-field option is kept in the spec only when it is
explicitly declared — an absent key means "inherit the View-level
default", which prepareViewSearch() resolves so that an explicit
value (0 included) overrides the global tolerance.
Tags
Return values
array<string, array<string, mixed>>getViewSearchFields()
Normalizes the searched fields into a `field => boost` map — a boost-only façade over {@see getViewFieldSpecs()}, used by {@see buildViewLink()} and {@see viewDiff()} which only care about the field paths and their weights.
protected
getViewSearchFields() : array<string, float>
Tags
Return values
array<string, float>ngramMatch()
Builds the `NGRAM_MATCH(doc.<field>, @term [, threshold], "<analyzer>")` core of a {@see Search::NGRAM} branch (without the surrounding boost). The threshold is inlined only when the field declares one, else the server default applies. Shared by the whole-term and the per-word emissions.
protected
ngramMatch(array<string|int, mixed> $spec, string $path, string $term) : string
Parameters
- $spec : array<string|int, mixed>
-
The field spec (must carry a Search::NGRAM entry).
- $path : string
-
The
doc.<field>accessor. - $term : string
-
The bound term (
@search_Nor@search_N_M).
Return values
string —The NGRAM_MATCH(…) expression.
prepareFacets()
Prepare the query with AQL facets definitions.
protected
prepareFacets(array<string|int, mixed>|null $init[, array<string|int, mixed>|null &$binds = null ][, string $docRef = AQL::DOC ][, string $logicalOperator = Logic::AND ]) : string|null
Parameters
- $init : array<string|int, mixed>|null
- $binds : array<string|int, mixed>|null = null
- $docRef : string = AQL::DOC
- $logicalOperator : string = Logic::AND
Return values
string|nullprepareFilterBetween()
Prepares an inclusive `between` (range) clause: `key >= @min && key <= @max`.
protected
prepareFilterBetween(array<string|int, mixed> $init, array<string|int, mixed>|null &$binds, string $docRef, callable $resolve, bool $defaultBounds) : string
The compared key is alt-aware (it flows through static::alterFilterKey()).
Each bound is resolved by $resolve, which differs per filter type — a raw
bind for numbers/strings, the date machinery (now / timezone) for dates.
Bound omission is type-driven:
$defaultBounds = false(number/string): an omitted bound drops its side, yielding a one-sided range (key >= @minorkey <= @max).$defaultBounds = true(date): an omitted bound still emits a clause; the resolver maps the null value to "now", so the range is always two-sided.
Parameters
- $init : array<string|int, mixed>
-
The filter init (reads
min/max). - $binds : array<string|int, mixed>|null
-
The bind variables, populated by reference.
- $docRef : string
-
The document reference.
- $resolve : callable
-
fn(mixed $value, ?array &$binds): string — resolves a bound to AQL.
- $defaultBounds : bool
-
Whether an omitted bound still emits a clause (dates) or is dropped.
Tags
Return values
stringprepareFilterComparator()
Prepares the filter clause with a specific operator.
protected
prepareFilterComparator([array<string|int, mixed> $init = [] ]) : string
Parameters
- $init : array<string|int, mixed> = []
Return values
stringprepareFilterKey()
Prepares the filter clause with a specific key and document, with optional function transformations via 'alt' parameter.
protected
prepareFilterKey([string|array<string|int, mixed>|null $init = [] ][, string $docRef = AQL::DOC ]) : string
Supports function chaining:
- Single function: "alt":"lower"
- Multiple functions: "alt":["trim","lower"]
- Functions with params: "alt":[["trim",1],"lower"]
Parameters
- $init : string|array<string|int, mixed>|null = []
-
Filter initialization array
- $docRef : string = AQL::DOC
-
Document reference (default: AQL::DOC)
Tags
Return values
string —The transformed key expression
prepareFilterValue()
Prepare the filter clause with a specific value to evaluates.
protected
prepareFilterValue([array<string|int, mixed>|null $init = [] ][, array<string|int, mixed>|null &$binds = null ]) : string
Binds the raw value, then applies the value-side (right) alt chain when
one is set (object form alt:{ key:.. , val:.. } or val:true mirror):
- scalar value → the chain wraps the bind placeholder, e.g.
LOWER(@value). - array value (e.g.
op:in) → the chain is mapped over each element via an inline projection, e.g.@value[* RETURN LOWER(CURRENT)]. The single bind still holds the whole array, so existing binding behavior is preserved.
Parameters
- $init : array<string|int, mixed>|null = []
- $binds : array<string|int, mixed>|null = null
Tags
Return values
stringprepareNear()
Build the `DISTANCE(...)` expression for a `?near=` anchor and bind its coordinates.
protected
prepareNear(array<string|int, mixed> $near, array<string|int, mixed>|null &$binds[, string $docRef = AQL::DOC ][, array<string|int, mixed> $init = [] ]) : string|null
The key of the payload names the geo field to order by distance from, so it is a
sort dimension and travels through the same fail-closed gate as any sort key: it
must be declared in $this->sortable (URL key → geo field path) and it inherits (or
declares) a Field::REQUIRES permission — a geo field hidden from the projection
stays untriable (no distance oracle). Returns null when the key is missing, is not
whitelisted, is refused by permission, or the coordinates are incomplete.
Parameters
- $near : array<string|int, mixed>
-
The
?near=payload ({ key, latitude, longitude }), already array-checked by the caller. - $binds : array<string|int, mixed>|null
-
Bind variables, populated by reference.
- $docRef : string = AQL::DOC
-
The document variable the fields hang off.
- $init : array<string|int, mixed> = []
-
The request-level init. Reads
Arango::AUTHORIZER.
Tags
Return values
string|null —DISTANCE(doc.<field>.latitude, doc.<field>.longitude, @lat, @lng) or null.
pushWholeTermField()
Pushes the whole-term match of one field onto the Analyzer groups — the base `doc.<field> IN TOKENS(@term, …)` (boosted when the field weight is not `1`), the optional exact-phrase bonus and the optional fuzzy branch, plus the {@see Search::NGRAM} branch when declared. This is the `OR`-grammar emission, shared by {@see buildViewSearchGroups()} (every field) and by the `OR` fields of {@see buildViewSearchGroupsWithOperator()}.
protected
pushWholeTermField(array<string|int, mixed> &$groups, array<string|int, mixed> $spec, string $path, string $term, array<string|int, mixed> $analyzers, float $weight, bool $phrase, int $fuzzy) : void
Parameters
- $groups : array<string|int, mixed>
-
Analyzer name => list of expressions, mutated by reference.
- $spec : array<string|int, mixed>
-
The resolved field spec.
- $path : string
-
The
doc.<field>accessor. - $term : string
-
The bound whole term (
@search_N). - $analyzers : array<string|int, mixed>
-
The Analyzers indexing the field (
IN TOKENSside). - $weight : float
-
The field boost.
- $phrase : bool
-
Whether to add the exact-phrase bonus.
- $fuzzy : int
-
The Levenshtein tolerance (
0disables the branch).
resolveFieldSearchSpec()
Resolves the per-field search facets shared by both group builders : the Analyzers indexing the field (a per-field {@see Search::ANALYZER} overrides the View-level one, a single Analyzer normalized to a one-element list), the boost, the fuzzy tolerance and phrase bonus (a per-field value overrides the View-level default), and the `doc.<field>` accessor (with the `[*]` array marker stripped — the flat path already matches any element of the indexed array, and the `SEARCH` grammar rejects the expansion form).
protected
resolveFieldSearchSpec(array<string|int, mixed> $spec, int|string $field, string $modelAnalyzer, bool $globalPhrase, int $globalFuzzy, string $docRef) : array{0: string[], 1: float, 2: int, 3: bool, 4: string}
Parameters
- $spec : array<string|int, mixed>
-
The resolved field spec.
- $field : int|string
-
The field key (the dotted path,
[*]allowed). - $modelAnalyzer : string
-
The View-level Analyzer.
- $globalPhrase : bool
-
The View-level phrase-bonus default.
- $globalFuzzy : int
-
The View-level Levenshtein tolerance default.
- $docRef : string
-
The document variable the field hangs off.
Return values
array{0: string[], 1: float, 2: int, 3: bool, 4: string} —[ analyzers, weight, fuzzy, phrase, path ].
splitSearchTermWords()
Splits an `AND`-operator search term into its words, on whitespace plus the given extra separator characters ({@see Search::SEPARATORS}). Whitespace always splits; `$separators` adds literal characters (a string, or a list of characters joined to one), `null` falls back to the hyphen default, and an empty value splits on whitespace only. The extra characters are regex-escaped, so any punctuation is safe. Empty words are dropped.
protected
splitSearchTermWords(string $term[, string|array<string|int, mixed>|null $separators = null ]) : array<string|int, string>
Parameters
- $term : string
-
The raw comma-term (may hold several words).
- $separators : string|array<string|int, mixed>|null = null
-
The extra separator characters (string / list / null=default hyphen).
Return values
array<string|int, string> —The non-empty words, in order.
authorizeSortKey()
Resolve a whitelisted sort entry to its AQL field expression, gated by permission.
private
authorizeSortKey(string $key, mixed $entry, array<string|int, mixed> $init, string $docRef) : string|null
The entry (the $sortable[$key] value) is either a plain field path — a string
or an array path ([ 'address', 'city' ]) — or an explicit definition (an
associative array carrying Field::PATH and/or Field::REQUIRES). The permission
subject is resolved in two steps, aligned on the projection's Field::REQUIRES:
- explicit — a
Field::REQUIRESdeclared on the entry itself takes priority; - inherited — otherwise the subject of the homonymous field declared in
$this->fieldsis reused, so « what you cannot read, you cannot sort on ».
When a subject is resolved and isAuthorized() denies it, the key is refused
(null) and the caller drops the criterion — a field hidden from the projection
stays untriable (no sort oracle). No subject, or no authorizer injected, sorts
freely (fail-open — exactly the field-level semantics).
Parameters
- $key : string
-
The public URL key (already resolved against the whitelist).
- $entry : mixed
-
The
$sortable[$key]value (path or explicit definition). - $init : array<string|int, mixed>
-
The request-level init. Reads
Arango::AUTHORIZER. - $docRef : string
-
The document variable the field hangs off.
Return values
string|null —The doc.<field> expression, or null when the sort is refused.
collectAggregate()
Builds the `AQL::AGGREGATE` map from {@see Group::AGG}.
private
collectAggregate(array<string|int, mixed> $group, string $docRef[, array<string|int, mixed> $init = [] ]) : array<string|int, mixed>
Parameters
- $group : array<string|int, mixed>
-
The group spec.
- $docRef : string
-
The document reference.
- $init : array<string|int, mixed> = []
Tags
Return values
array<string|int, mixed> —[ outName => 'FN(doc.field)' ].
collectAssign()
Builds the `AQL::ASSIGN` map from {@see Group::BY} and {@see Group::ALT}.
private
collectAssign(array<string|int, mixed> $group, string $docRef[, array<string|int, mixed> $init = [] ]) : array<string|int, mixed>
Parameters
- $group : array<string|int, mixed>
-
The group spec.
- $docRef : string
-
The document reference.
- $init : array<string|int, mixed> = []
Tags
Return values
array<string|int, mixed> —[ varName => 'doc.field' | 'FN(doc.field)' ].
collectMatchFields()
Collects the field names referenced by a `match` payload, for the permission gate. Mirrors the shape read by {@see \oihana\arango\db\helpers\buildCombinedInlineFilter()}: the explicit `all` / `any` / `none` lists expose their field under `key`, while the simple object form (`{ propertyID: …, value: … }`) uses its keys directly.
private
collectMatchFields(array<string|int, mixed> $match) : array<int, string>
Parameters
- $match : array<string|int, mixed>
-
The
matchpayload (already validated as an array by the caller).
Return values
array<int, string> —The referenced sub-field names (possibly empty).
filterFieldsBySkin()
Filters fields based on an optional skin.
private
filterFieldsBySkin(array<string, mixed> $fields, string|null $skin) : array<string, mixed>
Parameters
- $fields : array<string, mixed>
-
Fields to filter
- $skin : string|null
-
Skin to match
Return values
array<string, mixed> —Filtered fields
generateUniqueKey()
Generates a unique key for special filters like edges, joins, or unique names.
private
generateUniqueKey(string $key, string|null $filter[, string|null $parentKey = null ]) : string|null
Parameters
- $key : string
-
Base field key
- $filter : string|null
-
Filter type
- $parentKey : string|null = null
-
Optional parent key.
Return values
string|null —Generated unique key or existing
isSortAuthorized()
Decide whether a sort/near field is granted for the request.
private
isSortAuthorized(string $path, mixed $requires, array<string|int, mixed> $init) : bool
Two paths, mirroring the projection's own gating:
- explicit (Façon A) — an entry that declared its own
Field::REQUIRESis run through isAuthorized(); - inherited (Façon B) — otherwise the
Field::REQUIRESis inherited from the projection at the resolved$pathvia isPathAuthorized(), which descendsField::FIELDS/AQL::SKIN_FIELDSand strips[*], so a dotted/aliased path (address.salary) is gated at its exact sub-field — never at the homonym of the URL key.
Both fail open: no explicit subject with a projection that carries no
Field::REQUIRES on the path (or no authorizer injected) sorts freely —
exactly the field-level semantics, symmetric with ?filter=.
Parameters
- $path : string
-
The resolved field path (
address.salary,location.point, …). - $requires : mixed
-
The explicit
Field::REQUIRESsubject(s) declared on the entry, ornull. - $init : array<string|int, mixed>
-
The request-level init. Reads
Arango::AUTHORIZER.
Return values
bool —true when the field may be sorted on, false when refused.
normalizeAggregate()
Normalizes an aggregate definition into a `[ code, field ]` pair.
private
normalizeAggregate(mixed $definition) : array{0: ?string, 1: ?string}
Accepts 'sum:amount' (string) or ['sum','amount'] (list).
Parameters
- $definition : mixed
Return values
array{0: ?string, 1: ?string}normalizeFieldDefinition()
Normalize a field definition into a structured array for queries.
private
normalizeFieldDefinition(string $key[, array<string|int, mixed> $options = [] ][, string|null $parentKey = null ][, string|null $skin = null ]) : array<string, mixed>|null
- Converts string filters to array
- Handles subfields for DOCUMENT or MAP filters
- Generates unique keys for special filters
The sub-fields of a structural filter (WRAP, DOCUMENT, MAP) are prepared
recursively with the SAME skin, so a Field::SKINS marker on a nested
sub-field is honored at every depth — with the level-one rules: a sub-field
without a marker is always kept, and a null skin keeps everything.
When the skin filters out ALL the declared sub-fields, the method returns
null and the field itself is dropped from the projection (key absent).
A structural field can also declare per-skin alternative sub-projections
through AQL::SKIN_FIELDS (same table shape and resolution order as an
edge/join definition). A declared table that resolves to nothing for the
requested skin drops the field the same way (returns null).
Parameters
- $key : string
-
Field name
- $options : array<string|int, mixed> = []
-
Field options, may include:
- Field::FILTER
- Field::NAME
- Field::QUOTED
- Field::FIELDS (for DOCUMENT or MAP)
- $parentKey : string|null = null
-
The Optional parent key
- $skin : string|null = null
-
Optional skin propagated to the nested sub-fields.
Tags
Return values
array<string, mixed>|null —Normalized field definition, or null when the
skin removed every declared sub-field.
normalizeGroupFields()
Normalizes {@see Group::BY} into a `[ varName => field ]` map.
private
normalizeGroupFields(mixed $by) : array<string, string>
- CSV string
'category,status'→[ 'category' => 'category', 'status' => 'status' ]. - list
['category','status']→ same. - assoc
['year' => 'created']→ kept as-is.
Dotted fields yield underscore variable names (address.city → address_city).
Parameters
- $by : mixed
Return values
array<string, string>resolveSortEntry()
Resolve a whitelisted sort entry to its `[ fieldPath, requires ]` pair.
private
resolveSortEntry(string $key, mixed $entry) : array{0: mixed, 1: mixed}
The entry (the $sortable[$key] value) is either a plain field path — a string
or an array path ([ 'address', 'city' ]) — or an explicit definition (an
associative array carrying Field::PATH and/or Field::REQUIRES). Only the
explicit Field::REQUIRES (Façon A) is returned here; the inherited
permission (Façon B) is decided by isSortAuthorized() against the
resolved $path — never against the URL key — so a dotted/aliased path
(salary → address.salary) is gated at its exact (sub-)field, symmetric
with groupBy/bounds and free of the "wrong homonym" pitfall.
Shared by the textual ?sort= grammar and the ?near= distance anchor, so both
resolve a geo/scalar field the same way.
Parameters
- $key : string
-
The public URL key (already resolved against the whitelist).
- $entry : mixed
-
The
$sortable[$key]value (path or explicit definition).
Return values
array{0: mixed, 1: mixed} —The [ fieldPath, requires ] pair (requires is the
explicit subject, or null when the entry declares none).