Oihana PHP

AlterDocumentTrait uses trait:short, \oihana\traits\ContainerTrait

Provides a system to alter properties of arrays or objects based on a configurable set of rules (called "alters").

The alteration definitions are stored in the $alters array and can apply various transformations to data, such as converting values to floats, parsing JSON, cleaning arrays, or resolving URLs.

Supports chaining multiple alterations on a single property:

Example usage:

class MyProcessor
{
    use AlterDocumentTrait;

    public function __construct()
    {
        $this->alters =
        [
            'price' => Alter::FLOAT,
            'tags'  => [ Alter::ARRAY , Alter::CLEAN ],
            'meta'  => [ Alter::JSON_PARSE ],
            'link'  => [ Alter::URL , '/product/' ],
            'score' => [ Alter::CALL , fn( $value ) => $value * 10 ],
            'total' => [ ALTER::MAP , fn( &$document ) => $document['price'] + ( $document['price'] * ( $document['vat'] ?? 0 ) ) ] ,
            'geo'   => [ Alter::NORMALIZE , [ Alter::HYDRATE , GeoCoordinates::class ] ],
            'name'  => [ Alter::TRIM , Alter::UPPERCASE , Alter::NORMALIZE ],
        ];
    }
}

Supported alteration types (see enum Alter):

  • Alter::ARRAY → Split string into array and apply sub-alters.
  • Alter::CLEAN → Remove empty/null elements from an array.
  • Alter::CALL → Call a function on the value.
  • Alter::FLOAT → Convert to float (or array of floats).
  • Alter::GET → Fetch a document using a model.
  • Alter::HYDRATE → Hydrate a value with a specific class.
  • Alter::INT → Convert to integer (or array of integers).
  • Alter::JSON_PARSE → Parse JSON string.
  • Alter::JSON_STRINGIFY → Convert value to JSON string.
  • Alter::MAP → Map a property of a document (or all the document structure) - Can transform or update the document.
  • Alter::NORMALIZE → Normalize a document property using configurable flags.
  • Alter::NOT → Invert boolean values.
  • Alter::URL → Generate a URL from a property.
  • Alter::VALUE → Override with a fixed value.

Mix this trait into a model or a transformer when you need to normalize whole documents (single associative array/object or a list of them) right after they are read from a data source and before they are exposed to the rest of the application. The rules live in the public $alters property and can be overridden per call.

Tags
author

Marc Alcaraz (ekameleon)

since
1.0.0

Table of Contents

Properties

$alters  : array<string|int, mixed>
The alteration definitions applied to document properties.

Methods

alter()  : mixed
Applies defined alterations to a document (array or object) based on a set of rules.
initializeAlters()  : static
Initializes the `$alters` property from an initialization array.
alterProperty()  : array<string|int, mixed>|object
Alters a specific property of the given document using one or more transformation rules.
applyChainedAlterations()  : array<string|int, mixed>|object
Applies chained alterations to a property.
applySingleAlteration()  : array<string|int, mixed>|object
Applies a single alteration (original behavior).
executeAlteration()  : mixed
Executes a specific alteration.
firstIsAlter()  : bool
Checks if a value is an Alter enum or an array starting with an Alter enum.
isChainedDefinition()  : bool
Detects if the definition represents chained alterations.

Properties

$alters

The alteration definitions applied to document properties.

public array<string|int, mixed> $alters = []

Each key is a property name and each value is either a single Alter constant or an array describing a parameterized/chained alteration.

Methods

alter()

Applies defined alterations to a document (array or object) based on a set of rules.

public alter(mixed $document[, array<string|int, mixed>|null $alters = null ]) : mixed

This method inspects the input document and applies transformations according to the provided $alters definitions:

  • If the document is a sequential array (list), the alteration is recursively applied to each element.
  • If the document is an associative array or an object, only the keys defined in $alters are processed.
  • If a key in $alters is associated with a chained alteration (array of alters), each alteration is applied sequentially, passing the output of one as input to the next.
  • Scalar values (string, int, float, bool, resource, null) are returned unchanged unless specifically targeted in $alters.

The $alters parameter allows temporarily overriding or extending the internal $this->alters property for the current method call. Passing null will use the trait's internal $this->alters array.

