, (*1)
Custom Data transformers on top of League/Fractal library., (*2)
See Fractal documentation at http://fractal.thephpleague.com/, (*3)
Laravel 5.x/6.x
Install the saritasa/transformers
package:, (*4)
$ composer require saritasa/transformers
If you use Laravel 5.4 or less,
or 5.5+ with package discovery disabled,
add the TransformersServiceProvider service provider in config/app.php
:, (*5)
'providers' => array(
// ...
Saritasa\Transformers\TransformersServiceProvider::class,
)
This is required for localization to work properly., (*6)
Interface to unlink dependency from League/Fractal library.
Ensure, that every transformer implementation in this library has this interface., (*7)
Example:, (*8)
class AnotherTransformerWrapper implements IDataTransformer
{
public function __construct(IDataTransformer $nestedTransformer) { ... }
}
When you just need to convert model to JSON response via Dingo/Api methods,
and have no specific formatting requirements, you can just use
BaseTransformer. It calls Arrayable->toArray() method.
Thus, for Eloquent model result will consist of fields,
described as $visible and not $hidden.
Additionally converts fields, enumerated in $dates to ISO8061 format., (*9)
Example:, (*10)
class User extends \Illuminate\Database\Eloquent\Model {
// "full_name" is a property calculated from first_name and last_name
protected $visible = ['full_name', 'created_at'];
protected $hidden = ['email', 'password'];
protected $dates = ['created_at', 'updated_at', 'birthday'];
}
class UserController extends BaseApiController {
public function myProfile(): \Dingo\Api\Http\Response {
$user = $this->user(); // Returns Eloquent model
return $this->response->item($user, new BaseTransformer);
// Output will be JSON
// { "full_name": "Ivan Ivanov", "created_at": "2017-04-12T23:20:50.52Z" }
}
}
$user = User::find($userId);
Will output requested fields to result, regardless they described as
$hidden or $visible in Eloquent model, (*11)
Example:, (*12)
class User extends \Illuminate\Database\Eloquent\Model {
// "full_name" is a property calculated from first_name and last_name
protected $visible = ['full_name', 'created_at'];
protected $hidden = ['email', 'password'];
protected $dates = ['created_at', 'updated_at', 'birthday'];
}
class UserController extends BaseApiController {
public function myProfile(): \Dingo\Api\Http\Response {
$user = $this->user(); // Returns Eloquent model
$profileTransformer = new ObjectFieldsTransformer('first_name', 'last_name', 'email', 'birthday');
return $this->response->item($user, $profileTransformer);
// Output will be JSON
// { "first_name": "Ivan", "last_name": "Ivanov", "email": "ivanov@mail.ru", "birthday": "1985-04-12T00:00:00.00Z" }
}
}
$user = User::find($userId);
Apply multiple transformers in order of arguments;, (*13)
Example:, (*14)
class UserProfileTransformer extends CombineTransformer
{
public function __construct()
{
parent::__construct(
new PreloadUserAvatarTransformer(),
new PreloadUserSettingsTransformer()
);
}
}
Result will first apply ->toArray() method (which acts, respecting Eloquent's
$visible and $hidden fields), then limits output to selected fields.
This, hidden fields will not get in output, even if listed., (*15)
Example:, (*16)
class User extends \Illuminate\Database\Eloquent\Model {
protected $visible = ['full_name', 'created_at'];
protected $hidden = ['email', 'password'];
protected $dates = ['created_at', 'updated_at', 'birthday'];
}
class UserController extends BaseApiController {
public function myProfile(): \Dingo\Api\Http\Response {
$user = $this->user(); // Returns Eloquent model
$publicProfileTransformer = new LimitFieldsTransformer('full_name', 'birthday');
return $this->response->item($user, new BaseTransformer);
// Output will be JSON
// { "full_name": "Ivan Ivanov" }
}
}
$user = User::find($userId);
Exceptions
Should be thrown by class, implementing IDataTransformer, if it encounters data,
that cannot be transformed., (*17)
Example:, (*18)
function transform(Arrayable $data) {
if (!$data->author) {
new TransformException($this, "Author may not be empty");
}
// ...
}
Should be thrown, if your transformer expects model of a certain type,
but gets another class., (*19)
class UserTransformer extends BaseTransformer {
public function transform(Arrayable $model) {
if (!$model instanceof User) {
throw new TransformTypeMismatchException($this, User::class, get_class($model));
}
return transformUser($model);
}
private function transformUser(User $user) {
... // Handle strong-typed model
}
}
Utility Classes
DtoModel
Allows you to use pure DTO models instead of Eloquent, while using Fractal for
collection transformation., (*20)
Contributing
- Create fork, checkout it
- Develop locally as usual. Code must follow PSR-1, PSR-2 -
run PHP_CodeSniffer to ensure, that code follows style guides
-
Cover added functionality with unit tests and run PHPUnit to make sure, that all tests pass
- Update README.md to describe new or changed functionality
- Add changes description to CHANGES.md file. Use Semantic Versioning convention to determine next version number.
- When ready, create pull request
Make shortcuts
If you have GNU Make installed, you can use following shortcuts:, (*21)
-
make cs
(instead of php vendor/bin/phpcs
) -
run static code analysis with PHP_CodeSniffer
to check code style
-
make csfix
(instead of php vendor/bin/phpcbf
) -
fix code style violations with PHP_CodeSniffer
automatically, where possible (ex. PSR-2 code formatting violations)
-
make test
(instead of php vendor/bin/phpunit
) -
run tests with PHPUnit
-
make install
- instead of composer install
-
make all
or just make
without parameters -
invokes described above install, cs, test tasks sequentially -
project will be assembled, checked with linter and tested with one single command
Resources