JsonField Behavior
Crustum/JsonField.JsonField
Attach this behavior to a Table to enable JSON-column hydration and save routing. It is the single integration point between your entities' #[JsonColumn] / #[JsonEmbed] / #[JsonReference] declarations and the ORM lifecycle; everything else (the JsonFieldAwareTrait query helpers, the association builder) is opt-in on top.
Standard behavior usage — enabling, configuring, removing, and accessing behaviors — is documented in the CakePHP Behaviors cookbook. This page covers only what this behavior does.
What It Does
- On
Model.beforeFindthe behavior installsJsonFieldResultSetas the query's result set class. As each row hydrates, every#[JsonEmbed]decoded array becomes a nestedJsonEntity(or your declared embed class) with theembeddedParentback-pointer set, and per-pathtoPHPcasting is applied. See Reading Data. - On
Model.beforeSaveit persists JSON-embed and JSON-FK reference changes:- References (
#[JsonReference]) store their resolved foreign key into the declared JSON path (saveAssociated()). - A new entity (or one whose JSON storage column is itself dirty) is written as a whole column: each embed is exported and per-path
toDatabasecasters run, then coreJsonTypeencodes the result. - An existing entity with only dirty nested-embed fields is written with atomic, engine-native
set()expressions (jsonb_set/JSON_SET/json_set) scoped to the changed path; the rest of the column is preserved. See Writing Data. - Root-level typed paths declared outside any
#[JsonEmbed](viaJsonSchemaReader::registerCaster()) are cast through theirtoDatabasecaster on a whole-column write.
- References (
Configuration
The behavior takes a single option:
mergeJsonEmbeds(bool, defaultfalse) — whentrue, a plain-array value assigned to an embed property is deep-merged into the already-hydrated embed entity instead of replacing it. This makespatchEntity()with partial embed data keep sibling fields. The defaultfalsereplaces the embed wholesale.
php
public function initialize(array $config): void
{
parent::initialize($config);
$this->addBehavior('Crustum/JsonField.JsonField', [
'mergeJsonEmbeds' => true,
]);
}Entities without any #[JsonColumn] declaration are ignored by the behavior, so it is safe to attach broadly.