Skip to main content
Version: Next ๐Ÿšง

Transformers

Definition & Principles#

Read 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
- {section-name}
- {container-name}
- UI
- API
- Transformers
- UserTransformer.php
- ...

Code Samples#

Reward Transformer with Country relation#

class ItemTransformer extends Transformer
{
protected $availableIncludes = [
'images',
];
protected $defaultIncludes = [
'roles',
];
public function transform(Item $item)
{
$response = [
'object' => $item->getResourceKey(),
'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,
'readable_created_at' => $item->created_at->diffForHumans(),
'readable_updated_at' => $item->updated_at->diffForHumans(),
];
// add more or modify data for Admins only
$response = $this->ifAdmin([
'real_id' => $item->id,
'deleted_at' => $item->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)#

$user = $this->getUser();
$this->transform($user, UserTransformer::class);
// more options are available

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:

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.

return $this->transform($rewards, ProductsTransformer::class)->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)

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. Look at the full examples above.

For more information about the Transformers read this.

Last updated on by Mohammad Alavi