Parameters
$document : mixed

The input to transform. Can be an associative array, object, or a list of items.

$alters : array<string|int, mixed>|null = null

Optional temporary alter definitions for this call. Keys are property names, values are Alter:: constants or arrays of chained alters.

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

DependencyException

If the dependency cannot be resolved by the container.

NotFoundException

If no entry is found for the given identifier in the container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

ReflectionException

If a class or property cannot be reflected (e.g. during hydration).

example
class Example
{
    use AlterDocumentTrait;

    public function __construct()
    {
        $this->alters = [
            'price' => Alter::FLOAT,
            'tags'  => [ Alter::ARRAY, Alter::CLEAN ],
            'name'  => [ Alter::TRIM, Alter::UPPERCASE ], // Chained alterations
        ];
    }
}

$input = [
    'price' => '19.99',
    'tags'  => 'foo,bar',
    'name'  => '  john  '
];

$processor = new Example();
$output = $processor->alter($input);

// $output:
// [
//     'price' => 19.99,
//     'tags'  => ['foo', 'bar'],
//     'name'  => 'JOHN',
// ]
Return values
mixed

The transformed document, preserving the input structure (array, object, or list of arrays/objects).

initializeAlters()

Initializes the `$alters` property from an initialization array.

public initializeAlters([array<string|int, mixed> $init = [] ]) : static

The definitions are read from the ModelParam::ALTERS key when present; otherwise the current value is kept. The alter key configuration is then initialized through initializeAlterKey().

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

Initialization options, typically the model constructor payload.

Return values
static

The current instance, for fluent chaining.

alterProperty()

Alters a specific property of the given document using one or more transformation rules.

protected alterProperty(string $key, array<string|int, mixed>|object $document, string|array<string|int, mixed> $definition[, Container|null $container = null ]) : array<string|int, mixed>|object

The transformation is defined by the $definition argument, which can be:

  • A string representing a single Alter:: constant (e.g. Alter::FLOAT)
  • An array with a single alteration and parameters: [ Alter::URL , '/product/' ]
  • An array with chained alterations (NEW): [ Alter::NORMALIZE , [ Alter::HYDRATE , Class::class ] ]
  • An array with multiple simple alterations (NEW): [ Alter::TRIM , Alter::UPPERCASE , Alter::NORMALIZE ]

If the alteration modifies the value, the altered value is set back into the document. Otherwise, the original document is returned unmodified.

Supported alter types:

  • Alter::ARRAY — Explodes a string into an array (using ;) and applies sub-alters
  • Alter::CALL — Calls a user-defined callable on the value
  • Alter::CLEAN — Removes empty ("") or null elements from arrays
  • Alter::FLOAT — Casts the value to float
  • Alter::GET — Resolves a document by ID using a model
  • Alter::HYDRATE — Hydrate a value with a specific class.
  • Alter::INT — Casts the value to integer
  • Alter::JSON_PARSE — Parses a JSON string into a PHP value
  • Alter::JSON_STRINGIFY — Encodes a value into a JSON string
  • Alter::MAP — Normalize a document property using configurable flags
  • Alter::NORMALIZE — Normalize a document property using configurable flags
  • Alter::NOT — Invert boolean values
  • Alter::URL — Generates a URL based on document properties
  • Alter::VALUE — Replaces the value with a fixed constant
Parameters
$key : string

The name of the property to alter (e.g. 'price', 'tags')

$document : array<string|int, mixed>|object

The document (array or object) passed by reference

$definition : string|array<string|int, mixed>

The alteration definition: either a string (Alter::) or an array ([ Alter::X , ...args ])

$container : Container|null = null

An optional DI container reference.

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

DependencyException

If the dependency cannot be resolved by the container.

NotFoundException

If no entry is found for the given identifier in the container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

ReflectionException

If a class or property cannot be reflected (e.g. during hydration).

