I am having an issue with route model binding on my dingo (dev-master w/ L5.3 support) specific routes. On my Laravel web routes it works fine and returns the model with the correct data. It also works on Laravel 5.2.
routes/api.php
$api->get('users/{user}', ['as' => 'users.show', 'uses' => 'UserController@show']);
UserController.php
public function show(User $user)
{
dd($user);
return $this->response->item($user, new UserTransformer);
}
The $user object is empty. I have tried with another controller too with the same results.
I can only get it to work by using first(), which defeats the purpose of model binding.
public function show(User $user)
{
$data = $user->first();
return $this->response->item($data, new UserTransformer);
}
+1
Add bindings middleware to your route as such:
$api->group(['middleware' => 'bindings'], function($api){
$api->get('users/{user}', ['as' => 'users.show', 'uses' => 'UserController@show']);
});
Thanks @az-iar that works well.
@az-iar Oh, thanks, new to me.
+1 for this working well. Thanks.
For those who find this solution not working - check your Kernel.php, $routeMiddleware should contain:
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
Yes this bindings route middleware is there and still I am not able to get model object.
Its working for other controllers,
I am using laravel 5.3
@RushabhJoshi Check your route parameter for the model if matches. For example: $api->get('users/{users}') vs User model (plural vs singular). If you dump your parameter, do you get the model's ID?
My route is api/products/{product}. it listen to get request and My argument with typehint Product $product
@RushabhJoshi What is the difference between your ProjectController and others? You said the problem is only with this controller.
I see no difference both are resource controller one is only dedicated for api purpose.
Does your api middleware group have assigned 'bindings'? In app/Http/Kernel.php:
// For web routes
'web' => [
...
\Illuminate\Routing\Middleware\SubstituteBindings::class
],
// For api routes
'api' => [
'throttle:60,1',
'bindings'
],
Yes, I haven't changed any defaults
Send here you Kernel, Controller and related routes please.
Kernel.php
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
protected $commands = [
//
];
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')
// ->hourly();
}
protected function commands()
{
require base_path('routes/console.php');
}
}
Controller
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Model\Product;
/**
* @Resource("products", only={"index", "show"}, names={"index"="api.products.index", "show"="api.products.show"})
* @Controller(prefix="api")
* @Middleware("auth.token")
*/
class ProductController extends Controller
{
// here can't get product from route binding
public function show($id)
{
$product = Product::findOrFail($id);
$product->load('images', 'keywords', 'gardenTypes', 'partnerProducts', 'details', 'recommendedProducts');
return response()->json($product);
}
}
@RushabhJoshi Http Kernel, not console Kernel. If you run the route:list command, do you have there /api/products/{product} route?
Sorry
My http kernel is
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'category' => \App\Http\Middleware\CheckCategroy::class,
'admin' => \App\Http\Middleware\CheckAdminUser::class,
'auth.token' => \App\Http\Middleware\ApiAuthorization::class,
];
}
and my route list
| | GET|HEAD | api/categories | api.categories.index | App\Http\Controllers\Api\CategoryController@index | auth.token |
| | GET|HEAD | api/products | api.products.index | App\Http\Controllers\Api\ProductController@index | auth.token |
| | GET|HEAD | api/products/{product} | api.products.show | App\Http\Controllers\Api\ProductController@show | auth.token
I also realise now do I need web middleware?
@RushabhJoshi no, you don't have to define the web middleware if using only api. If you pass the product model into the method, what do you get when you dump it?
public function show(Product $product)
$product->id?this is giving me null
@RushabhJoshi There may be a problem in that annotation definition. Dingo has his own route, so if you want to define your api routes, you have to use Dingo's router like this (RouteServiceProvider):
$api = app('Dingo\Api\Routing\Router');
$api->version('v1', function ($api) {
$api->group([
'namespace' => $this->namespace,
'middleware' => 'api',
], function ($api) {
// your routes
});
});
If you execute the command route:list, these are Laravel's routes. For Dingo it is api:routes.
Check this too.
I think its laravel problem I should report them
I'm having the same issue moving the models from App to Package. Still searching for a solution.
-update: I forgot to assign the correct middleware to the route.
So my route now looks like this:
| GET|HEAD | theme/{theme}/setting/{setting} | Bespired\Dibs\Http\Controllers\Studio\ThemeController@setting | web |
meaning it has 'web' that holds the middleware
\Illuminate\Routing\Middleware\SubstituteBindings::class
I don't think auth.token is enough middleware to do the model binding.
Any solutions?
This change should be on the Upgrade Guide from 5.2 -> 5.3!
I have same @RushabhJoshi problem. Any solution. I'm using laravel 5.4.
Seems that it does work on route group. but when I added binding middleware to each sub routes of a group all things worked.
I found that must to add bindings middleware in the same route group that added auth.api middleware instead adding it to each sub routes separately.
means like this :
$api->group(['middleware' => 'api.auth|bindings'], function ($api) {
});
Anyone got the solution. This returns null:
`
$api->group(['middleware' => 'bindings'], function ($api) {
$ctrlPrefix = "\App\Api\V1\Controllers";
$api->resource('Institute', $ctrlPrefix.'\InstituteController');
});
This is my controller:
{
return response()->json($institute);
}
`
I'm on 5.4 please help.
Well I got the same issue...
I think the documentation about this part could be improvements.
Most of the people think, naturally, that using App\Providers\RouteServiceProvider::mapApiRoutes is the good approach for it. But it's a trap.
for information in my provider I do this:
protected function mapApiRoutes()
{
$api = app('api.router');
require_once base_path('routes/api.php');
}
and in my api.php file
<?php
use Dingo\Api\Routing\Router;
/** @var Router $api */
$api->version(
'v1',
['middleware' => [
'api',
'api.auth',
'jwt.refresh',
]],
function(Router $api)
{
// route declaration
}
);
What I would expect is to have the same kind (perhaps a macro in router) of behaviour like in my provider
Route::api->middleware('api')->prefix('api')->group(base_path('routes/web.php')) ;
So I don't need the prefix in the config file now and it make everybody confortable ;)
up i've the same problem in laravel 5.8
Special thanks to @az-iar , add bindings to middleware solved my problem.
With laravel 8, I see bindings middleware exists in route but I dont know why I still add in route middleware:
```
protected $middlewareGroups = [
'web' => [
App\Http\MiddlewareEncryptCookies::class,
\IlluminateCookie\MiddlewareAddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\MiddlewareAuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
```
Most helpful comment
Add
bindingsmiddleware to your route as such: