Route Model Binding not working
Asked Answered
A

3

26

I'm trying to use Route Model Binding for Simple CRUD but Update And Delete Function Not Working. and I'm Using laravel 5.5

Route::resource('admin/file','AdminController');

My View For Edit and Delete Buttons

<a href="{{ route('file.edit', ['id'=>$file->id]) }}">

<form action="{{ route('file.destroy', ['id'=>$file->id]) }}" method="post">
   {{method_field('DELETE')}}
   {{csrf_field()}}
   <button type="submit" class="delete">delete</button>
</form>

My Resource Controller :

namespace App\Http\Controllers;

use App\Files;
use Illuminate\Http\Request;

Store Work Fine

  public function store(Request $request)
{
    $this->validate($request,[
        'title'=>'required',
        'body'=>'required',
        'price'=>'required',
        'linkFile'=>'required',
    ]);

     Files::create($request->all());
    return redirect(route('file.index'));
}

But Edit and Delete Not Working

public function edit(Files $files)
{
   return view('admin.edit',compact('files'))->with('title','Edit File');
}

public function destroy(Files $files)
{
    $files->delete();
    return redirect(route('file.index'));
}

My Model:

protected $table='files';

protected $fillable=[
    'title','body','price','linkFile'
];

When I Delete Button Nothing Happens and Edit as Same

If I Add dd($files) at First Column for Edit and Delete Function Then Response Will be [] and There's No Error for handle

Here My Route Lists

enter image description here

Anyone Can help Please?

Aegina answered 19/9, 2017 at 18:4 Comment(0)
A
121

Finally, after 2 days I found my answer and I would like to provide my answer here for everyone who maybe has the same problem.

For route binding to work, your type-hinted variable name must match the route placeholder name

For example my edit method

Here is my route URI for the edit

admin/file/{file}/edit

As you can see there is a {file} placeholder in the route definition, so the corresponding variable must be called $file.

public function edit(Files $file)
{
   return view('admin.edit',compact('file'));
}
Aegina answered 19/9, 2017 at 19:41 Comment(3)
This helped me as well. I had a camelCase version of the variable in the controller which didn't resolve. Thanks!Kast
I kept trying to use {$id} and all variations of the id, this saved me a lot of time.Gradatim
Another tip, you can check the routes via php artisan route:list to see what the variables are. Also, if its two words, it seems like a variable {foo_bar} will be accessible with $fooBar as well as $foo_bar.Emmalineemmalyn
A
18

I´ve stumbled across this again. I´m not sure if this was my own mistake or if this middlerware is missing by default.

Im using Laravel 8 and develop an API. I always got an empty array back as a response, when I tried to call a route that should implicitly bind to a model.

TL;DR Check if the Kernel.php file $routedMiddlewareGroups api array has the SubstituteBindings::class added to it. Otherwise your requests won´t get resolved correctly.

The request to the API | Get User by ID | Frontend, Vue.js

UserComponent.vue

methods: {
        close() {
            $('#user-modify-modal').modal('hide');
        },
        open() {
            $('#user-modify-modal').modal({backdrop: 'static', keyboard: false});

            this.fetchUserData(this.params.id);
        },
        async fetchUserData(id) {
            await axios
            .get('users/${this.params.id}')
            .then((result) => {
                this.user = result.data;
            }).catch((err) => {
                console.error(err);
            });
        }
    },

Heres how I set up my API protected routes:

routes/api.php

//protected routes | API
Route::group(['middleware' => ['api', 'cors', 'json.response', 'auth:api'], 'prefix' => 'v1'], function() {
    Route::post('/logout', [ApiLoginController::class, 'logout']);

    Route::get('/user', function (Request $request) {
        return $request->user();
    });
    Route::get('/users', [UserController::class, 'index']);
    //the function im Testing...
    Route::get('users/{user}', [UserController::class, 'show']);
    Route::post('/users', [UserController::class, 'store']);
    Route::put('/users/{user}', [UserController::class, 'update']);
    Route::delete('/users/{user}', [UserController::class, 'show']);
});

UserController.php

...
/**
     * Get user by ID
     *
     * @param Request $request
     * @param User $user
     * @return void
     */
    public function show(User $user) {

        return response()->json($user);
    }
...

Without this middlerware SubstituteBinding::class the Implicit Binding will NOT work!

Make sure to check your kernel / api settings

Kernel.php

 /**
     * 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\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            'throttle:120,1',
            EncryptCookies::class,
            AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,

            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

Now when calling

http://localhost/api/v1/users/1

It returns the correct user data.

Andesite answered 22/4, 2021 at 0:50 Comment(0)
A
14

I know this problem already has a solution, but let me add some knowledge that might be useful to others...

As the documentation says, when using resource controllers, the resource routes will use parameters based on the "singularized" name of the resource. In the case of the question, since @siros was using the "file" resource name (singular form) in the route, the binding name in the controller method should be "file", although his model is named Files. If he attempted to use:

Route::resource('admin/files','AdminController');

The controller would still need Files $file to work, since file is the singularized form of files.

However, there is other (and more elegant) solution to the problem. You can change the type-hinted variable in the URL by providing a parameters option in the configuration of the route, as shown in the documentation, which would automatically apply for the show, edit, update and destroy methods. This will let you keep the variable name in your controller matching the model name, for example.

So, in this case, @siros could use this in the routes file:

Route::resource('admin/file','AdminController', [
    'parameters' => [
        'file' => 'files'
    ]
]);

And he could use this in the controller:

public function edit(Files $files)

Hope this helps someone.

Alcahest answered 22/9, 2019 at 17:45 Comment(1)
in laravel 8: Route::resource('file', AdminController::class)->parameters(['file' => 'files']);Epithelium

© 2022 - 2024 — McMap. All rights reserved.