surgiie / transformer
A data transforming/formatting package for php.
Installs: 22 891
Dependents: 1
Suggesters: 0
Security: 0
Stars: 127
Watchers: 2
Forks: 6
Open Issues: 0
pkg:composer/surgiie/transformer
Requires
- php: ^8.2.0
- illuminate/http: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
- illuminate/validation: ^11.0|^12.0
Requires (Dev)
- laravel/pint: ^1.16
- pestphp/pest: ^2.34
- phpstan/phpstan: ^2.0
- symfony/var-dumper: ^7.0
README
A PHP package for transforming data and values with a simple, expressive syntax. Powered by Laravel framework components.
Installation
composer require surgiie/transformer
Usage
To use the package, pass your data and an array of callable functions that your data should be passed through:
<?php use Closure; use Illuminate\Support\Stringable; // Example functions available at runtime: function to_carbon($value) { return new Carbon\Carbon($value); } function only_numbers($value) { return preg_replace("/[^0-9]/",'',$value); } $input = [ 'first_name'=>' jim ', 'last_name'=>' thompson', 'address' => '123 some street', 'phone_number'=>'123-456-7890', 'date_of_birth'=>"1991-05-01", ]; $transformers = [ 'first_name'=>'trim|ucfirst', 'last_name'=>'trim|ucfirst', 'phone_number'=>'only_numbers', // more on object values and method delegation below 'address' => [Stringable::class, '->after:123 ', '->toString'], 'date_of_birth'=>'to_carbon|->format:m/d/y', ]; $transformer = new DataTransformer($input, $transformers); $newData = $transformer->transform(); // Returns: // [ // "first_name" => "Jim", // "last_name" => "Thompson", // "phone_number" => "1234567890", // "address"=> "some street", // "date_of_birth" => "05/01/91", // ]
The syntax is similar to Laravel's validation syntax, as this package is powered by the same framework components.
Passing Arguments
Pass arguments to your transformer functions using the <function>:<comma-delimited-list> syntax:
<?php $transformers = [ 'example'=>'your_function:arg1,arg2', ];
Specifying Value Argument Position
By default, the value being transformed is passed as the first argument to your function, followed by any additional arguments. If your function expects the value in a different position, use the :value: placeholder:
<?php $input = ['phone_number'=>'123-456-3235']; $transformers = [ 'example'=>'preg_replace:/[^0-9]/,,:value:', ]; $transformer = new DataTransformer($input, $transformers); $transformer->transform();
Casting Arguments
When passing arguments to transformer functions, you may encounter runtime errors due to type hints. Since arguments are specified as strings, you can cast them to specific types using the @<type> suffix:
<?php function example_function(int $value) { return $value + 1; } $input = ['example' => '1']; // This will throw an error because '1' is a string, not an integer $transformers = [ 'example' => 'example_function:1', ]; // Fix by casting the argument to an integer $transformers = [ 'example' => 'example_function:1@int', ];
Available Casting Types
int- Integerstr- Stringfloat- Floatbool- Booleanarray- Arrayobject- Object
Note: For complex type casting needs, use a Closure or Surgiie\Transformer\Contracts\Transformable class (see below).
Optional Transformation
To transform a value only when it's not null or blank, use the ? character in your transformation chain. This is typically placed at the start:
<?php $input = ['first_name'=>null]; $transformers = [ 'example'=>'?|function_one|function_two', ]; $transformer = new DataTransformer($input, $transformers); $transformer->transform();
Note: This uses Laravel's blank() helper to determine empty values. For complex conditional logic, use a Closure or \Surgiie\Transformer\Contracts\Transformable class with the exit callback.
Closures and Transformable Classes
Use closures for custom transformation logic:
<?php $input = ['first_name'=>' Bob']; $transformers = [ 'first_name'=>['trim', function ($value) { // modify the value return $value; }], ]; $transformer = new DataTransformer($input, $transformers); $transformer->transform();
Alternatively, implement the Surgiie\Transformer\Contracts\Transformable contract for reusable transformation classes:
<?php use Surgiie\Transformer\DataTransformer; use Surgiie\Transformer\Contracts\Transformable; class TransformValue implements Transformable { public function transform($value, Closure $exit) { // quit transforming value(s) if($someCondition){ $exit(); } // or modify the value $value = "Changed"; return $value; } } $input = ['first_name' => ' Bob']; $transformers = [ 'first_name' => ['trim', new TransformValue], ]; $transformer = new DataTransformer($input, $transformers); $transformer->transform();
Nested Array Data
Transform nested array data using dot notation:
<?php $input = [ 'contact_info'=>[ 'first_name'=>' jim ', 'last_name'=>' thompson', 'phone_number'=>'123-456-7890', 'address'=>'123 some lane.' ] ]; $transformers = [ 'contact_info.first_name'=>'trim|ucwords', 'contact_info.last_name'=>'trim|ucwords', 'contact_info.phone_number'=>'preg_replace:/[^0-9]/,,:value:', 'contact_info.address'=>[function ($address) { return 'Address Is: '.$address; }], ]; $transformer = new DataTransformer($input, $transformers); $transformer->transform();
Wildcards
Apply transformers to multiple keys using wildcard patterns:
<?php $input = [ 'first_name'=>' jim ', 'last_name'=>' thompson', 'ignored'=>' i-will-be-the-same' ]; $transformers = [ // apply to all keys that contain "name" '*name*'=>'trim|ucwords', ]; $transformer = new DataTransformer($input, $transformers); $transformer->transform();
Object Method Delegation
When a value is transformed into an object instance, you can chain method calls using the -><methodName>:args syntax:
<?php use Closure; class Example { protected $value; public function __construct($value) { $this->value = $value; } public function concat($string) { return $this->value . $string; } } function example($value) { return new Example($value); } $input = [ 'string'=>"Foo", ]; $transformers = [ 'string'=>'example|->concat:Bar', ];
You can also instantiate classes directly using class constants (the value will be passed to the constructor):
<?php $input = [ 'string'=>"Foo", ]; $transformers = [ 'string'=>[Example::class, '->concat:Bar'], ];
Guard Layer
Add a security layer to control which functions can be executed during transformation. Register a guard callback that returns true to allow a function to execute:
<?php use Surgiie\Transformer\DataTransformer; use Surgiie\Transformer\Transformer; // The guard receives the function name and the input key being processed Transformer::guard(function($method, $key) { // Only allow 'trim' to be executed return in_array($method, ['trim']); }); $input = [ 'first_name'=>' jim ', ]; $transformers = [ 'first_name'=>'trim|ucwords', ]; $transformer = new DataTransformer($input, $transformers); // Throws ExecutionNotAllowedException when attempting to execute 'ucwords' $transformer->transform();
Transforming Single Values
Transform individual values using the Transformer class:
<?php use Surgiie\Transformer\Transformer; $transformer = new Transformer(" uncle bob ", ['trim', 'ucwords']); $transformer->transform(); // returns "Uncle Bob"
Using the Transformer Trait
Transform data on-the-fly in your classes by using the \Surgiie\Transformer\Concerns\UsesTransformer trait:
<?php use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Surgiie\Transformer\Concerns\UsesTransformer; class ExampleController extends Controller { use UsesTransformer; public function store(Request $request) { //... // transform a single value $newValue = $this->transform(" example ", ['trim|ucwords']); // or transform an array of data $newData = $this->transformData(['example'=> 'data '], ["example"=>'trim|ucwords']); } }
Using the Request Macro
Transform request data using the transform() macro available on Illuminate\Http\Request instances:
public function store(Request $request) { // Using data from the request object (i.e. `$request->all()`) $transformedData = $request->transform([ 'first_name' => ['strtoupper'], ]); // $transformedData['first_name'] will be all uppercase // all other data will be included from the request // You can also customize the input that is transformed, // in this case $transformedData will only have the `first_name` key. $transformedData = $request->transform($request->only(['first_name']), [ 'first_name' => ['strtoupper'], ]); }
When calling on a FormRequest object, it uses the validated() function to retrieve the input data. Note that this requires the data you are targeting to be defined as a validation rule in your form request's rules function, otherwise the data will be omitted from transformation.
Disabling Auto-Discovery
Laravel automatically registers the package service provider. If you want to disable auto-discovery, add the following to your composer.json:
"extra": { "laravel": { "dont-discover": [ "surgiie/transformer" ] } }
Contributing
Contributions are welcome! You can contribute through:
- Discussions - Share ideas and ask questions
- Issues - Report bugs or request features
- Pull Requests - Submit code improvements