Oihana PHP Arango

helpers

Table of Contents

Namespaces

edges
joins
relations

Functions

assertDocuments()  : void
Ensures that a given value is an instance of {@see Documents}.
buildVariables()  : void
Builds all fields variables definitions (edges, joins, etc.).
extractFromIDs()  : array<string|int, mixed>
Extract unique "_from" vertex IDs from a list of edge documents.
extractNestedRelations()  : array{edges: array, joins: array}
Extract nested edges and joins from a relation configuration or resolved model.
extractToIDs()  : array<string|int, mixed>
Extract unique "_to" vertex IDs from a list of edge documents.
extractVertexIDs()  : array<string|int, mixed>
Extract unique vertex IDs from a list of edge documents.
getDocuments()  : Documents|null
Resolves a {@see Documents} instance from various types of input definitions.
isAuthorized()  : bool
Decides whether a field projection is allowed for the current request.
parseFilterSegment()  : FilterPath|null
Parse a single path segment from hierarchical configuration.
vertexID()  : string|null
Resolves a fully-qualified vertex ID for an ArangoDB edge.

Functions

assertDocuments()

Ensures that a given value is an instance of {@see Documents}.

assertDocuments(mixed $value) : void

This runtime assertion validates type safety for Documents. If the provided value is not an instance of Documents, an UnexpectedValueException is thrown with a descriptive message.

This is especially useful when handling dynamically typed data or container-resolved dependencies, where you want to enforce strict model integrity.

Parameters
$value : mixed

The value to assert as an Documents instance.

Tags
throws
UnexpectedValueException

If the provided value is not an instance of Documents.

example
use oihana\arango\models\helpers\assertDocuments;
use oihana\arango\models\Documents;

$documents = new Documents();

// ✅ Valid: no exception thrown
assertDocuments( $documents );

// ❌ Invalid: throws UnexpectedValueException
assertDocuments( 'not an edges instance' );
// → UnexpectedValueException: The value property must be an instance of Documents (arango).
author

Marc Alcaraz (eKameleon)

version
1.0.0

buildVariables()

Builds all fields variables definitions (edges, joins, etc.).

buildVariables([array<string|int, mixed> &$variables = [] ][, array<string|int, mixed> $fields = [] ][, array<string|int, mixed>|null $edges = [] ][, array<string|int, mixed>|null $joins = [] ][, ContainerInterface|null $container = null ][, string $docRef = AQL::DOC ][, array<string|int, mixed> $init = [] ]) : void

Field-level gating: when a field declares Field::REQUIRES and the request-scoped authorizer denies it, the matching LET variable is not emitted. Combined with the symmetric drop in aqlFields(), the field disappears from both the AQL projection and the response — no key in the JSON, no orphan reference in the AQL.

The check is uniform: edges, joins, and edge-counts all share the same gating contract. A Filter::EDGES_COUNT companion is gated exactly the same way as the others — it is simply not gated by default because no Field::REQUIRES is declared on it. To gate the count, declare Field::REQUIRES on the count entry itself.

Parameters
$variables : array<string|int, mixed> = []
$fields : array<string|int, mixed> = []
$edges : array<string|int, mixed>|null = []
$joins : array<string|int, mixed>|null = []
$container : ContainerInterface|null = null
$docRef : string = AQL::DOC
$init : array<string|int, mixed> = []
Tags
throws
BindException
ConstantException
ContainerExceptionInterface
NotFoundExceptionInterface
ReflectionException

extractFromIDs()

Extract unique "_from" vertex IDs from a list of edge documents.

extractFromIDs(array<string|int, mixed> $edges) : array<string|int, mixed>

This helper function is a shortcut for extractVertexIds() with $side fixed to Schema::_FROM. It returns a unique list of vertex IDs from the "_from" field in an array of edge documents (objects or associative arrays).

Parameters
$edges : array<string|int, mixed>

Array of edge objects or associative arrays containing _from and _to.

Tags
example
use oihana\arango\models\helpers\extractFromIds;
use org\schema\constants\Schema;

$edges = [
    (object) ['_from' => 'apis/1', '_to' => 'permissions/1'],
    (object) ['_from' => 'apis/1', '_to' => 'permissions/2'],
    ['_from' => 'apis/2', '_to' => 'permissions/1'],
];

