4

I've found good information on handling nested resource controllers and passing multiple constraints but seem to find nothing on this specific problem (probably cause I'm thinking about it all wrong!).

If I want to create the following in my API

  • /cars (show all cars)
  • /cars/1 (show carId = 1)
  • /cars/1/performance (show performance for carId=1)
  • /cars/1/performance/parts (show performance of parts for carId=1)
  • /cars/1/performance/parts/1 (show performance of partId=1 for carId=1)
  • /cars/performance (show performance of all cars)
  • /cars/performance/parts
  • /parts
  • /parts/1 etc... (same for parts as cars above)

would I have to create routes and controllers for most of them in this fashion

Route::group(array('prefix' => 'myAwesomeCarApi'), function()
{
    Route::resource('cars', 'CarsController'); 
    Route::resource('cars/performance', 'CarsPerController');
    Route::resource('cars/performance/parts', 'CarsPerPartsController');
    Route::resource('cars.performance/parts', 'CarsPerPartsController');
    Route::resource('parts', 'PartsController');
    Route::resource('parts/performance', 'PartsPerController');
    etc...
});

or is there some trickery I'm missing for creating dynamic controllers e.g only 3 (CarController, PartsController, PerformanceController) and handling the different routes in the code?

1 Answer 1

5

I think what you’re looking for are nested resource controllers. These allow you to build routes like /car/1/part/1. This route would map to the action CarPartController@show and pass two parameters: the car ID and the part ID.

In terms of performance of cars/parts, I would say this is kinda like the “show” method (in that performance is not an entity in itself) so would create another method in your controllers like this:

class CarPartController extends Controller {

    public function show($carId, $partId)
    {
        // Show specified part for specified car
    }

    public function performance($carId, $partId)
    {
        // Show the performance for specified part on specified car
    }

}

Then your routes would look like this:

Route::get('car/{car}/performance', 'CarController@performance');
Route::get('car/{car}/part/{part}/performance', 'CarPartController@performance');

Route::resource('car', 'CarController');
Route::resource('car/{car}/part', 'CarPartController');

According to the Laravel documentation, non-resource methods have to be defined before the resource controllers.

You could also take this approach one step further and implement route–model binding, so that instances of your Car and Part model are injected into your controller actions rather than IDs:

Route::model('car', 'Car');
Route::model('part', 'Part');

And an example controller action:

public function performance(Car $car, Part $part)
{
    // Show performance for specified part on specified car
}

Hope this helps.

Sign up to request clarification or add additional context in comments.

13 Comments

Thanks that's great, excactly what I needed. When you're first starting out using routes, mvc and REST api there are a lot of concepts to get your head around so applying them can be confusing sometimes!
I guess my followup question is how or whether this fits in with REST principles because once I start using Route::get('car/{car}/performance', 'CarController@performance'); am I not then moving away from the strictly GET/PUT/DELETE etc. REST principles
You don't need to add the segment that contains the wildcard, you can write it like this: Route::resource('car.part', 'CarPartController');
@cdarken That’s not a wildcard. That’s a route parameter.
@MartinBean you are right. And that parameter will be generated automatically if you use the dot.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.