\Drupal\strata\Capture EntityDelta

Reduces an entity save to the fields that actually changed.

A full entity image is expensive and mostly redundant: measured on Drupal-shaped data, a node image is 2,661 bytes and a title edit is 97. The previous version is already in memory during a save as the entity's original, so the comparison costs nothing to obtain and 4.1 to 4.3 microseconds to compute.

Some fields are excluded by name rather than by comparison. changed moves on every save and describes the save rather than the content. access, login and init on a user move on every authenticated request and are two thirds of a Drupal site's total write volume; restoring an old access would make an active account look dormant, which is corruption rather than recovery, so they are never part of a delta and never part of a restore.

Summary

Methods
Properties
Constants
changedFields
payload
isMeaningful
isAccessTouch
No public properties found
IGNORED
ACCESS_FIELDS
No protected methods found
No protected properties found
No protected constants found
ignoredFor
values
normalize
No private properties found
No private constants found

Constant

IGNORED

IGNORED = ['changed', 'revision_timestamp', 'revision_uid', 'revision_id', 'vid']

Fields that describe a save rather than content, so a change to one alone is not a change.

ACCESS_FIELDS

ACCESS_FIELDS = ['access', 'login', 'init']

Fields excluded from a user delta and from a user restore.

Methods

changedFields()

changedFields(\Drupal\Core\Entity\EntityInterface  $entity, \Drupal\Core\Entity\EntityInterface|null  $original) : list<string>

The fields that changed between an entity and its original.

Parameters

\Drupal\Core\Entity\EntityInterface $entity

The entity as saved.

\Drupal\Core\Entity\EntityInterface|null $original

The entity as it was, or NULL for a create.

Returns

list

Field names that changed, excluding the ignored ones. A create reports every field it has.

payload()

payload(\Drupal\Core\Entity\EntityInterface  $entity, \Drupal\Core\Entity\EntityInterface|null  $original) : array<string,mixed>

The delta payload for an entity save.

Carries only the changed fields, so a restore has exactly what it needs to put the subject back and nothing that would overwrite an unrelated later change.

Parameters

\Drupal\Core\Entity\EntityInterface $entity

The entity as saved.

\Drupal\Core\Entity\EntityInterface|null $original

The entity as it was, or NULL for a create.

Returns

array

Field name keyed to its new value.

isMeaningful()

isMeaningful(\Drupal\Core\Entity\EntityInterface  $entity, \Drupal\Core\Entity\EntityInterface|null  $original) : bool

Whether a save changed anything worth capturing.

A save that moved only changed, or only a user's access timestamps, is not a content change.

Parameters

\Drupal\Core\Entity\EntityInterface $entity

The entity as saved.

\Drupal\Core\Entity\EntityInterface|null $original

The entity as it was, or NULL for a create.

Returns

bool —

TRUE when at least one meaningful field changed.

isAccessTouch()

isAccessTouch(\Drupal\Core\Entity\EntityInterface  $entity, \Drupal\Core\Entity\EntityInterface|null  $original) : bool

Whether a save touched only a user's access timestamps.

This is the two-thirds case. Such a save is recorded as a compact login event rather than as a field delta, which keeps the security trail without the volume.

Parameters

\Drupal\Core\Entity\EntityInterface $entity

The entity as saved.

\Drupal\Core\Entity\EntityInterface|null $original

The entity as it was, or NULL for a create.

Returns

bool —

TRUE when the only difference is in the access fields.

ignoredFor()

ignoredFor(\Drupal\Core\Entity\EntityInterface  $entity) : list<string>

Field names excluded for a given entity.

Parameters

\Drupal\Core\Entity\EntityInterface $entity

The entity.

Returns

list

Field names to skip.

values()

values(\Drupal\Core\Entity\FieldableEntityInterface  $entity) : array<string,mixed>

An entity's field values in a comparable form.

Computed fields are skipped: they are derived from other fields, so capturing one would record a change that has no cause and cannot be restored independently.

Scalars are normalised to strings before comparison. An entity held in memory carries an integer where the same entity loaded from the database carries the string the driver returned, so a strict comparison between a saved entity and its original reports every scalar field as changed. Normalising keeps a genuine change visible - 1 and 2 still differ - while a value that only crossed the database boundary does not.

Parameters

\Drupal\Core\Entity\FieldableEntityInterface $entity

The entity.

Returns

array

Field name keyed to its normalised value list.

normalize()

normalize(mixed  $value) : mixed

Reduces a value to a form that survives a database round trip unchanged.

Parameters

mixed $value

Any field value.

Returns

mixed —

The value with every scalar cast to a string, recursively. NULL stays NULL, since an absent value and an empty string are different things.