Transformers allow you to process XML data before it’s returned to your application. Unlike casts which convert data into specific classes, transformers modify, filter, or restructure the data itself.Use transformers to:
Filter arrays of elements based on criteria
Ensure data is always in a specific format (e.g., always an array)
All transformers must implement the Transformer interface with a single static apply() method:
namespace Flowgistics\XML\Transformers;interface Transformer{ /** * Apply is invoked before the final output is sent to the user. * * @param mixed $data - the xml data * @return mixed */ public static function apply(mixed $data): mixed;}
The package includes an ArrayTransformer that ensures data is always wrapped in an array, even if there’s only one element:
use Flowgistics\XML\XML;// Using the built-in alias$xml = XML::import('notes.xml') ->expect('note')->as('array') ->get();// Equivalent to:$xml = XML::import('notes.xml') ->transform('note')->with(ArrayTransformer::class) ->get();// $xml->note is always an array, even with one element
The expect() method is an alias for transform() - they work identically.
For transformers that need configuration, you can use static properties or constants:
class LimitTransformer implements Transformer{ public static int $limit = 10; public static function apply(mixed $data): array { $items = is_array($data) ? $data : [$data]; return array_slice($items, 0, self::$limit); }}// Configure before usingLimitTransformer::$limit = 5;$xml = XML::import('notes.xml') ->transform('note')->with(LimitTransformer::class) ->get();// Only first 5 notes are returned
You can apply multiple transformers to the same element:
$xml = XML::import('notes.xml') ->transform('note')->with(CompletedNoteFilter::class) ->transform('note')->with(ArrayTransformer::class) ->get();// First filters completed notes, then ensures result is an array
Transformers are applied in the order you chain them. Make sure the output of one transformer is compatible with the input expected by the next.
Transformers and casts can be used together. The order matters:
// Transform first, then cast$xml = XML::import('notes.xml') ->transform('note')->with(CompletedNoteFilter::class) ->cast('note')->to(Note::class) ->get();// Filters notes, then casts remaining ones to Note models// Cast first, then transform$xml = XML::import('notes.xml') ->cast('note')->to(Note::class) ->expect('note')->as('array') ->get();// Casts to models, then ensures it's an array of models
Filter before casting when you want to reduce the number of objects created. Cast before transforming when your transformer needs to work with class instances.
XML elements might be a single item or an array. Write transformers that handle both:
public static function apply(mixed $data): array{ $items = is_array($data) ? $data : [$data]; // Process $items return $processed;}
Preserve data types when possible
If you receive an array of XMLElement objects, try to return the same type:
public static function apply(mixed $data): mixed{ // Preserve the original structure return array_filter($data, function ($item) { return $item->isValid(); });}
Document expected input and output
Use PHPDoc to make it clear what your transformer expects and returns: