Skip to main content
Version: 9.x

Transformers

Definition & Principles#

Read from the Porto SAP Documentation (#Transformers).

Rules#

  • All API responses MUST be formatted via a Transformer.

  • Every Transformer SHOULD extend from App\Ship\Parents\Transformers\Transformer.

  • Each Transformer MUST have a transform() function.

Folder Structure#

 - app    - Containers        - {container-name}            - UI                - API                    - Transformers                        - UserTransformer.php                        - ...

Code Samples#

Reward Transformer with Country relation:

<?php
namespace App\Containers\Item\UI\API\Transformers;
use App\Containers\Item\Models\Item;use App\Ship\Parents\Transformers\Transformer;
class ItemTransformer extends Transformer{
    protected $availableIncludes = [        'images',    ];
    protected $defaultIncludes = [        'roles',    ];
    public function transform(Item $item)    {        $response = [            'object'      => 'Item',            'id'          => $item->getHashedKey(),            'name'        => $item->name,            'description' => $item->description,            'price'       => (float)$item->price,            'weight'      => (float)$item->weight,            'created_at'  => $item->created_at,            'updated_at'  => $item->updated_at,        ];
        // add more or modify data for Admins only        $response = $this->ifAdmin([            'real_id'    => $user->id,            'deleted_at' => $user->deleted_at,        ], $response);
        return $response;    }
    public function includeImages(Item $item)    {        return $this->collection($item->images, new ItemImageTransformer());    }
    public function includeRoles(User $user)    {        return $this->collection($user->roles, new RoleTransformer());    }}

Usage from Controller (Single Item)

<?php
// getting any Model$user = $this->getUser();
// building the response with the transformer of the Model$this->response->item($user, new UserTransformer());
// in case of collection of data$this->response->collection($user, new UserTransformer());
// in case of Array$this->response->array([    'custom_field'  =>  'whatever',    'email'         =>  $user->email,]);
// more options are available

Usage from Controller (Multiple Items/Collection)

<?php
// getting many Models Paginated$rewards = $this->getRewards();
// building the response with the transformer of the Modelreturn $this->response->paginator($rewards, new RewardTransformer());

Relationships (include)#

Loading relationships in Transformer (calling other Transformers):

This can be done in 2 ways:

  1. By the User, he can specify what relations to return in response.

  2. By the Developer, define what relations to include at run time.

From Front-end#

You can request data with their relationships directly from the API call using include=tags,user but first the Transformer need to have the availableIncludes defined with their functions like this:

<?php
namespace App\Containers\Account\UI\API\Transformers;
use App\Ship\Parents\Transformers\Transformer;use App\Containers\Account\Models\Account;use App\Containers\Tag\Transformers\TagTransformer;use App\Containers\User\Transformers\UserTransformer;
class AccountTransformer extends Transformer{    protected $availableIncludes = [        'tags',        'user',    ];
    public function transform(Account $account)    {        return [            'id'       => (int)$account->id,            'url'      => $account->url,            'username' => $account->username,            'secret'   => $account->secret,            'note'     => $account->note,        ];    }
    public function includeTags(Account $account)    {        // use collection with `multi` relationship        return $this->collection($account->tags, new TagTransformer());    }
    public function includeUser(Account $account)    {        // use `item` with single relationship        return $this->item($account->user, new UserTransformer());    }
}

Now to get the Tags with the response when Accounts are requested pass the ?include=tags parameter with the [GET] request.

To get Tags with User use the comma separator: ?include=tags,user.

From Back-end#

From the controller you can dynamically set the DefaultInclude using (setDefaultIncludes) anytime you want.

<?php
return $this->response->paginator($rewards, (new ProductsTransformer())->setDefaultIncludes(['tags']));

You need to have includeTags function defined on the transformer. Look at the full examples above.

If you want to include a relation with every response from this transformer you can define the relation directly in the transformer on ($defaultIncludes)

<?php
protected $availableIncludes = [    'users',];
protected $defaultIncludes = [    'tags',];
// ..

You need to have includeUser and includeTags functions defined on the transformer. Look at the full examples above.

Transformer Available helper functions:#

  • user() : returns current authenticated user object.

  • ifAdmin($adminResponse, $clientResponse) : merges normal client response with the admin extra or modified results, when current authenticated user is Admin.

For more information about the Transformers read this.