Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel nested route model binding

Tags:

php

laravel

I am developing an API using Laravel for use with a mobile app and am having some issues with Route Model Binding on nested routes. The app will have a standalone sqlite db which will synchronise client journeys with the central server when network is available. For that reason, the PK's in the app cannot be used to access the records on the central server. Each user will have a unique username which will be stored on the central server in a table with the following columns:

  • user_id
  • username

The journey table will then have the following columns:

  • journey_id
  • user_id
  • user_journey_id

where the user_journey_id will be the PK of the journey record on the client device. The idea is that the clients can then access the api with something like: http://example.com/api/client/UNIQUE_USERNAME/journey/1234 to retrieve the journey from the central server.

I have the following resources setup:

Route::resource('client','ClientController');
Route::resource('client.journey','JourneyController');

and have setup route model binding successfully for the client as follows:

$router->bind('client', function($value, $route) {
    return \App\Client::where('username', '=', $value)->firstOrFail();
});

I'm having a bit of trouble with setting up the nested model binding as I require the client username in combination with the user_journey_id to retrieve the correct journey. Is there a way to do this with route model binding?
Or should this just be done in the controller with some like:

public function show(Client $client, $user_journey_id)
{
   ... // have logic here to get the journey.

This is how I do it currently but the route model binding would certainly make it a bit easier.

like image 431
Sonoman Avatar asked Jul 23 '15 08:07

Sonoman


1 Answers

Binding multiple URL parameters to models is certainly possible in Laravel, as is nested route model binding.

One caveat is that you'll need to specify the routes individually for these particular routes, rather than using Laravel's resource controllers as you've used in your example.

To register a route with more than one model binding you'll need to do something like this:

The route definition:

Route::get('/api/client/{user}/journey/{journey}', [
  'as' => 'client.journey', 
  'uses' => 'JourneyController@getJourney'
]);

The bind definitions:

$router->bind('user', function($value, $route) {
    return \App\Client::where('username', '=', $value)->firstOrFail();
});

$router->bind('journey', function($value, $route) {
    return \App\Journey::where('user_journey_id', '=', $value)->firstOrFail();
});

You'll then find that both models are being resolved and injected to the action method in the controller class:

public function show(User $user, Journey $journey)
{
     //do whatever you need to do here...

The only real drawback to this approach is the fact that you have to define routes manually instead of making use of Laravel's handy resource controllers. Of course, you could implement some of your own logical to make these kinds of routes easier for you to define.

like image 174
David Smith Avatar answered Oct 06 '22 17:10

David Smith