web-dev-qa-db-fra.com

Laravel Règles de validation si la valeur existe dans un autre tableau de champs

Je travaille dans Laravel 5.4 et j'ai besoin de règles de validation légèrement spécifiques mais je pense que cela devrait être facilement réalisable sans avoir à étendre la classe. Je ne sais pas comment faire fonctionner cela ..

Ce que je voudrais faire, c'est faire le 'music_instrument' champ de formulaire obligatoire si program tableau contient 'Music'.

J'ai trouvé ce fil Comment définir require si la valeur est choisie dans un autre champ à choix multiples dans la validation de laravel? mais ce n'est pas une solution (car il n'a jamais été résolu en premier lieu) et la raison pour laquelle il ne fonctionne pas parce que les index de tableau soumis ne sont pas constants (les cases à cocher non sélectionnées ne sont pas prises en compte dans l'indexation du résultat de la soumission ...)

Mon cas ressemble à ceci:

<form action="" method="post">
    <fieldset>

        <input name="program[]" value="Anthropology" type="checkbox">Anthropology
        <input name="program[]" value="Biology"      type="checkbox">Biology
        <input name="program[]" value="Chemistry"    type="checkbox">Chemistry
        <input name="program[]" value="Music"        type="checkbox">Music
        <input name="program[]" value="Philosophy"   type="checkbox">Philosophy
        <input name="program[]" value="Zombies"      type="checkbox">Zombies

        <input name="music_instrument" type="text" value"">

        <button type="submit">Submit</button>

    </fieldset>
</form>

Si je sélectionne certaines des options dans la liste des cases à cocher, je peux potentiellement avoir ce résultat dans mon $request valeurs

[program] => Array
    (
        [0] => Anthropology
        [1] => Biology
        [2] => Music
        [3] => Philosophy
    )

[music_instrument] => 'Guitar'

En regardant les règles de validation ici: https://laravel.com/docs/5.4/validation#available-validation-rules Je pense que quelque chose comme le sien devrait fonctionner mais je ne reçois littéralement rien:

  $validator = Validator::make($request->all(),[
        'program'           => 'required',
        'music_instrument'  => 'required_if:program,in:Music'
  ]);

J'espérais que ça marcherait aussi mais pas de chance:

'music_instrument'  => 'required_if:program,in_array:Music',

Pensées? Suggestions?

Je vous remercie!

7
GRowing

Je n'ai pas essayé cela, mais dans les champs de tableau généraux, vous écrivez généralement comme ceci: program.*, alors peut-être que quelque chose comme ça fonctionnera:

  $validator = Validator::make($request->all(),[
        'program'           => 'required',
        'music_instrument'  => 'required_if:program.*,in:Music'
  ]);

Si cela ne fonctionne pas, vous pouvez évidemment le faire également dans l'autre sens, par exemple comme ceci:

$rules = ['program' => 'required'];

if (in_array('Music', $request->input('program', []))) {
    $rules['music_instrument'] = 'required';
}

$validator = Validator::make($request->all(), $rules);
16
Marcin Nabiałek

Vous pouvez créer une nouvelle règle personnalisée appelée required_if_array_contains comme ça...

Dans app/Providers/CustomValidatorProvider.php, ajoutez une nouvelle fonction privée:

/**
 * A version of required_if that works for groups of checkboxes and multi-selects
 */
private function required_if_array_contains(): void
{
    $this->app['validator']->extend('required_if_array_contains',
        function ($attribute, $value, $parameters, Validator $validator){

            // The first item in the array of parameters is the field that we take the value from
            $valueField = array_shift($parameters);

            $valueFieldValues = Input::get($valueField);

            if (is_null($valueFieldValues)) {
                return true;
            }

            foreach ($parameters as $parameter) {
                if (in_array($parameter, $valueFieldValues) && strlen(trim($value)) == 0) {
                    // As soon as we find one of the parameters has been selected, we reject if field is empty

                    $validator->addReplacer('required_if_array_contains', function($message) use ($parameter) {
                        return str_replace(':value', $parameter, $message);
                    });

                    return false;
                }
            }

            // If we've managed to get this far, none of the parameters were selected so it must be valid
            return true;
        });
}

Et n'oubliez pas de vérifier qu'il existe une instruction use en haut de CustomValidatorProvider.php pour notre utilisation de Validator comme argument dans notre nouvelle méthode:

...

use Illuminate\Validation\Validator;

Ensuite, dans la méthode boot () de CustomValidatorProvider.php, appelez votre nouvelle méthode privée:

public function boot()
{
    ...

    $this->required_if_array_contains();
}

Ensuite, apprenez à Laravel à écrire le message de validation de manière conviviale en ajoutant un nouvel élément au tableau dans resources/lang/en/validation.php:

return [
    ...

    'required_if_array_contains' => ':attribute must be provided when &quot;:value&quot; is selected.',
]

Vous pouvez maintenant écrire des règles de validation comme ceci:

public function rules()
{
    return [
        "animals": "required",
        "animals-other": "required_if_array_contains:animals,other-mamal,other-reptile",
    ];
}

Dans l'exemple ci-dessus, animals est un groupe de cases à cocher et animals-other est une entrée de texte qui n'est requise que si le other-mamal ou other-reptile la valeur a été vérifiée.

Cela fonctionnerait également pour une entrée de sélection avec la sélection multiple activée ou toute entrée qui se traduit par un tableau de valeurs dans l'une des entrées de la demande.

3
Martin Joiner

L'approche que j'ai adoptée pour un problème similaire consistait à créer une fonction privée dans ma classe Controller et à utiliser une expression ternaire pour ajouter le champ requis s'il se vérifiait.

J'ai environ 20 champs qui ont une case à cocher pour activer les champs d'entrée dans ce cas, donc cela peut être exagéré en comparaison, mais à mesure que vos besoins augmentent, cela pourrait s'avérer utile.

/**
 * Check if the parameterized value is in the submitted list of programs
 *  
 * @param Request $request
 * @param string $value
 */
private function _checkProgram(Request $request, string $value)
{
    if ($request->has('program')) {
        return in_array($value, $request->input('program'));
    }

    return false;
}

En utilisant cette fonction, vous pouvez appliquer la même logique si vous avez également d'autres champs pour vos autres programmes.

Puis dans la fonction store:

public function store(Request $request)
{
    $this->validate(request(), [
    // ... your other validation here
    'music_instrument'  => ''.($this->_checkProgram($request, 'music') ? 'required' : '').'',
    // or if you have some other validation like max value, just remember to add the |-delimiter:
    'music_instrument'  => 'max:64'.($this->_checkProgram($request, 'music') ? '|required' : '').'',
    ]);

    // rest of your store function
}
2
brent_aof