简体   繁体   中英

Laravel 5.7. Route model binding validation

I'd like to use sweet Laravel model binding and then run some complex validation checks on the model itself.

Something like

Route::post('/do-something/{something}', 'SomeController@store');

and

$request->validate([
    'something' => [
        new MyFirstVeryComplexRule,
        new MySecondVeryComplexRule,
        new MyThirdVeryComplexRule,
        //...
    ],
]);

I assume, that $value passed to each rule will be an instance of App\\Something class.

Is is possible to achieve that?

The closest option I can think of is to pass id of a model and then run App\\Some::find($value) in each rule instance, but this kills the performance and is not scalable.

Answer

No, this is not possible because of x,y,z, try a,b,c

will also be accepted.

You could create a custom binding in your RouteServiceProvider like this:

public function boot()
{
    parent::boot();

    Route::bind('something', function ($value) {
        $instance = Model::find($value) ?? abort(404);

        $validator = Validator::make([
            'something' => $instance,
        ], [
            'something' => [
                new MyFirstVeryComplexRule,
                new MySecondVeryComplexRule,
                new MyThirdVeryComplexRule
            ]
        ]);

        if ($validator->errors()->any()) {
            // perform on error tasks
        }

        return $instance;
    });
}

Then the $value of each rule will receive the instance of your Model.

For more information, you can take a look at Customizing The Resolution Logic under Route Model Binding : https://laravel.com/docs/5.8/routing#route-model-binding

From Laravel's Routing documentation :

Alternatively, you may override the resolveRouteBinding method on your Eloquent model. This method will receive the value of the URI segment and should return the instance of the class that should be injected into the route:

class YourModel {
    public function resolveRouteBinding($value, $field = null)
    {
        return $this->where('name', $value)->firstOrFail();
    }
}

You can use this just like @Chin Leung does:

class YourModel {
    public function resolveRouteBinding($value, $field = null)
    {
        $instance = Model::find($value) ?? abort(404);

        $validator = Validator::make([
            'something' => $instance,
        ], [
            'something' => [
                new MyFirstVeryComplexRule,
                new MySecondVeryComplexRule,
                new MyThirdVeryComplexRule
            ]
        ]);

        if ($validator->errors()->any()) {
            // perform on error tasks
        }

        return $instance;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM