CoolCMS API

OwnershipPayload
in package

FinalYes

Stateless reading of identifiers from the `data` payload of an external Api request.

It may extract an id ("which record / which parent is this about"). It must never extract an owner (userId, insertUserId, user.id): who owns a record is decided only by the Api manager through a SELECT by that id, since checking a value taken from the same request proves nothing.

It is a separate class so it is unit-testable without DI and so that its two consumers, the gate (OwnershipCheckTrait) and the owner assignment on INSERT (SaveTrait::applyExternalOwner()), tell INSERT from UPDATE identically; otherwise one would treat a request as create and the other as edit.

Table of Contents

Methods

entityId()  : int|null
Returns the id of the edited record from `data`, or `null` for an INSERT.
findValue()  : mixed
Finds a key case-insensitively and ignoring underscores, the same normalization the hydration ({@see \App\Core\Utils\Hydrators\OrmEntityHydrator::normalizePropertyName()}) and the `#[ExternalReadonly]` strip apply.
normalizeId()  : int|null
Normalizes `5`, `'5'` and `' 5 '` to `5`; `0`, `-1`, `''`, `'abc'`, `null`, arrays and objects to `null`.
parentId()  : int|null
Returns the parent id from `data`. Accepts every shape a ToOne association can arrive in: `data[order][id]=5` (full object or `{"id":5}` reference), `data[order]=5`, `data[orderId]=5`, `data[order_id]=5`.

Methods

entityId()

Returns the id of the edited record from `data`, or `null` for an INSERT.

public static entityId(array<string|int, mixed> $data) : int|null

Zero, a negative number, an empty string and a non-numeric value all mean "no id" and so INSERT. This is fail-closed: the INSERT branch of the gate is stricter (it verifies the parent and assigns the owner on the server), while an UPDATE with an invalid id would end in find() === null anyway.

Parameters
$data : array<string|int, mixed>
Return values
int|null

findValue()

Finds a key case-insensitively and ignoring underscores, the same normalization the hydration ({@see \App\Core\Utils\Hydrators\OrmEntityHydrator::normalizePropertyName()}) and the `#[ExternalReadonly]` strip apply.

public static findValue(array<string|int, mixed> $data, string $property) : mixed

IMPORTANT: if the gate looked only at the exact key id, a client could send ID or _id: the gate would see an INSERT (which never checks who owns an existing record) while the hydration still processes it as an UPDATE, because setID()/set_id() resolve to setId(). That bypass is closed in the strip and must not return through this method.

Parameters
$data : array<string|int, mixed>
$property : string

normalizeId()

Normalizes `5`, `'5'` and `' 5 '` to `5`; `0`, `-1`, `''`, `'abc'`, `null`, arrays and objects to `null`.

public static normalizeId(mixed $value) : int|null

IMPORTANT: no blind (int) cast. (int) 'abc' and (int) null give 0, which then looks like a valid id and, combined with not null default 0 columns (Watchdog / AdvertFollower userId), becomes a live trap.

Parameters
$value : mixed
Return values
int|null

parentId()

Returns the parent id from `data`. Accepts every shape a ToOne association can arrive in: `data[order][id]=5` (full object or `{"id":5}` reference), `data[order]=5`, `data[orderId]=5`, `data[order_id]=5`.

public static parentId(array<string|int, mixed> $data, string $property) : int|null

IMPORTANT: the value comes from the client and only says which parent it wants to attach to. That the parent belongs to the requester is verified by the manager against the database.

Parameters
$data : array<string|int, mixed>
$property : string

name of the ToOne property on the entity (camelCase, e.g. order)

Return values
int|null
On this page

Search results