Laravel 5.7 validate fields with asterisk, required_if

Viewed 2022

I have a Vue form that let users add work experience for there profile. Users can add extra experience by clicking on a button. Clicking on that will add an new item with new input fields. I can't add the whole script because it's quit big. But here is an example to give you an idea:

<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>

After each element there is a button to add a new row. This works fine but I have some validation issues. I only want to validate the fields if one of the fields has a value. For example: If experiences[0][institution] has a value, experiences[0][title] and experiences[0][comments] are required. This has to work in every order. If title has a value, the other fields are required. I can't really find out a way how to validate this. This is my validation rule:

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

Problem here is that it simply doesn't validate. I can't figure out how to make a rule that says, if field X has a value, Y and Z are required.

Hope anyone here can help me finding a solution! :)

3 Answers

Like Azeame said, make a custom validation rule and check if all values are filled or all are empty. Something in de lines of:

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;
}

Maybe there is a beter way, but this should work.

required_if doesn't work with null as it will treat it as a string ("null"), it will work with boolean values though.

Instead you can use the required_without rule:

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

Example

$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());

Write a custom rule with php artisan make:rule and in the passes() function write a check to ensure that all of the array keys are present and also that at least 2 of the array values are not null. I'm thinking something like this:

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

    return true;
}

and in your $this->validate pass the rule as ['experiences.*' =>['array', new CustomRule()] instead of required_if...

I haven't checked this so feel free to edit if it's broken.

Related