michaeldyrynda / laravel-model-uuid

This package allows you to easily work with UUIDs in your Laravel models
MIT License
442 stars 46 forks source link

Route uuid binding Laravel 8 #104

Closed joshwegener closed 3 years ago

joshwegener commented 3 years ago

(Please note I 'm not to UUIDs) I'm using Laravel with Jetstream, I'm trying to add the scope binding for URL routes, but I get an error with \App\Post, has this moved in laravel 8?

// app/Providers/RouteServiceProvider.php

Route::bind('post', function ($post) {
    return \App\Post::whereUuid($post)->first();
});

Thanks!

joshwegener commented 3 years ago

Oh I feel stupid... \App\Post is a model example....

joshwegener commented 3 years ago

I assume if I use explicit binding I won 't have this issue?

// app/Providers/RouteServiceProvider.php

public function boot()
{
    Route::model('user', User::class);
}
michaeldyrynda commented 3 years ago

I don't have enough context with your issue to comment either way. What error are you getting or what are you trying to achieve? How can I make the documentation clearer for your use case?

robvankeilegom commented 3 years ago

@joshwegener is referencing https://laravel.com/docs/8.x/routing#route-model-binding.

use App\Http\Controllers\UserController;
use App\Models\User;

// Route definition...
Route::get('/users/{user}', [UserController::class, 'show']);

// Controller method definition...
public function show(User $user)
{
    return view('user.profile', ['user' => $user]);
}

This will work with the route: /users/1 where 1 is the id of the user model. But if you're using uuids in your route this won't work.

One solution is to add the following in a service provider (obliviously out of the scope of the package):

Route::bind('user', function ($uuid) {
    return \App\Models\User::whereUuid($uuid)->firstOrFail();
});

You'll have to do this for every model that uses uuids in its routes which is too cumbersome imo.

Another solution is to add on the model:

    /**
     * Retrieve the model for a bound value.
     *
     * @param  mixed  $value
     * @param  null|string  $field
     *
     * @return null|\Illuminate\Database\Eloquent\Model
     */
    public function resolveRouteBinding($value, $field = null)
    {
        return $this->whereUuid($value, $field)->firstOrFail();
    }

This could be done on the GeneratesUuid trait in the package but then we would assume all models with the trait are using uuids in their routes.

I suggest @joshwegener creates a parent model in their codebase with the resolveRouteBinding function.

michaeldyrynda commented 3 years ago

Can you not just override the getRouteKeyName method on the models that require implicit binding?

In Laravel 8 you can customise the key on an ad-hoc basis, which may or may not be desirable over the above, depending on how many routes you have.

Route::get('/users/{user:uuid}', [UserController::class, 'show']);