Api: Add "manually" to Transformer "include" parameter.

Created on 17 Feb 2016  路  6Comments  路  Source: dingo/api

Hi, maybe I'm misunderstanding something but this is what I want (testing purposes).

class UserTransformer {
   protected $availableIncludes = ['posts'];

   public function transform(User $user)
   {
      return [
         'id' => (int) $user->id,
         'name' => $user->username
      ];
   }

   public function includePosts(User $user)
   {
      $posts = $user->posts;

      return $this->collection($posts, PostTransformer::class);
   {
}

TestController

url: /test

public function showUserWithPost()
{
   $user = User::find(1);

   // ADD "include" parameter in order to show users'posts.
   return $this->item($user, UserTransformer::class)->addIncludePost(); 
}

Thx.

Most helpful comment

You can use Fractal's $defaultIncludes to do this, either globally (defining it on the transformer) or at runtime by using setDefaultIncludes.

return $this->collection($posts, (new PostTransformer)->setDefaultIncludes(['posts']));

All 6 comments

You will have to manipulate the request to add your param at runtime since the function that parses the includes read directly from Request. I do think this is an area that should be updated to also support param passing.

request()->merge(['include' => 'posts']);

or inject Request and use

$request->merge(['include' => 'posts']);

@fbingha thx

Alternative solution.

In your Controller (in _showUserWithPost_ method), add $include = 'posts'; at the beginning. Note that you could include multiple models separating with a comma (ex: $include = 'posts,comments';)

And return :

        return $this->response->collection($items, new UserTransformer($fields), [], function($resource, $fractal){
            if(isset($include)) $fractal->parseIncludes($include);
        });

Note that you could of course set directly $fractal->parseIncludes('posts');. But as I use it to allow the client to include ressources through the query using $include = app('request')->get('include');, maybe this is more flexible.

With this approach, even if you include something that it is not available (cf. declared as available in your Transformer in _$availableIncludes_) you won't get this error :
Call to undefined method Illuminate\\Database\\Query\\Builder::comments()

You can use Fractal's $defaultIncludes to do this, either globally (defining it on the transformer) or at runtime by using setDefaultIncludes.

return $this->collection($posts, (new PostTransformer)->setDefaultIncludes(['posts']));

@YouHieng I am facing a problem when I am trying to use include in my url ? getting this error

Call to undefined method Illuminate\Database\Query\Builder::resource()

My controller code is here :

`$project = Project::all();
return $this->response->collection($project, ProjectTransformer::class, [], function($resource, $fractal){
if(isset($_GET['include'])){
$fractal->parseIncludes(explode(',', $_GET['include']));
}
});

In this issue I added my transformer code https://github.com/dingo/api/issues/1154

I just add this constructor to my transformer objects and then I can pass any of the available includes to the constructor:

    public function __construct($additionalIncludes = [])
    {
        if (!is_array($additionalIncludes)) {
            $additionalIncludes = [$additionalIncludes];
        }

        $diff = array_diff($additionalIncludes, $this->availableIncludes);
        if (count($diff) > 0) {
            throw new \InvalidArgumentException("Invalid include(s): ".implode(', ', $diff));
        }

        $this->setDefaultIncludes(array_merge(
            $this->defaultIncludes,
            $additionalIncludes
        ));
    }

Then I can use it like this:

return $this->response->collection($collection, new MyTransformer(['posts', 'whatever']))->setStatusCode(200);

Was this page helpful?
0 / 5 - 0 ratings