HasMany
extends AbstractRelationship
in package
Relationship class for "has many" relationships
Tags
Table of Contents
Constants
- COMPOSITE_KEY_DELIMITER = "\x1f"
- Delimiter used to join multiple column values into one composite lookup key
Properties
- $children : array<string|int, mixed>
- Relationship children (list of dotted child paths to eager-load under this relationship)
- $foreignKey : string|array<string|int, mixed>|null
- Foreign key
- $foreignTable : string|null
- Foreign table class
- $options : array<string|int, mixed>|null
- Relationship options
- $parent : Record|null
- Parent record
Methods
- __construct() : mixed
- Constructor
- buildCompositeKey() : string
- Build a single composite lookup key from an ordered list of column values
- getChildRelationships() : array<string|int, mixed>
- Get child relationships
- getChildren() : Collection
- Get children
- getEagerRelationships() : array<string|int, mixed>
- Get eager relationships
- getEmptyRelationshipValue() : mixed
- Get the value to use when no eager-loaded result exists for a given leaf record
- getForeignKey() : string|array<string|int, mixed>|null
- Get foreign key
- getForeignTable() : string|null
- Get foreign table class
- getOptions() : array<string|int, mixed>|null
- Get options
- getParent() : Record|null
- Get parent record
- setChildRelationships() : static
- Set children child relationships
- tupleFor() : array<string|int, mixed>|null
- Build an ordered tuple of values for the given columns from a record (either a Record instance or a plain array row). Returns null if any one of the columns is missing or null, i.e. the record has no usable composite key and should be skipped.
- applyEagerIdFilter() : void
- Apply the eager-load id filter to a SELECT's WHERE clause and collect its bound values.
- assertKeyCardinality() : void
- Validate that an array foreign-key column count matches the target table's own primary-key column count. A plain string $foreignKey is always treated as cardinality 1.
- assertTupleCardinality() : void
- Validate that the tuples in an eager-load id list have the same number of components as the array foreign key they will be bound to. A plain string $foreignKey (cardinality 1) and an empty $ids list are always valid.
- bindPlaceholder() : string
- Bind a single value as a query parameter and return the placeholder token that must be rendered in its place.
- bindPlaceholders() : array<string|int, mixed>
- Bind a flat list of values for a single column and return their placeholder tokens
- hydrateChildRelationships() : void
- Hydrate nested child relationships onto a flat list of leaf records, resolving each named child relationship once (accumulated by name) and distributing every one of them onto every leaf record — so multiple differently-named children under this relationship don't overwrite each other.
- applyAdditionalColumnsFilter() : void
- Apply the options['columns'] additional WHERE filter (if any) and collect its bound values
- applyQueryOptions() : void
- Apply the limit, offset, join, and order options (if any)
- hydrateRows() : array<string|int, mixed>
- Hydrate the fetched rows into a per-parent-key map of Collections (or raw arrays), and eager-load any nested child relationships on the resulting leaf records
Constants
COMPOSITE_KEY_DELIMITER
Delimiter used to join multiple column values into one composite lookup key
public
string
COMPOSITE_KEY_DELIMITER
= "\x1f"
Properties
$children
Relationship children (list of dotted child paths to eager-load under this relationship)
protected
array<string|int, mixed>
$children
= []
$foreignKey
Foreign key
protected
string|array<string|int, mixed>|null
$foreignKey
= null
$foreignTable
Foreign table class
protected
string|null
$foreignTable
= null
$options
Relationship options
protected
array<string|int, mixed>|null
$options
= null
$parent
Parent record
protected
Record|null
$parent
= null
Methods
__construct()
Constructor
public
__construct(Record $parent, string $foreignTable, string|array<string|int, mixed> $foreignKey[, array<string|int, mixed>|null $options = null ]) : mixed
Instantiate the relationship object
Parameters
- $parent : Record
- $foreignTable : string
- $foreignKey : string|array<string|int, mixed>
- $options : array<string|int, mixed>|null = null
buildCompositeKey()
Build a single composite lookup key from an ordered list of column values
public
static buildCompositeKey(array<string|int, mixed> $values) : string
Parameters
- $values : array<string|int, mixed>
Return values
stringgetChildRelationships()
Get child relationships
public
getChildRelationships() : array<string|int, mixed>
Return values
array<string|int, mixed>getChildren()
Get children
public
getChildren([array<string|int, mixed>|null $options = null ]) : Collection
Parameters
- $options : array<string|int, mixed>|null = null
Return values
CollectiongetEagerRelationships()
Get eager relationships
public
getEagerRelationships(array<string|int, mixed> $ids[, bool $toArray = false ]) : array<string|int, mixed>
Parameters
- $ids : array<string|int, mixed>
- $toArray : bool = false
Tags
Return values
array<string|int, mixed>getEmptyRelationshipValue()
Get the value to use when no eager-loaded result exists for a given leaf record
public
getEmptyRelationshipValue() : mixed
getForeignKey()
Get foreign key
public
getForeignKey() : string|array<string|int, mixed>|null
Return values
string|array<string|int, mixed>|nullgetForeignTable()
Get foreign table class
public
getForeignTable() : string|null
Return values
string|nullgetOptions()
Get options
public
getOptions() : array<string|int, mixed>|null
Return values
array<string|int, mixed>|nullgetParent()
Get parent record
public
getParent() : Record|null
Return values
Record|nullsetChildRelationships()
Set children child relationships
public
setChildRelationships(array<string|int, mixed> $children) : static
Parameters
- $children : array<string|int, mixed>
Return values
statictupleFor()
Build an ordered tuple of values for the given columns from a record (either a Record instance or a plain array row). Returns null if any one of the columns is missing or null, i.e. the record has no usable composite key and should be skipped.
public
static tupleFor(mixed $record, array<string|int, mixed> $columns) : array<string|int, mixed>|null
Parameters
- $record : mixed
- $columns : array<string|int, mixed>
Return values
array<string|int, mixed>|nullapplyEagerIdFilter()
Apply the eager-load id filter to a SELECT's WHERE clause and collect its bound values.
protected
applyEagerIdFilter(Sql $sql, string|array<string|int, mixed> $key, array<string|int, mixed> $ids, array<string|int, mixed> &$params) : void
A single-column key renders as one "column IN (...)" predicate. A composite key renders as one AND-nested group of per-tuple OR-nested equality groups, so that whatever gets appended to the WHERE clause afterward is ANDed against the whole "matches any of these id tuples" block rather than becoming a sibling OR at the top level. It renders identically when there is no sibling predicate.
Parameters
- $sql : Sql
- $key : string|array<string|int, mixed>
- $ids : array<string|int, mixed>
- $params : array<string|int, mixed>
assertKeyCardinality()
Validate that an array foreign-key column count matches the target table's own primary-key column count. A plain string $foreignKey is always treated as cardinality 1.
protected
assertKeyCardinality(string|array<string|int, mixed> $foreignKey, array<string|int, mixed> $targetPrimaryKeys) : void
Parameters
- $foreignKey : string|array<string|int, mixed>
- $targetPrimaryKeys : array<string|int, mixed>
Tags
assertTupleCardinality()
Validate that the tuples in an eager-load id list have the same number of components as the array foreign key they will be bound to. A plain string $foreignKey (cardinality 1) and an empty $ids list are always valid.
protected
assertTupleCardinality(array<string|int, mixed> $ids, string|array<string|int, mixed> $foreignKey) : void
Parameters
- $ids : array<string|int, mixed>
- $foreignKey : string|array<string|int, mixed>
Tags
bindPlaceholder()
Bind a single value as a query parameter and return the placeholder token that must be rendered in its place.
protected
static bindPlaceholder(Sql $sql, string $column, mixed $value, array<string|int, mixed> &$params) : string
A bare placeholder character is NOT a usable placeholder on every dialect: only MySQL/SQL Server take a bare '?'. PostgreSQL needs a positional '$N' and SQLite/PDO need a named ':name', so the token has to be generated here rather than repeating whatever Sql::getPlaceholder() returns. The Sql object's own parameter counter is used to number (PostgreSQL) and to uniquely name (SQLite/PDO) every parameter in the statement, so callers can bind several groups of parameters into one query without colliding.
The generated names deliberately start with the counter, i.e. with a digit, which is exactly what keeps them from ever colliding with the column-derived names that Sql\Parser\Expression::parseShorthand() emits for the same statement.
Parameters
- $sql : Sql
- $column : string
- $value : mixed
- $params : array<string|int, mixed>
Return values
stringbindPlaceholders()
Bind a flat list of values for a single column and return their placeholder tokens
protected
static bindPlaceholders(Sql $sql, string $column, array<string|int, mixed> $values, array<string|int, mixed> &$params) : array<string|int, mixed>
Parameters
- $sql : Sql
- $column : string
- $values : array<string|int, mixed>
- $params : array<string|int, mixed>
Return values
array<string|int, mixed>hydrateChildRelationships()
Hydrate nested child relationships onto a flat list of leaf records, resolving each named child relationship once (accumulated by name) and distributing every one of them onto every leaf record — so multiple differently-named children under this relationship don't overwrite each other.
protected
hydrateChildRelationships(array<string|int, mixed> $leafRecords, string|array<string|int, mixed> $primaryKeyColumn) : void
The column used to query and match a given child relationship is decided per relationship name, not once for all of them: "to-one by foreign key" children (HasOneOf and BelongsTo) are keyed by the leaf record's own foreign key column — the column holding the value that identifies which foreign row to fetch — while every other kind is keyed by the leaf record's primary key.
Parameters
- $leafRecords : array<string|int, mixed>
- $primaryKeyColumn : string|array<string|int, mixed>
applyAdditionalColumnsFilter()
Apply the options['columns'] additional WHERE filter (if any) and collect its bound values
private
applyAdditionalColumnsFilter(Sql $sql, array<string|int, mixed> &$params) : void
The parsed expressions carry their own dialect-correct placeholder tokens, so the SQL object's parameter counter is advanced by one per bound value to keep any placeholder generated afterward for the same statement in step with them.
Parameters
- $sql : Sql
- $params : array<string|int, mixed>
applyQueryOptions()
Apply the limit, offset, join, and order options (if any)
private
applyQueryOptions(Sql $sql, AbstractAdapter $db) : void
Parameters
- $sql : Sql
- $db : AbstractAdapter
hydrateRows()
Hydrate the fetched rows into a per-parent-key map of Collections (or raw arrays), and eager-load any nested child relationships on the resulting leaf records
private
hydrateRows(array<string|int, mixed> $rows, string $table, bool|array<string|int, mixed> $toArray) : array<string|int, mixed>
Parameters
- $rows : array<string|int, mixed>
- $table : string
- $toArray : bool|array<string|int, mixed>