example
$this->alters =
[
    'price'    => Alter::FLOAT,                         // Casts 'price' to float
    'tags'     => [ Alter::ARRAY , Alter::CLEAN ],      // Splits and cleans 'tags'
    'meta'     => [ Alter::JSON_PARSE ],                // Parses 'meta' JSON string
    'url'      => [ Alter::URL , '/product/' ],         // Generates a product URL
    'discount' => [ Alter::CALL , fn($v) => $v * 0.9 ], // Applies a callable
    'rating'   => [ Alter::VALUE , 5 ],                 // Fixed value replacement
    'geo'      => [ Alter::NORMALIZE , [ Alter::HYDRATE , GeoCoordinates::class ] ],
    'name'     => [ Alter::TRIM , Alter::UPPERCASE , Alter::NORMALIZE ],
];

$document =
[
    'price'    => '29.90',
    'tags'     => 'a;;b;',
    'meta'     => '{"active":true}',
    'url'      => '123',
    'discount' => 100,
    'rating'   => 0,
    'geo'      => ['latitude' => null, 'longitude' => 2.5],
    'name'     => '  john doe  ',
];

$result = $this->alterProperty('price', $document, Alter::FLOAT);
// Returns the document with 'price' casted to float (29.9)
Return values
array<string|int, mixed>|object

The altered document (same reference type as input)

applyChainedAlterations()

Applies chained alterations to a property.

protected applyChainedAlterations(string $key, array<string|int, mixed>|object $document, array<string|int, mixed> $definitions[, Container|null $container = null ]) : array<string|int, mixed>|object

Each alteration in the chain is applied sequentially, with the output of one becoming the input of the next.

Parameters
$key : string

The property key

$document : array<string|int, mixed>|object

The document containing the property

$definitions : array<string|int, mixed>

The array of alteration definitions

$container : Container|null = null

An optional DI container reference.

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

DependencyException

If the dependency cannot be resolved by the container.

NotFoundException

If no entry is found for the given identifier in the container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

ReflectionException

If a class or property cannot be reflected (e.g. during hydration).

Return values
array<string|int, mixed>|object

$document The document with the altered property

applySingleAlteration()

Applies a single alteration (original behavior).

protected applySingleAlteration(string $key, array<string|int, mixed>|object $document, array<string|int, mixed> $definitions[, Container|null $container = null ]) : array<string|int, mixed>|object
Parameters
$key : string

The property key

$document : array<string|int, mixed>|object

The document containing the property

$definitions : array<string|int, mixed>

The alteration definition with parameters

$container : Container|null = null

An optional DI container reference.

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

DependencyException

If the dependency cannot be resolved by the container.

NotFoundException

If no entry is found for the given identifier in the container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

ReflectionException

If a class or property cannot be reflected (e.g. during hydration).

Return values
array<string|int, mixed>|object

The document with the altered property

executeAlteration()

Executes a specific alteration.

protected executeAlteration(string|Alter $alter, string $key, mixed $value, array<string|int, mixed> $params, array<string|int, mixed>|object &$document[, Container|null $container = null ][, bool &$modified = false ]) : mixed
Parameters
$alter : string|Alter

The alteration type

$key : string

The property key (for context)

$value : mixed

The value to alter

$params : array<string|int, mixed>

The alteration parameters

$document : array<string|int, mixed>|object

The full document (for context)

$container : Container|null = null

An optional DI container reference.

$modified : bool = false

Output parameter indicating if the value was modified

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

DependencyException

If the dependency cannot be resolved by the container.

NotFoundException

If no entry is found for the given identifier in the container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

ReflectionException

If a class or property cannot be reflected (e.g. during hydration).

Return values
mixed

The altered value

firstIsAlter()

Checks if a value is an Alter enum or an array starting with an Alter enum.

protected firstIsAlter(mixed $first) : bool
Parameters
$first : mixed

The value to check

Return values
bool

True if it's an Alter or array with Alter as first element

isChainedDefinition()

Detects if the definition represents chained alterations.

protected isChainedDefinition(array<string|int, mixed> $definitions) : bool

Chaining is detected when:

  • The first element is an Alter enum
  • AND the second element is either:
    • Another Alter enum (simple chaining)
    • An array whose first element is an Alter enum (chaining with params)
Parameters
$definitions : array<string|int, mixed>

The alteration definitions

Return values
bool

True if chaining is detected, false otherwise

On this page

Search results