Skip to content

Relationship

Adds relationship-aware assignment, persistence, and export helpers.

PhalconKit models call assignRelated() before native model assignment so request payloads can contain nested relationship data. The default behavior remains permissive for backward compatibility: unknown relation-looking payloads and non-whitelisted aliases are ignored so scalar model assignment can continue through Phalcon. Applications that validate request payloads more tightly can enable strict relationship assignment per model instance.


  • Full name: \PhalconKit\Mvc\Model\Traits\Relationship

Constants

Constant Visibility Type Value
DEFAULT_RELATIONSHIP_OPTIONS private array ['enforceDirectOwnership' => false, 'allowUnownedDirectRelationAdoption' => true, 'autoRestoreDirectRelations' => false]

Properties

keepMissingRelated

private array $keepMissingRelated

strictRelatedAssignment

Whether relation-specific assignment mistakes should throw exceptions.

private bool $strictRelatedAssignment

This flag does not make normal scalar model assignment strict. It only affects payloads that are clearly intended for relationship handling, such as known relation aliases, complex nested values, and relation list items.


relationshipContext

private string $relationshipContext

dirtyRelated

protected \Phalcon\Mvc\ModelInterface[] $dirtyRelated

loadedRelated

Eager-loaded relationship values that should be readable/exportable without being treated as pending related records to save.

protected array<string,mixed> $loadedRelated

Methods

appendMessage

public appendMessage(\Phalcon\Messages\MessageInterface $message): \Phalcon\Mvc\ModelInterface
  • This method is abstract. Parameters:
Parameter Type Description
$message \Phalcon\Messages\MessageInterface

setStrictRelatedAssignment

Enable or disable strict validation for relationship payloads.

public setStrictRelatedAssignment(bool $strictRelatedAssignment): void

Leave this disabled for legacy forms that may send extra nested data. Enable it in API/resource layers where relation aliases are controlled by explicit save-field policies and a malformed relation should fail loudly.

Parameters:

Parameter Type Description
$strictRelatedAssignment bool

isStrictRelatedAssignment

Return whether malformed relationship payloads should throw exceptions.

public isStrictRelatedAssignment(): bool

setRelationshipOptions

Replace the configured relationship behavior options.

public setRelationshipOptions(array $options): void

The option group is intentionally stored in the shared model options manager so applications can opt into stricter behavior per model without changing generated relationship declarations.

Parameters:

Parameter Type Description
$options array

getRelationshipOptions

Return relationship options, optionally including a per-alias override.

public getRelationshipOptions(?string $alias = null): array

Parameters:

Parameter Type Description
$alias ?string

getConfiguredRelationshipOptions

Read relationship defaults from bootstrap config when available.

private getConfiguredRelationshipOptions(): array<string,mixed>

The config path is intentionally feature-specific (model.relationship) rather than part of the generic model options manager.


getRelationshipOption

Return one configured relationship behavior option.

public getRelationshipOption(string $option, ?string $alias = null, mixed $default = null): mixed

Parameters:

Parameter Type Description
$option string
$alias ?string
$default mixed

getRelationshipAliasOptions

private getRelationshipAliasOptions(array $configured, string $alias): array

Parameters:

Parameter Type Description
$configured array
$alias string

setKeepMissingRelated

Set the missing related configuration list

public setKeepMissingRelated(array $keepMissingRelated): void

Parameters:

Parameter Type Description
$keepMissingRelated array

getKeepMissingRelated

Return the missing related configuration list

public getKeepMissingRelated(): array<string,bool>

getKeepMissingRelatedAlias

Return the keepMissing configuration for a specific relationship alias

public getKeepMissingRelatedAlias(string $alias): bool

Parameters:

Parameter Type Description
$alias string

setKeepMissingRelatedAlias

Set the keepMissing configuration for a specific relationship alias

public setKeepMissingRelatedAlias(string $alias, bool $keepMissing): void

Parameters:

Parameter Type Description
$alias string
$keepMissing bool

