t0berius's avatar

route model binding returns empty model

Using model binding for some routes I realized the returned model is empty.

I already checked my naming and for me everything seems fine:

| | GET|HEAD | item/{product} | | App\Http\Controllers\TestController@getProductPage | web

Inside my controller:

public function getProductPage(Request $request, Product $product){

    dd($product);
}

My product model:

public function getRouteKeyName()
{
    return 'id';
}

The returned object of type Product is empty, just the default attributes are set like:

#primaryKey: "id" #keyType: "int" +incrementing: true #with: [] #withCount: [] #perPage: 15 +exists: false

0 likes
17 replies
shez1983's avatar

do you have a soft deleted trait? thats the only thing i can think of - also install debugbar or 'listen' to the queries (check the doc) - to see what query laravel is doing and do that in your DB directly

t0berius's avatar

No soft deletes are not activated for any model.

Cronix's avatar

What do your actual links hitting that route look like?

t0berius's avatar

at the moment they look like:

http://192.168.56.100/item/1

Routes:

Route::get('item/{product}', 'TestController@getProductPage');

For sure, product with id 1 exists inside database. Debugbar doesn't display any query when visiting the page.

tykus's avatar

You do not need to override the getRouteKeyName method if you are using the default id property.

Have you double-checked that the wildcard and action argument are exactly the same, i.e. product and $product respectively. If they do not match, then Route-Model binding will not work.

t0berius's avatar

I've deleted the getRouteKeyName.

After this, to make things simple, I've included this code into my routes

Route::get('smalltest/{product}', function (App\Product $product) {
    dd($product);
});

Returns:

Product {#387 ▼
 #fillable: array:1 [▶]
 #connection: null
 #table: null
 #primaryKey: "id"
 #keyType: "int"
 +incrementing: true
...
}
1 like
t0berius's avatar

It's related to all my models, I've tried another one. Here we go:

ProductImage

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class ProductImage extends Model
{
    public $timestamps = false;

    public function product()
    {
        return $this->belongsTo('App\Product');
    }

    protected $fillable = [
        'name',
    ];
}

Inside my routes:

Route::get('smalltest/{product_image}', function (App\ProductImage $product_image) {
    dd($product_image);
});

Same "problem" as stated above.

Snapey's avatar

any global scope?

Check the sql as suggested earlier

t0berius's avatar

How to get the SQL easy? debugbar doesn't display any SQL when editing the dd() to a simple echo();

tykus's avatar
tykus
Best Answer
Level 104

Did you mess with the web middleware group to remove the SubstituteBindings middleware?

4 likes
t0berius's avatar

@tykus

goddamn..checked my repo history. I'm better quiet I think, SubstituteBindings will handle all this stuff like running sql queries?

sylar's avatar

Do you have \Illuminate\Routing\Middleware\SubstituteBindings::class in your 'web'

middleware group ?

and can you post output from php artisan route:list, its looks like a mismatch between the key and the model name

jesulo's avatar

Hi, I have same issue, has solved?

1 like
FallHealer's avatar

I had the same problem. I have a custom middleware group in app/Http/Kernel.php which was missing the \Illuminate\Routing\Middleware\SubstituteBindings::class. Just placed it there and now it works fine.

1 like
makeable's avatar

For anyone experiencing this make sure your type-hinted model variable name matches the parameter name listed when you run php artisan route:list. Laravel automatically converts the resource name to singular.

For instance, given the following route:

Route::resource('api/meta', Controllers\MetaController::class);

... Laravel actually expects the following in the MetaController@show method:

	public function show(Meta $metum): Meta
	{
        return $meta;
	}

Any other parameter name than Meta $metum will result in an empty model.

To change this behavior you may override the parameter name using:

Route::resource('api/meta', Controllers\MetaController::class)->parameters(['meta' => 'meta']);

Cheers!

3 likes
vektorstudio's avatar

Thanks, I had route called message-groups and was expecting the name of the model, but after running route:list, discovered it had it as just message-groups/{group} changing that in the destroy params to just $group instead of $messageGroup did the trick

Please or to participate in this conversation.