4
votes

Laravel 5.7 valide les champs avec un astérisque, obligatoire_if

J'ai un formulaire Vue qui permet aux utilisateurs d'ajouter une expérience de travail pour leur profil. Les utilisateurs peuvent ajouter une expérience supplémentaire en cliquant sur un bouton. En cliquant dessus, vous ajouterez un nouvel élément avec de nouveaux champs de saisie. Je ne peux pas ajouter tout le script car il est assez gros. Mais voici un exemple pour vous donner une idée:

$this->validate(request(), [
        'experiences.*.title'       => 'required_if:experiences.*.institution,null',
        'experiences.*.institution' => 'required_if:experiences.*.title,null',
]);

Après chaque élément, il y a un bouton pour ajouter une nouvelle ligne. Cela fonctionne bien mais j'ai quelques problèmes de validation. Je souhaite uniquement valider les champs si l'un des champs a une valeur. Par exemple: Si expériences [0] [institution] a une valeur, expériences [0] [title] et expériences [0] [commentaires] sont obligatoires . Cela doit fonctionner dans chaque ordre. Si title a une valeur, les autres champs sont obligatoires. Je ne peux pas vraiment trouver un moyen de valider cela. Voici ma règle de validation:

<div class="item">
    <div class="row">
        <div class="form-group col-md-6">
            <label class="form-label">Title</label>
            <input type="text" name="experiences[0][title]" class="form-control">
        </div>
        <div class="form-group col-md-6">
            <label class="form-label">Institution</label>
            <input type="text" name="experiences[0][institution]" class="form-control">
        </div>
    </div>
    <div class="row">
        <div class="col-md-12">
            <textarea name="experiences[0][comments]" class="form-control"></textarea>
        </div>
    </div>
</div>
<div class="item">
    <div class="row">
        <div class="form-group col-md-6">
            <label class="form-label">Title </label>
            <input type="text" name="experiences[1][title]" class="form-control">
        </div>
        <div class="form-group col-md-6">
            <label class="form-label">institution </label>
            <input type="text" name="experiences[1][institution]" class="form-control">
        </div>
    </div>
    <div class="row">
        <div class="col-md-12">
            <textarea name="experiences[1][comments]" class="form-control"></textarea>
        </div>
    </div>
</div>

Le problème ici est qu'il ne valide tout simplement pas. Je ne peux pas comprendre comment créer une règle qui dit, si le champ X a une valeur, Y et Z sont obligatoires.

J'espère que n'importe qui ici pourra m'aider à trouver une solution! :)


0 commentaires

3 Réponses :


1
votes

required_if ne fonctionne pas avec null car il le traitera comme une chaîne ( "null" ), il fonctionnera avec boolean

À la place, vous pouvez utiliser la règle required_without :

$experiences = [
    [
        "title"       => "My title",
        "institution" => "",
        "comments"    => "<p>My first description</p>", //passes
    ],
    [
        "title"       => "",
        "institution" => "My title",
        "comments"    => "<p>My second description</p>", //passes
    ],
    [
        "title"       => "My title",
        "institution" => "My title",
        "comments"    => "<p>My third description</p>", //passes
    ],
    [
        "title"       => "",
        "institution" => null,
        "comments"    => "<p>My forth description</p>", //fails
    ],

];

$rules = [
    "experiences.*.title"       => "required_without:experiences.*.institution",
    "experiences.*.institution" => "required_without:experiences.*.title",
];

$validator = Validator::make(compact('experiences'), $rules);

dd($validator->fails());

Exemple

$this->validate(request(), [
    "experiences.*.title"       => "required_without:experiences.*.institution",
    "experiences.*.institution" => "required_without:experiences.*.title",
]);


7 commentaires

D'une manière ou d'une autre, il ignore la première partie de la validation. Si je laisse title vide et donne une valeur à institution , cela ne valide pas. Mais la deuxième partie après la fusion , fonctionne très bien :-)


@Ruub pouvez-vous afficher la sortie de dd (request ('experiences')) pour votre exemple ci-dessus?


["title" => null, "institution" => "Mon entreprise", "comments" => "

Ma première description

",], ["title" => "Mon titre "," institution "=> null," comments "=>"

Ma deuxième description

",]];


Attendez, la sortie exacte est: array: 2 [0 => array: 3 ["title" => null "institution" => "My Company" "comments" => "

Ma première description "] 1 => array: 3 [" title "=>" Mon titre "" institution "=> null" comments "=>"

Ma deuxième description

"]]


@Ruub Scratch tout cela, c'est un problème avec la règle utilisée. Je vais mettre à jour ma réponse maintenant.


Hmm. Maintenant, il ne valide pas si l'un des champs a une valeur. Mais c'est le cas s'il y a les deux vides. Mais ce n'est pas vraiment ce que nous recherchons :)


@Ruub C'est très étrange car j'obtiens exactement le contraire. Juste pour ne pas manquer quelque chose, dites-vous que si l'un des champs a une valeur, la validation échoue et lève une exception, mais ce n'est pas le cas s'ils sont tous les deux vides?



1
votes

Ecrivez une règle personnalisée avec php artisan make: rule et dans la fonction passes () écrivez une vérification pour vous assurer que toutes les clés du tableau sont présentes et aussi que au moins 2 des valeurs du tableau ne sont pas nulles. Je pense à quelque chose comme ceci:

function passes($attribute, $value){
    if(array_keys($value) !== ['title','institution','comments']){
        return false;
    }
    if(empty($value['title']) && empty($value['institution'])){
        return false;
    }

    return true;
}

et dans votre $ this-> validate passez la règle en tant que ['experiences. *' => [ 'array', new CustomRule ()] au lieu de required_if...

Je n'ai pas vérifié ceci, alors n'hésitez pas à le modifier s'il est cassé.


8 commentaires

J'ai aussi eu l'idée de créer une règle personnalisée, mais j'espérais vraiment qu'il y aurait un moyen plus "simple" de le faire :)


C'est en fait très facile, essayez-le, vous serez surpris, si je n'étais pas dans mon téléphone sans WiFi pour le moment, je vous l'écrirais maintenant


@Ruub J'ai mis à jour la réponse, voyez si cela fonctionnera pour vous, je pense que cela devrait bien fonctionner


Je vais essayer :)


Hmm. Il renvoie vrai car les trois champs sont présents. Mais cela ne vérifie pas s'ils ont tous une valeur.


Que diriez-vous de combiner ma solution avec celle de Ross, est-ce que cela couvrira toutes les bases?


Je pense que oui, je reviendrai avec une mise à jour. Merci les gars!


Je l'ai modifié à nouveau, bien que je ne sois pas en fait un avantage dans la première instruction if, mais il est 4h30 du matin et je n'ai pas encore dormi, alors je l'ai laissé pour le moment, vous pouvez également remplacer les appels vides par un comparaison à null, besoin de dormir



3
votes

Comme Azeame l'a dit, créez une règle de validation personnalisée et vérifiez si toutes les valeurs sont remplies ou si toutes sont vides. Quelque chose dans les lignes de:

public function passes($attribute, $value)
{
    $required = ['title','institution','comments'];

    $experience = collect($value)->reject(function ($item, $key) {
        return empty($item);
    });

    if (count($experience) == 0) {
        return true;
    }

    foreach ($required as $field) {
        if ( !$experience->has($field)) {
            return false;
        }
    }

    return true;
}

Il y a peut-être un meilleur moyen, mais cela devrait fonctionner.


1 commentaires

Je vais essayer :)