getRelationshipContext

Get the current relationship context

public getRelationshipContext(): string

setRelationshipContext

Set the current relationship context

public setRelationshipContext(string $context): void

Parameters:

Parameter Type Description
$context string

getDirtyRelated

Return the dirtyRelated entities

public getDirtyRelated(): array<string,mixed>

setDirtyRelated

Set the dirtyRelated entities

public setDirtyRelated(array $dirtyRelated): void

Parameters:

Parameter Type Description
$dirtyRelated array

getDirtyRelatedAlias

Return the dirtyRelated entities

public getDirtyRelatedAlias(string $alias): mixed

Parameters:

Parameter Type Description
$alias string

setDirtyRelatedAlias

Return the dirtyRelated entities

public setDirtyRelatedAlias(string $alias, mixed $value): void

Parameters:

Parameter Type Description
$alias string
$value mixed

hasDirtyRelated

Check whether the current entity has dirty related or not

public hasDirtyRelated(): bool

hasDirtyRelatedAlias

Check whether the current entity has dirty related or not

public hasDirtyRelatedAlias(string $alias): bool

Parameters:

Parameter Type Description
$alias string

getLoadedRelated

Return the eager-loaded related entities

public getLoadedRelated(): array<string,mixed>

setLoadedRelated

Set the eager-loaded related entities

public setLoadedRelated(array $loadedRelated): void

Parameters:

Parameter Type Description
$loadedRelated array

getLoadedRelatedAlias

Return eager-loaded related entities for one alias

public getLoadedRelatedAlias(string $alias): mixed

Parameters:

Parameter Type Description
$alias string

setLoadedRelatedAlias

Set eager-loaded related entities for one alias

public setLoadedRelatedAlias(string $alias, mixed $value): void

Parameters:

Parameter Type Description
$alias string
$value mixed

hasLoadedRelatedAlias

Check whether an eager-loaded relation alias exists

public hasLoadedRelatedAlias(string $alias): bool

Parameters:

Parameter Type Description
$alias string

setRelated

Store a related value in both Phalcon's native relation cache and PhalconKit's read-only eager-loading cache.

public setRelated(string $alias, mixed $records): \Phalcon\Mvc\ModelInterface

Phalcon 5.18's native eager loader calls this method while hydrating find(['eager' => [...]]) results. Mirroring the value keeps direct property access, getRelated(), exports, and native isRelationshipLoaded() checks consistent without marking the relation for persistence.

Parameters:

Parameter Type Description
$alias string Registered relationship alias.
$records mixed Related model, row, resultset, or null.

Return Value:

The current model instance.


normalizeRelationAlias

private normalizeRelationAlias(string $alias): string

Parameters:

Parameter Type Description
$alias string

normalizeRelationAliases

private normalizeRelationAliases(array $related): array

Parameters:

Parameter Type Description
$related array

writeDeclaredRelatedAlias

private writeDeclaredRelatedAlias(string $alias, mixed $value): void

Parameters:

Parameter Type Description
$alias string
$value mixed

assign

Assigns values to the model from an array, with options to control which fields are assigned.

public assign(array $data, array|null $whiteList = null, array|null $dataColumnMap = null): \Phalcon\Mvc\ModelInterface

Handles related records using assignRelated method and passes remaining values to the parent's assign method.

Parameters:

Parameter Type Description
$data array The array of data to assign to the model.
$whiteList array|null An optional array specifying which fields in the model can be assigned.
$dataColumnMap array|null An optional column map to transform external keys into internal model field names.

Return Value:

Returns the updated ModelInterface instance.

Throws:


assignRelated

Assign related

public assignRelated(array $data, array|null $whiteList = null, array|null $dataColumnMap = null): \Phalcon\Mvc\ModelInterface

Single [alias => new Alias()] // create new alias

Many [alias => [new Alias()]] // create new alias [alias => [1, 2, 3, 4]] // append / merge 1, 2, 3, 4 [alias => [false, 1, 2, 4]]; // delete 3

