Oihana PHP Arango

UserMaxLevelResolver

Persists `users.maxLevel` in real-time when role assignments or role levels change.

Wired in DI on three signals :

  • userHasRoles.afterInsert → recompute the user on _from of the newly inserted edge.
  • userHasRoles.afterDelete → recompute the user(s) on _from of the deleted edge(s). Handles both shapes of the payload (data = a single edge object for deleteEdge and data = an array of edges for deleteEdges cascades).
  • roles.afterUpdate → recompute every user INBOUND from the updated role. The level field is not diffed against the previous state — admin role PATCH is rare and the recompute is idempotent.

The recompute runs as a single AQL UPDATE per call ; for the INBOUND path the entire user set is updated in one round-trip.

Tags
author

Marc Alcaraz

Table of Contents

Properties

$logger  : LoggerInterface|null
$rolesModel  : Documents|null
$userHasRolesModel  : Edges|null
$usersModel  : Documents|null

Methods

__construct()  : mixed
Creates a new UserMaxLevelResolver instance.
backfillAll()  : int
Recomputes `maxLevel` on every user document.
onRoleUpdated()  : void
Listener on `roles.afterUpdate` — recomputes every user `INBOUND` from the updated role. Same visibility rationale as {@see onUserHasRolesEdgeInserted()}.
onUserHasRolesEdgeDeleted()  : void
Listener on `userHasRoles.afterDelete` — recomputes every user vertex referenced by `_from` of the deleted edge(s). Same visibility rationale as {@see onUserHasRolesEdgeInserted()}.
onUserHasRolesEdgeInserted()  : void
Listener on `userHasRoles.afterInsert` — recomputes the user vertex on `_from` of the inserted edge. Public to allow direct invocation in tests and external orchestrators ; the production call site is the signal closure wired by {@see register()}.
recompute()  : void
Recomputes `maxLevel` for one or several users in a single AQL round-trip. No-op when the input is empty.
recomputeForRole()  : void
Recomputes `maxLevel` on every user `INBOUND` from a given role.
register()  : void
Wires this resolver on the three signals it cares about.
extractUserKey()  : string|null
Extracts the user vertex `_key` from a single `_id` string, a full user-vertex object, or returns `null` when the value is unusable. Accepts both `users/123` and a bare `123`.
normalizeUserKeys()  : array<int, string>
Reduces the input shape of a `recompute()` call to a list of unique non-empty `_key` strings.
recomputeFromEdgePayload()  : void
Shared edge-payload handler — extracts the affected user `_key` set from an `afterInsert` (single edge) or `afterDelete` (single edge or array of edges), then runs a single batched recompute. Failures are logged but never bubble up : the signal listener must not break the originating write operation.

Properties

Methods

__construct()

Creates a new UserMaxLevelResolver instance.

public __construct([Documents|null $usersModel = null ][, Edges|null $userHasRolesModel = null ][, Documents|null $rolesModel = null ][, LoggerInterface|null $logger = null ]) : mixed
Parameters
$usersModel : Documents|null = null
$userHasRolesModel : Edges|null = null
$rolesModel : Documents|null = null
$logger : LoggerInterface|null = null

backfillAll()

Recomputes `maxLevel` on every user document.

public backfillAll() : int

Used by the auth:users:backfill:maxlevel command after the persistence is first deployed (or as a safety net when an inconsistency is suspected). Returns the number of user documents that were updated.

Tags
throws
ArangoException
BindException
ContainerExceptionInterface
NotFoundExceptionInterface
ReflectionException
Return values
int

onRoleUpdated()

Listener on `roles.afterUpdate` — recomputes every user `INBOUND` from the updated role. Same visibility rationale as {@see onUserHasRolesEdgeInserted()}.

public onRoleUpdated(Payload $payload) : void
Parameters
$payload : Payload

onUserHasRolesEdgeDeleted()

Listener on `userHasRoles.afterDelete` — recomputes every user vertex referenced by `_from` of the deleted edge(s). Same visibility rationale as {@see onUserHasRolesEdgeInserted()}.

public onUserHasRolesEdgeDeleted(Payload $payload) : void
Parameters
$payload : Payload

onUserHasRolesEdgeInserted()

Listener on `userHasRoles.afterInsert` — recomputes the user vertex on `_from` of the inserted edge. Public to allow direct invocation in tests and external orchestrators ; the production call site is the signal closure wired by {@see register()}.

public onUserHasRolesEdgeInserted(Payload $payload) : void
Parameters
$payload : Payload

recompute()

Recomputes `maxLevel` for one or several users in a single AQL round-trip. No-op when the input is empty.

public recompute(string|array<int, string|null> $userKeys) : void
Parameters
$userKeys : string|array<int, string|null>

A single Arango _key, a list of keys, or a list of users/<key> _id strings (the helper normalises every entry).

Tags
throws
ArangoException
BindException
ContainerExceptionInterface
NotFoundExceptionInterface
ReflectionException

recomputeForRole()

Recomputes `maxLevel` on every user `INBOUND` from a given role.

public recomputeForRole(string $roleKey) : void

Triggered by the roles.afterUpdate listener. The role's level may or may not have changed — recompute is idempotent and the cost is bounded by the number of users carrying the role, which is typically small.

Parameters
$roleKey : string
Tags
throws
ArangoException
BindException
ContainerExceptionInterface
NotFoundExceptionInterface
ReflectionException

register()

Wires this resolver on the three signals it cares about.

public register() : void

Idempotent — safe to call once per instance.

extractUserKey()

Extracts the user vertex `_key` from a single `_id` string, a full user-vertex object, or returns `null` when the value is unusable. Accepts both `users/123` and a bare `123`.

private extractUserKey(mixed $value) : string|null
Parameters
$value : mixed
Return values
string|null

normalizeUserKeys()

Reduces the input shape of a `recompute()` call to a list of unique non-empty `_key` strings.

private normalizeUserKeys(string|array<int, mixed> $userKeys) : array<int, string>
Parameters
$userKeys : string|array<int, mixed>
Return values
array<int, string>

recomputeFromEdgePayload()

Shared edge-payload handler — extracts the affected user `_key` set from an `afterInsert` (single edge) or `afterDelete` (single edge or array of edges), then runs a single batched recompute. Failures are logged but never bubble up : the signal listener must not break the originating write operation.

private recomputeFromEdgePayload(Payload $payload, string $context) : void
Parameters
$payload : Payload
$context : string
On this page

Search results