Transformers contain the business logic for changing a model's format to whatever you need for the output, whether that's HTML, Datatable, or JSON API. Decoupling this logic from the model allows for unobtrusive schema changes, a reliable place for housing formatting logic, and data formatting operations outside of views (for example, converting a date, or performing translations).
- Transformers, like models, could be used throughout the application, and should be stored in
app/Transformers
- Transformer class naming should be named after your model, for example
UserTransformer
Transformation blueprints can be set on the Transformer class as properties, and should be an array of field names belonging to your Model. Create your transformer, remembering to extend the BaseTransformer
class:
// app/Transformers/UserTransformer.php
namespace App\Transformers;
class UserTransformer extends BaseTransformer
{
/**
* Simple list of Users by their ID (suitable for a dropdown menu)
*/
protected $listFormat = ['id', 'email'];
}
And that's it, it's ready to use! You simply pass your Model (or many Models) to your Transformer and specify the format (in our example's case, list
), and the transformer will take care of the rest.
Passing a Single Model
$user = User::where('email', '[email protected]')->firstOrFail();
$list = UserTransformer::transform($user)->into('list'); // array:2 ['id' => 1, 'email' => '[email protected]']
Passing a Collection of Models
$users = User::where('status', 'active')->get();
$list = UserTransformer::transform($users)->into('list');
/* Outputs:
array:x [
['id' => 1, 'email' => '[email protected]'],
['id' => 2, 'email' => '[email protected]'],
...
]
*/
Adding A New Formatter
You can easily add a new formatter to use elsewhere in the application by setting a new property on the Transformer class - you will need to name it using camelCase
and add the word Formatter
to the end:
// UserTransformer.php
protected $tableFormatter = ['id', 'email', 'active', 'company.name|cname'];
// Controller or elsewhere
$users = User::where('status', 'active')->get();
$list = UserTransformer::transform($users)->into('table');
/* Outputs:
array:x [
['id' => 1, 'email' => '[email protected]', 'status' => 'active', 'cname' => 'Company'],
['id' => 2, 'email' => '[email protected]', 'status' => 'active', 'cname' => 'Company'],
...
]
*/
Note in the table
transformer blueprint, we are accessing the company
relation of the User
model to get the company name
(equivalent to $user->company->name
- make sure you eager load!!). We are also providing an alias for the field after the pipe |
operator (if not provided, the key in the outputted array would be company.name
).
You can define a transformer in a method if you need further control or additional logic (in the below example, formatting a timestamp field ready for a view and translating an attribute):
// app/Transformers/UserTransformer.php
namespace App\Transformers;
use App\Model\User;
class UserTransformer extends BaseTransformer
{
/**
* Transformer for Datatable
*/
public function datatableFormat(User $user)
{
return [
'id' => $user->id,
'email' => $user->email,
'company_name' => $user->company->name,
'status' => trans($user->status),
'created_at' => $user->created_at->toDayDateTimeString()
];
}
}
You call the transformation in exactly the same way as before:
$users = User::with('company')->where('status', 'active')->get();
$list = UserTransformer::transform($users)->into('table');
/* Outputs:
array:x [
['id' => 1, 'email' => '[email protected]', 'company_name' => 'Airangel', 'status' => 'Active', 'created_at' => 'Thu, Mar 16, 2017 3:39 PM'],
['id' => 2, 'email' => '[email protected]', 'company_name' => 'Airangel', 'status' => 'Active', 'created_at' => 'Thu, Mar 16, 2017 3:39 PM'],
...
]
*/
If you choose not to define any properties or methods, the Transformer will default to calling toArray
on the Model.