Parameters:

Parameter Type Description
$data array
$whiteList array|null
$dataColumnMap array|null

Throws:


isRelatedAssignmentWhiteListed

Check whether a relation alias is allowed by a nested assignment whitelist.

private isRelatedAssignmentWhiteListed(string $alias, array $whiteList): bool

The whitelist can contain relation aliases as plain values or as keys that point to nested allowed fields. This mirrors existing PhalconKit save-field payloads without forcing callers to choose one representation.

Parameters:

Parameter Type Description
$alias string
$whiteList array

isRelationPayload

Determine whether an unknown key carries relationship-shaped data.

private isRelationPayload(mixed $value): bool

Scalar unknown keys are left to native model assignment. Complex values are the only safe candidates for strict relationship-alias validation because they are how REST/save payloads express nested relations.

Parameters:

Parameter Type Description
$value mixed

isModelAssignmentField

Check whether a non-relation assignment key is a known model field.

private isModelAssignmentField(string $field, ?array $dataColumnMap = null): bool

Strict relationship assignment must not reject JSON/array columns or mapped model attributes just because their values look like nested relation payloads. The optional data column map is checked first because callers may use external request keys that Phalcon maps before writing.

Parameters:

Parameter Type Description
$field string
$dataColumnMap ?array

isDirectOwnedRelationType

private isDirectOwnedRelationType(?int $type): bool

Parameters:

Parameter Type Description
$type ?int

assertDirectRelatedRecordCanBeAssigned

private assertDirectRelatedRecordCanBeAssigned(?string $alias, ?int $type, array $relationFields, array $referencedFields, \Phalcon\Mvc\EntityInterface $record): void

Parameters:

Parameter Type Description
$alias ?string
$type ?int
$relationFields array
$referencedFields array
$record \Phalcon\Mvc\EntityInterface

getDirectRelatedOwnershipState

private getDirectRelatedOwnershipState(array $relationFields, array $referencedFields, \Phalcon\Mvc\EntityInterface $record): string

Parameters:

Parameter Type Description
$relationFields array
$referencedFields array
$record \Phalcon\Mvc\EntityInterface

isEmptyRelationValue

private isEmptyRelationValue(mixed $value): bool

Parameters:

Parameter Type Description
$value mixed

isSameRelationValue

private isSameRelationValue(mixed $expected, mixed $actual): bool

Parameters:

Parameter Type Description
$expected mixed
$actual mixed

prepareDirectRelatedRecordForSave

private prepareDirectRelatedRecordForSave(\Phalcon\Mvc\Model\RelationInterface $relation, \Phalcon\Mvc\EntityInterface $record, ?string $alias, ?int $index = null): bool

Parameters:

Parameter Type Description
$relation \Phalcon\Mvc\Model\RelationInterface
$record \Phalcon\Mvc\EntityInterface
$alias ?string
$index ?int

preSaveRelatedRecords

Saves related records that must be stored prior to save the master record Refactored based on the native cphalcon version, so we can support : - combined keys on relationship definition - relationship context within the model messages based on the alias definition

protected preSaveRelatedRecords(\Phalcon\Db\Adapter\AdapterInterface $connection, \Phalcon\Mvc\ModelInterface[] $related, \Phalcon\Support\Collection\CollectionInterface $visited): bool

Parameters:

Parameter Type Description
$connection \Phalcon\Db\Adapter\AdapterInterface
$related \Phalcon\Mvc\ModelInterface[]
$visited \Phalcon\Support\Collection\CollectionInterface

Throws:


postSaveRelatedRecords

Processes the saving of related records for the current model.

protected postSaveRelatedRecords(\Phalcon\Db\Adapter\AdapterInterface $connection, array|object[]|\Phalcon\Mvc\ModelInterface[] $related, \Phalcon\Support\Collection\CollectionInterface $visited): bool