$fromIds = extractFromIds($edges);
// Result: ['apis/1', 'apis/2']
author

Marc Alcaraz (eKameleon)

version
1.0.0
Return values
array<string|int, mixed>

Unique list of "_from" vertex IDs.

extractNestedRelations()

Extract nested edges and joins from a relation configuration or resolved model.

extractNestedRelations(array<string|int, mixed> $config[, object|null $targetModel = null ][, bool|null $isEdge = null ][, ContainerInterface|null $container = null ]) : array{edges: array, joins: array}

This function can work in two modes:

  1. Resolution mode: Resolves target model from config via container, then extracts relations
  2. Direct mode: Extracts relations from an already-resolved target model

In both modes, the function merges the extracted relations with any explicit AQL::EDGES and AQL::JOINS defined in the relation configuration.

Resolution mode (for parseFilterSegment):

$relations = extractNestedRelations(
    config: $edgeConfig,
    isEdge: true,
    container: $container
);

Direct mode (for buildEdgeTraversal/buildJoinTraversal):

$relations = extractNestedRelations(
    config: $edgeConfig,
    targetModel: $alreadyResolvedModel
);
Parameters
$config : array<string|int, mixed>

The relation configuration (edge or join config).

$targetModel : object|null = null

Optional: already-resolved target model.

$isEdge : bool|null = null

Required if $targetModel is null: true for edges, false for joins.

$container : ContainerInterface|null = null

Required if $targetModel is null: DI container.

Tags
throws
ContainerExceptionInterface
NotFoundExceptionInterface
Return values
array{edges: array, joins: array}

Associative array with 'edges' and 'joins' keys.

extractToIDs()

Extract unique "_to" vertex IDs from a list of edge documents.

extractToIDs(array<string|int, mixed> $edges) : array<string|int, mixed>

This helper function is a shortcut for extractVertexIds() with $side fixed to Schema::_TO. It returns a unique list of vertex IDs from the "_to" field in an array of edge documents (objects or associative arrays).

Parameters
$edges : array<string|int, mixed>

Array of edge objects or associative arrays containing _from and _to.

Tags
example
use oihana\arango\models\helpers\extractToIds;
use org\schema\constants\Schema;

$edges = [
    (object) ['_from' => 'apis/1', '_to' => 'permissions/1'],
    (object) ['_from' => 'apis/1', '_to' => 'permissions/2'],
    ['_from' => 'apis/2', '_to' => 'permissions/1'],
];

$toIds = extractToIds($edges);
// Result: ['permissions/1', 'permissions/2']
author

Marc Alcaraz (eKameleon)

version
1.0.0
Return values
array<string|int, mixed>

Unique list of "_to" vertex IDs.

extractVertexIDs()

Extract unique vertex IDs from a list of edge documents.

extractVertexIDs(array<string|int, mixed> $edges, string $side) : array<string|int, mixed>

This helper function is used to extract either the "_from" or "_to" vertex IDs from an array of edge documents (objects or arrays) and return only the unique IDs.

Parameters
$edges : array<string|int, mixed>

Array of edge objects or associative arrays containing _from and _to.

$side : string

The side to extract, either Schema::_FROM or Schema::_TO.

Tags
example
use oihana\arango\models\helpers\extractVertexIds;
use org\schema\constants\Schema;

$edges =
[
    (object) ['_from' => 'apis/1', '_to' => 'permissions/1'],
    (object) ['_from' => 'apis/1', '_to' => 'permissions/2'],
    ['_from' => 'apis/2', '_to' => 'permissions/1'],
];

$toIds = extractVertexIds($edges, Schema::_TO);
// Result: ['permissions/1', 'permissions/2']

$fromIds = extractVertexIds($edges, Schema::_FROM);
// Result: ['apis/1', 'apis/2']
author

Marc Alcaraz (eKameleon)

version
1.0.0
Return values
array<string|int, mixed>

Unique list of vertex IDs.

getDocuments()

Resolves a {@see Documents} instance from various types of input definitions.

