Support the ongoing development of Laravel.io →
Requests Eloquent
Last updated 6 months ago.
0

Have a look at Fractal: https://github.com/thephpleague/fractal

Last updated 6 months ago.
0

That looks really interesting. Thanks, I'll give that a shot.

Last updated 6 months ago.
0

Messing around with Fractal, and I got the basics to work. Just one further question - where's a good spot to initialize the Fractal manager in Laravel? Still pretty new to Laravel.

Last updated 6 months ago.
0

I have a very similar problem to you - I'm wanting to only return specific columns on many-to-many related objects for an API. After reading this thread I'm now also testing out Fractal, but I'm not having as much luck as you. The documentation doesn't contain a lot of examples so I'm struggling. Do you mind sharing what you've managed to do with Fractal?

In regards to intializing the Fractal manager, I was thinking in the base controller, but I'm also fairly new to Laravel so I say that's probably wrong.

Last updated 6 months ago.
0

I thought it looked ugly to have both HTML and JSON output in the same controller, so I split it up like this:

  • BaseController.php - the main class that extends the Controller class, various default view stuff goes here.
  • ContestBaseController - extends BaseController, contains only pure business logic, returns Contest objects.
  • ContestHtmlController - pretty much just a wrapper around ContestBaseController that gets Contest objects and returns Views.
  • ContestApiController - the same for the JSON API.

I initialize Fractal in BaseController.php for now:

  public function __construct()
  {
    $this->fractal = new Fractal\Manager();
  }

I wrote a ContestTransformer.php and stuck it in app/api, and added the app/api path to start/global.php.

<?php

use League\Fractal;

class ContestTransformer extends Fractal\TransformerAbstract
{

  public function transform(Contest $contest)
  {
    $ary = [
      'id'          => (int) $contest->id,
      'owner_id'    => (int) $contest->owner_id,
      'name'        => $contest->name,
      'is_public'   => (int) $contest->is_public,
      'is_finished' => (int) $contest->is_open,
      'start_date'  => $contest->start_date,
      'end_date'    => $contest->end_date,
      'players'     => $contest->players->toArray(),
      'events'      => [],
    ];

    // Massage events into proper format
    foreach($contest->event as $e) {
      // ...and this is where I quit last night
    }

    return $ary;
  }

}

/* EOF */

And then I can use it like this in ContestApiController.php:

  public function show($contest_id)
  {
    $contest = parent::show($contest_id);
    $resource = new Fractal\Resource\Item($contest, new ContestTransformer);

    return Response::json($this->fractal->createData($resource)->toArray());
  }

Still a bit messy, but I'm working on cleaning it up.

Last updated 6 months ago.
0

Oh, and I route it like this:

  Route::group(['prefix' => 'api/v0'], function() {
    Route::resource('contest', 'ContestApiController');
  });
Last updated 6 months ago.
0

Thank you very much for sharing.. I'm back on track now - very much appreciated.

Last updated 6 months ago.
0

One small update - I didn't like initializing Fractal in the constructor, so I added this method to the base controller:

protected function toJsonArray($resource)
{
  $fractal = new Fractal\Manager();
  return $fractal->createData($resource)->toArray();
}

And I call it in the API controllers:

public function show($contest_id)
{
  $contest = parent::show($contest_id);
  $resource = new Fractal\Resource\Item($contest, new ContestTransformer);
  return Response::json($this->toJsonArray($resource))
    ->setCallback(Input::get('callback'));
}
Last updated 6 months ago.
0

Instead of doing that, why not use dependency injection? Something like this:

use League\Fractal\Manager;

class ApiController extends Controller
{
    public function __construct(Manager $fractal)
    {
        $this->fractal = $fractal;
        $this->fractal->setRequestedScopes(explode(',', Input::get('include')));
    }
}

Then just make sure that all your API controllers extend ApiController instead of your usual BaseController. Makes things testable.

Last updated 6 months ago.
0

Can I do that with my current class setup? Still new to Laravel and "proper" PHP coding, but I'm certainly willing to learn new stuff.

Currently I have:

  • BaseController
  • ContestBaseController extends BaseController (handles all the CRUD verbs for the Contest resource, returns Contest objects)
  • ContestHtmlController extends ContestBaseController (calls the parent CRUD methods, then returns HTML views)
  • ContestApiController extends ContestBaseController (calls the parent CRUD methods, then returns JSON)
Last updated 6 months ago.
0

Don't know what your exact setup is, but I'd probably do it like that:

  • You got your BaseController and your ApiController (like I mentioned above) at the same level, both extending the basic Controller
  • Then you have all the controllers that return views for your application itself (what you call ContestHtmlController). All of them would extend your BaseController
  • The last part would be all your API controllers (ContestApiController), which would extend ApiController instead of BaseController
Last updated 6 months ago.
0

@jsvensson Did you figure out how to access the score data one level up?

Last updated 6 months ago.
0

For anyone bumping on this thread like me: Take a look at this post.

Especially this part:

public function products()
{
   return $this->belongsToMany('Product')
      ->withPivot('desired_column as desired_column');
      // this way you override aliasing the column to pivot_desired_column
      // thus avoid it being attached to the pivot model
}

You then access desired_column like this:

$model->products()->first()->desired_column //not first()->pivot->desired_column

The same is reflected in the JSON response which would solve the OPs problem.

Last updated 7 years ago.
0

Sign in to participate in this thread!

LaraJobs

Your banner here too?

jsvensson jsvensson Joined 13 Mar 2014

Moderators

We'd like to thank these amazing companies for supporting us

Your logo here?

Laravel.io

The Laravel portal for problem solving, knowledge sharing and community building.

© 2022 Laravel.io - All rights reserved.