Performs operations based on relationship types such as HAS_MANY, HAS_ONE, HAS_MANY_THROUGH, etc. Handles automatic deletion of missing related records and ensures correct binding and transaction management.

NOTE: we need this, this behavior only happens: - in many-to-many nodes Fix uniqueness on combined keys in node entities, and possibly more...

Parameters:

Parameter Type Description
$connection \Phalcon\Db\Adapter\AdapterInterface Database connection instance used for transactions.
$related array|object[]|\Phalcon\Mvc\ModelInterface[] Related records to be saved, provided as arrays or objects.
$visited \Phalcon\Support\Collection\CollectionInterface A collection of already visited models to prevent recursion.

Return Value:

Returns true on successful processing of related records, false if an error occurs.

Throws:

Throws an exception if there are no defined relations for a given alias or if invalid data types are provided. - InvalidArgumentException

See Also:

  • https://forum.phalconphp.com/discussion/2190/many-to-many-expected-behaviour
  • http://stackoverflow.com/questions/23374858/update-a-records-n-n-relationships
  • https://github.com/phalcon/cphalcon/issues/2871

postSaveRelatedRecordsAfter

Handles the saving process of related records after the parent record's save operation.

public postSaveRelatedRecordsAfter(\Phalcon\Mvc\Model\RelationInterface $relation, array|object[]|\Phalcon\Mvc\ModelInterface[] $relatedRecords, \Phalcon\Support\Collection\CollectionInterface $visited): bool|null

It assigns referenced fields to the related records and ensures they are saved with proper relationships maintained. If the relation is defined as Through, this method skips further processing.

Parameters:

Parameter Type Description
$relation \Phalcon\Mvc\Model\RelationInterface The relation instance that provides information about the relationship.
$relatedRecords array|object[]|\Phalcon\Mvc\ModelInterface[] An array of related records to be saved.
$visited \Phalcon\Support\Collection\CollectionInterface A collection to track visited records to prevent infinite recursion.

Return Value:

Returns true if all related records are saved successfully, false if an error occurs during saving, and null if the relation is of type Through.

Throws:

If there is an error during the save operation for a related record. - InvalidArgumentException


postSaveRelatedThroughAfter

Handles saving related records for through relationships after the primary records have been saved.

public postSaveRelatedThroughAfter(\Phalcon\Mvc\Model\RelationInterface $relation, array|object[]|\Phalcon\Mvc\ModelInterface[] $relatedRecords, \Phalcon\Support\Collection\CollectionInterface $visited): bool|null

Primarily used to manage intermediate models and ensure proper linkage and saving of related records in many-to-many or has-one-through relationships.

Parameters:

Parameter Type Description
$relation \Phalcon\Mvc\Model\RelationInterface The relation object defining the association details.
$relatedRecords array|object[]|\Phalcon\Mvc\ModelInterface[] An array of related records to be processed and saved.
$visited \Phalcon\Support\Collection\CollectionInterface A collection of visited records to maintain state and prevent circular references.

Return Value:

Returns true if all related records and intermediate records were successfully saved. Returns false if any save operation failed. Returns null if the relation is not a through relationship.

Throws:

If the intermediate model or related records cannot be properly saved. - InvalidArgumentException


findFirstByPrimaryKeys

Find the first record by its primary key attributes.

public findFirstByPrimaryKeys(array $data, string|null $modelClass): \Phalcon\Mvc\ModelInterface|\Phalcon\Mvc\Model\Row|null

Parameters:

Parameter Type Description
$data array The data containing the primary key values.
$modelClass string|null The class name of the model to search for. If not provided, the current model class will be used.

Return Value:

The found record entity.


getEntityFromData

Get the entity object from the given data.

public getEntityFromData(array $data, array $configuration = []): \Phalcon\Mvc\ModelInterface|\Phalcon\Mvc\Model\Row|null

It will try to find the existing record and then assign the new data. - Will first try using the primary key of the related record - Then will try using the defined relationship fields using the relationship alias

Parameters:

Parameter Type Description
$data array The data array.
$configuration array The configuration options.
- alias: The alias name.
- fields: The fields array.
- modelClass: The model class.
- readFields: The read fields array.
- type: The relationship type.
- whiteList: The whitelist array.
- dataColumnMap: The data column map array.

Return Value:

The entity object or null if not found.


appendMessages

public appendMessages(array $messages = [], ?string $context = null, ?int $index = null): void

Parameters:

Parameter Type Description
$messages array
$context ?string
$index ?int

appendMessagesFromRecord

Appends messages from a record to the current messages container.

public appendMessagesFromRecord(\Phalcon\Mvc\ModelInterface|null $record = null, string|null $context = null, int|null $index = null): void

Parameters:

Parameter Type Description
$record \Phalcon\Mvc\ModelInterface|null The record from which to append the messages.
$context string|null The context in which the messages should be added. Defaults to null.
$index int|null The index at which the messages should be added. Defaults to 0.

appendMessagesFromResultset

Append messages from a resultset to the current message container.

public appendMessagesFromResultset(\Phalcon\Mvc\Model\ResultsetInterface|null $resultset = null, string|null $context = null, int|null $index = null): void

Parameters:

Parameter Type Description
$resultset \Phalcon\Mvc\Model\ResultsetInterface|null The resultset containing the messages to be appended. If not provided, no messages will be appended.
$context string|null The context to assign to the appended messages. If not provided, the default context will be used.
$index int|null The index at which the messages should be inserted in the messages array. If not provided, the messages will be appended at the end.

appendMessagesFromRecordList

Appends messages from a record list to the current message container.

public appendMessagesFromRecordList(iterable|null $recordList = null, string|null $context = null, int|null $index = null): void

Parameters:

Parameter Type Description
$recordList iterable|null The list of records to append messages from.
$context string|null The context to associate with the messages.
$index int|null The index to use for the messages.

rebuildMessageContext

Rebuilds the message context.

public rebuildMessageContext(\Phalcon\Messages\Message $message, string|null $context = null): string

This method appends the given context to the previous context stored in the message metadata. If there is no previous context, only the given context is returned.

Parameters:

Parameter Type Description
$message \Phalcon\Messages\Message The message object whose context needs to be rebuilt.
$context string|null The context to be appended.

Return Value:

The rebuilt context


rebuildMessageIndex

Rebuilds the message index.

public rebuildMessageIndex(\Phalcon\Messages\Message $message, int|null $index = null): string

This method constructs the new message index based on the provided $index argument and the previous index stored in the message's metadata. It returns the new index as a string.

Parameters:

Parameter Type Description
$message \Phalcon\Messages\Message The message object for which the index is being rebuilt.
$index int|null The new index to be assigned to the message. Can be null.

Return Value:

The new index as a string


relatedToArray

Retrieves the related records as an array.

public relatedToArray(array|null $columns = null, bool $useGetter = true): array<string,mixed>

If $columns is provided, only the specified columns will be included in the array. If $useGetter is set to true, it will use the getter methods of the related records.

Parameters:

Parameter Type Description
$columns array|null (optional) The columns to include in the array for each related record
$useGetter bool (optional) Whether to use getter methods of the related records (default: true)

Return Value:

The related records as an array


getRelated

Overriding default phalcon getRelated in order to fix an important issue where the related record is being stored into the "related" property and then passed from the collectRelatedToSave and is mistakenly saved without the user consent

public getRelated(string $alias, mixed $arguments = null): mixed

Parameters:

Parameter Type Description
$alias string
$arguments mixed
Values populated by Phalcon 5.18's native eager loader are returned from
PhalconKit's read-only cache. Uncached relationships continue through
the models manager so they are never added to Phalcon's dirty relation
save pipeline.

Return Value:

Cached related data or the models manager query result.

Throws:


toArray

Returns the instance as an array representation

public toArray(array $columns = null, bool $useGetter = true): array

Parameters:

Parameter Type Description
$columns array
$useGetter bool