getDocuments([array<string|int, mixed>|string|Documents|null $definition = null ][, ContainerInterface|null $container = null ][, string $key = Arango::DOCUMENTS ][, Documents|null $default = null ]) : Documents|null

This helper function returns a Documents object from: a direct instance, an array definition, a service name within a PSR-11 container, or falls back to a provided default value.

Behavior:

  • If $definition is a Documents instance, it is returned as-is.
  • If $definition is an array, the function looks for the $key (default: Arango::DOCUMENTS).
  • If $definition is a non-empty string and $container contains a service with that name, the corresponding service is fetched.
  • If none of the above conditions are met, the $default value is returned.
Parameters
$definition : array<string|int, mixed>|string|Documents|null = null

Input definition that may represent an Documents instance, an associative array containing one, or a container service name.

$container : ContainerInterface|null = null

Optional PSR-11 container used to resolve string service names.

$key : string = Arango::DOCUMENTS

Array key to look for when $definition is an array

$default : Documents|null = null

Default Documents instance to return if resolution fails. (defaults to Arango::DOCUMENTS).

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving the service from the container.

NotFoundExceptionInterface

If the service is not found in the container.

example
use oihana\arango\models\helpers\getDocuments;
use oihana\arango\models\Documents;
use oihana\arango\enums\Arango;
use Psr\Container\ContainerInterface;

$docs = new Documents(['_key' => 'user_1']);

// Example 1: Direct instance
$result = getDocuments($docs);
// → returns the same $docs instance

// Example 2: From array definition
$result = getDocuments([Arango::DOCUMENTS => $docs]);
// → returns the $docs instance from the array

// Example 3: From container service
$container->method('has')->willReturn(true);
$container->method('get')->willReturn($docs);
$result = getDocuments('my.documents.service', $container);
// → returns the $docs instance from the container

// Example 4: Default fallback
$default = new Documents(['_key' => 'fallback']);
$result  = getDocuments(null, null, $default);
// → returns $default
author

Marc Alcaraz (eKameleon)

version
1.0.0
Return values
Documents|null

Returns the resolved Documents instance or the default value if not found.

isAuthorized()

Decides whether a field projection is allowed for the current request.

isAuthorized(array<string|int, mixed> $definition[, array<string|int, mixed> $init = [] ]) : bool

Reads the optional Field::REQUIRES permission subject(s) declared on the field definition, then defers the actual decision to a backend-agnostic Closure(string $subject): bool injected through $init[Arango::AUTHORIZER].

The framework remains agnostic of the underlying authorization layer (Casbin, OPA, custom, ...) — the consumer is responsible for binding the callable to a real enforcer and a request-scoped user identifier.

Resolution rules:

  • No Field::REQUIRES declared on the definition → true (no gating).
  • Field::REQUIRES resolves to an empty list → true (no gating).
  • No Arango::AUTHORIZER injected, or value is not callable → true (authorization layer disabled, fail open).
  • One or more subjects declared → true if at least one subject is granted by the callable (logical OR).
Parameters
$definition : array<string|int, mixed>

Field definition. Reads Field::REQUIRES.

$init : array<string|int, mixed> = []

The request-level init array. Reads Arango::AUTHORIZER.

Tags
example

Single subject

$definition[ Field::REQUIRES ] = 'users.roles:list' ;
isAuthorized( $definition , [ Arango::AUTHORIZER => fn() => true ] ) ; // true
isAuthorized( $definition , [ Arango::AUTHORIZER => fn() => false ] ) ; // false

OR over a list

$definition[ Field::REQUIRES ] = [ 'users.roles:list' , 'users.roles:admin' ] ;
$init[ Arango::AUTHORIZER ]    = fn( string $s ) : bool => $s === 'users.roles:admin' ;
isAuthorized( $definition , $init ) ; // true (admin matched)
author

Marc Alcaraz (eKameleon)

version
1.0.0
Return values
bool

true when the projection is allowed, false when every declared subject was refused.

parseFilterSegment()

Parse a single path segment from hierarchical configuration.

parseFilterSegment(string $segment, array<string|int, mixed> $filters[, array<string|int, mixed> $edges = [] ][, array<string|int, mixed> $joins = [] ][, array<string|int, mixed> $parentPath = [] ][, ContainerInterface|null $container = null ]) : FilterPath|null

