8

I've got the API working using the standard process, but I want to remove the data namespace from the JSON output. I see I need to implement ArraySerializer, I have been through the Fractal docs, but I can't work out where I need to added it in Laravel 5.2

I found this answer but I'm just getting the same output at the line of code I commented out:

class TrackController extends ApiController
{
    public function index()
    {
        $tracks = Track::all();
        //return $this->respondWithCollection($tracks, new TrackTransformer);
        // Same response as the commented out line above
        $response = new \League\Fractal\Resource\Collection($tracks, new TrackTransformer);
        $manager = new \League\Fractal\Manager();
        $manager->setSerializer(new \League\Fractal\Serializer\ArraySerializer());
        return response()->json($manager->createData($response)->toArray());
    }

    public function show($id)
    {
        $track = Track::find($id);
        return $this->respondWithItem($track, new TrackTransformer);
    }
}

Also, I'm implementing this on a specific controller, even if I got this working, where do I add the code/class so I can get ArraySerializer output for all my controllers?

I've posted this on Github if that helps.

Thomas Bormans
  • 5,156
  • 6
  • 34
  • 51
Jack Barham
  • 3,197
  • 10
  • 41
  • 62
  • first impression, i think you should move `$response = new \League\Fractal\Resource\Collection($tracks, new TrackTransformer);` after you set serializer – terry low Mar 28 '16 at 13:26
  • 1
    Where would I move it to? – Jack Barham Mar 28 '16 at 13:30
  • 1
    `$manager = new \League\Fractal\Manager(); $manager->setSerializer(new \League\Fractal\Serializer\ArraySerializer()); $response = new \League\Fractal\Resource\Collection($tracks, new TrackTransformer); ` – terry low Mar 28 '16 at 13:32
  • Thanks for the response. however, I'm still getting the same result with `data`. – Jack Barham Mar 28 '16 at 13:38
  • 1
    when you have use ArraySerializer u can set you key this way `$response = new \League\Fractal\Resource\Collection($tracks, new TrackTransformer, 'MYKEY')` without specify a key, fractal will automatically fall back to use the `data` key – terry low Mar 28 '16 at 13:45
  • Thanks, thats worked - Now I need to make it work for included items :) – Jack Barham Mar 28 '16 at 13:51
  • for your information, there is a package call `Cyvelnet/laravel5-fractal ` may save you some times in making data tranformation – terry low Mar 28 '16 at 13:51
  • Thanks, looks good - Im going try it now. – Jack Barham Mar 28 '16 at 14:45
  • @terrylow It doesn't work for me, gives error `{ "message": "The Response content must be a string or object implementing __toString(), \"object\" given.", "status_code": 500 }` and this is my code `return new \League\Fractal\Resource\Collection($request->user->friends, new FriendTransformer(), 'friends');` – Rohit Khatri Sep 17 '16 at 11:00
  • @RohitKhatri i belive you have forgotten to cast it to array or to json `$manager->createData($response)->toArray()` – terry low Sep 17 '16 at 14:50
  • @terrylow can you please give me a working example? – Rohit Khatri Sep 17 '16 at 15:24
  • @terrylow ok somehow I got it working, but still getting the `data` key instead `friends`, here's my new code `$resource = (new \League\Fractal\Resource\Collection($request->user->friends, new FriendTransformer(), 'friends')); $manager = new Manager(); return $manager->createData($resource)->toArray();` can you tell me what I'm doing wrong? – Rohit Khatri Sep 17 '16 at 15:27
  • @RohitKhatri please add this line `$manager->setSerializer(new \League\Fractal\Serializer\ArraySerializer());` before you instantial fractal manager, because fractal uses DataArraySerializer which will uses data namespace – terry low Sep 17 '16 at 15:29
  • It's working now, and can you tell me how should I implement it so I don't have to write these lines again and again instead `$this->response->collection($collection, new Transformer, 'key')` ? Thanks – Rohit Khatri Sep 17 '16 at 15:34
  • if you prefer not to use 3rd party packages, then add a new method response() to your base Controller class, then instantial your fractal manager in response method and return a initialized manager – terry low Sep 17 '16 at 15:59
  • @terrylow Thank you so much, you saved my time. – Rohit Khatri Sep 17 '16 at 16:37

2 Answers2

6

You need create own MySerializer extends of DataArraySerializer and use it instead of default. Default DataArraySerializer have three methods and in each of them need change return values to this:

use League\Fractal\Serializer\DataArraySerializer;

class MySerializer extends DataArraySerializer
{
    /**
     * Serialize a collection.
     *
     * @param string $resourceKey
     * @param array  $data
     *
     * @return array
     */
    public function collection($resourceKey, array $data)
    {
        return $data;
    }

    /**
     * Serialize an item.
     *
     * @param string $resourceKey
     * @param array  $data
     *
     * @return array
     */
    public function item($resourceKey, array $data)
    {
        return $data;
    }

    /**
     * Serialize null resource.
     *
     * @return array
     */
    public function null()
    {
        return [];
    }

}

So you change the behavior of the serialize mechanism and get result as you wish.

Stanislav
  • 923
  • 1
  • 11
  • 28
4

If you use spatie/laravel-fractal package or spatie/fractalistic, then you can remove the data key from the results by using the Spatie array serializer Spatie\Fractalistic\ArraySerializer() instead of the Fractal's default serializer.

You can use is like this:

Fractal::create()
   ->collection($books)
   ->transformWith(function($book) { return ['id' => $book['id']];})
   ->serializeWith(new \Spatie\Fractalistic\ArraySerializer())
   ->toArray();

This will return..

[
    ['id' => 1],
    ['id' => 2]
]

Instead of..

[
    'data' => [
        ['id' => 1],
        ['id' => 2]
    ]
]

Or, if you want to use the Spatie serializer globally, add it in the config/fractal.php file like this:

<?php

return [
    /*
     * The default serializer to be used when performing a transformation. It
     * may be left empty to use Fractal's default one. This can either be a
     * string or a League\Fractal\Serializer\SerializerAbstract subclass.
     */
    'default_serializer' => new Spatie\Fractalistic\ArraySerializer(),
    .
    .
    .
];

More info, see: Using a serializer

Amr
  • 4,809
  • 6
  • 46
  • 60