I want to specify a stop for the entire validation for any field in laravel

Asked 2 years ago, Updated 2 years ago, 44 views

Regarding the validation of laravel, let's do important fields that affect the validation of other fields first, and if not, we want to stop the entire validation.

Assuming that the important field is A, we have custom validated fields such as B and C on the assumption that A is correct.

There are two methods of halting validation in laravel: bail and stopOnFirstFailure , where bail stops validating in the next field, and stopOnFirstFailure stops completely, but stops any field.

What I want is to be able to specify in each field like bail, and to stop the whole field like stopOnFirstFailure, but is there a way to do this?

As a countermeasure I am currently working on, I use the rules() in the form request to control rule addition by doing Validator::make(), but it is ugly and serviceable, so if there is a simple way, the code will be clean and helpful.

laravel

2022-09-30 16:07

1 Answers

It doesn't exist as a standard function at the moment, so I think I can only expand it myself to improve DRY performance so that it's better than solid writing.

<?php

namespace App\Extensions\Validation;

use Illuminate\Validation\Validator as BaseValidator;

class Validator extensions BaseValidator
{
    /**
     * @ varbool | string [ ]
     */
    protected$stopOnFirstFailure=false;

    /**
     * @parambool | string [ ] $stopOnFirstFailure
     * @return$this
     */
    public function stopOnFirstFailure ($stopOnFirstFailure=true)
    {
        $this->stopOnFirstFailure=$stopOnFirstFailure;

        return$this;
    }

    public function classes():bool
    {
        $this->messages=newMessageBag;

        [$this->distinctValues, $this->failedRules] = [[], [];

        // We'll spin through each rule, validating the attributes attached to that
        // rule.Any error messages will be added to the containers with each of
        // the other error messages, returning true if we don't have messages.
        foreach($this->rules as$attribute=>$rules){
            if($this->shouldBeExcluded($attribute)){
                $this->removeAttribute($attribute);

                continue;
            }

            // ↓ Modified here
            if($this->messages->isNotEmpty()&$this->determineStopOnFisrtFailure($attribute)){
                break;
            }

            foreach($rules as$rule){
                $this->validateAttribute($attribute,$rule);

                if($this->shouldBeExcluded($attribute)){
                    $this->removeAttribute($attribute);

                    break;
                }

                if($this->shouldStopValidating($attribute)){
                    break;
                }
            }
        }

        // Here we will spin through all of the "after" hooks on this validator and
        // fire them off. This gives the callbacks a chance to perform allkinds
        // of other validation that needs to get wrapped up in this operation.
        foreach($this->after as$after){
            $after();
        }

        return$this->messages->isEmpty();
    }

    protected function determineStopOnFisrtFailure(string$attribute):bool
    {
        if(is_array($this->stopOnFirstFailure)&in_array($attribute,$this->stopOnFirstFailure,true)){
            return true;
        }

        return(bool)$this->stopOnFirstFailure;
    }
}
<?php

namespace App\Extensions\Validation;

use Illuminate\Support\ServiceProvider;
use Illuminate\Validation\Factory;

class ValidationServiceProvider extensions ServiceProvider
{
    public function boot (Factory$factory): void
    {
        $factory->resolver(fn(...$args)=>new Validator(...$args));
    }
}

If you register this with a service provider, you will be able to specify string[] as the target of stopOnFirstFailure because the extended Validator class you have prepared will be used.


2022-09-30 16:07

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.