This function analyzes a filter path segment and determines its type (simple field, document, array expansion, edge, or join). It validates the segment against the configuration and, for edges and joins, resolves nested relations from target models.

Key Features:

  • Validates array notation consistency (e.g., employee[*] must be of type EDGES/JOINS/ARRAY_EXPANSION)
  • Resolves nested edges/joins from target models for multi-level traversals
  • Supports both explicit relation references (via AQL::RELATION) and implicit (segment key)
  • Accumulates full path for better error reporting

Nested Relations Resolution: For edges, the function:

  1. Gets the edge model from the container
  2. Determines target model based on traversal direction (INBOUND → from, OUTBOUND → to)
  3. Extracts edges/joins from target model
  4. Merges with explicit nested relations from edge configuration

For joins, the function:

  1. Gets the join target model from the container
  2. Extracts edges/joins from target model
Parameters
$segment : string

Current path segment (e.g., "employee[*]", "address", "workLocation")

$filters : array<string|int, mixed>

Current level AQL::FILTERS configuration

$edges : array<string|int, mixed> = []

Available edges configuration at current level

$joins : array<string|int, mixed> = []

Available joins configuration at current level

$parentPath : array<string|int, mixed> = []

Accumulated path from parent segments for error reporting

$container : ContainerInterface|null = null

DI container for resolving target models and their relations

Tags
throws
RuntimeException

If relation reference is not found in edges/joins configuration

ContainerExceptionInterface

If container encounters an error resolving models

NotFoundExceptionInterface

If target model is not found in container

example
// Simple field
$info = parseFilterSegment('email', ['email' => FilterType::STRING], [], [], []);
// → type: 'string', path: ['email'], nestedEdges: [], nestedJoins: []

// Custom callable
$customFilter = fn($init, &$binds, $doc) => "LOWER($doc.name) == 'test'";
$info = parseFilterSegment('custom', ['custom' => $customFilter], [], [], []);
// → type: Closure, path: ['custom']

// Edge with nested relations
$info = parseFilterSegment(
    'employee[*]',
    ['employee' => ['type' => Filter::EDGES, 'filters' => [...]]],
    ['employee' => ['model' => Models::EMPLOYEE_EDGE]],
    [],
    [],
    $container
);
// → type: 'edges', path: ['employee'], nestedEdges: [...from target model...], nestedJoins: [...]
Return values
FilterPath|null

Parsed segment information with nested relations, or null if segment is not allowed

vertexID()

Resolves a fully-qualified vertex ID for an ArangoDB edge.

vertexID(string|null $vertexKey[, Documents|string|null $collection = null ]) : string|null

Converts a vertex key into a complete ArangoDB vertex ID by optionally prefixing it with a collection name.

This is useful when preparing _from or _to fields in edge queries, ensuring the correct collection/key format.

Behavior

  • If $vertexKey is null, the function returns null.
  • If $collection is a Documents instance with a collection property, the returned ID will be prefixed with this collection.
  • If $collection is a string, it will be used directly as the collection prefix.
  • If $collection is null, the function returns the raw $vertexKey.
Parameters
$vertexKey : string|null

The vertex key (document _key) or null.

$collection : Documents|string|null = null

Optional collection prefix, either a string or a Documents instance.

Tags
example
use oihana\arango\models\Documents;
use function oihana\arango\models\helpers\vertexID;

$docs = new Documents();
$doc->collection = 'users';

$fullID = vertexID('123', $docs);
// → 'users/123'

$rawID = vertexID('456');
// → '456'

$stringPrefix = vertexID('789', 'accounts');
// → 'accounts/789'

$stringPrefix = vertexID('users/789', 'accounts');
// → 'users/789'

$stringPrefix = vertexID('accounts/789', $docs);
// → 'accounts/789'

$nullID = vertexID( null , $docs );
// → null
author

Marc Alcaraz (eKameleon)

version
1.0.0
Return values
string|null

Returns the prefixed vertex ID if a collection is provided, otherwise the original key, or null if $vertexKey is null.

On this page

Search results