Laravel 10 - always validate field even if the field isn't in the request

47 Views Asked by At

I have following segment of the validation:

'places' => [
    new CompanyHasPlacesRule,
],

and the validation class:

public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $company = DB::table('companies')
            ->select('companies.id', DB::raw('GROUP_CONCAT(places.id) as placeIDs'))
            ->join('places', 'companies.id', '=', 'places.company_id')
            ->where('companies.id', $this->data['company_id'])
            ->groupBy('companies.id')
            ->first();
        
        if (! $company?->placeIDs && $value === null) {
            return;
        }

        if ($company?->placeIDs && $value === null) {
            $fail('Please select place associated with the company.');
        }

        if ($value && $company->placeIDs) {

            $difference = array_diff($value, explode(',', $company->placeIDs));

            if (! empty($difference)) {
                $fail('Selected company does not have this place assigned.');
            }

            return;
        }

        $fail('Selected company does not have this place assigned.');

    }

The problem: company doesn't always have a place, but if the company have a place, one or more places needs to be selected - places needs to be validated only if the company have places, and the only way to find out if the company has places is in validation. Is there a way to always validated places even if the places field is not in the request?

1

There are 1 best solutions below

0
Orlando315 On

Just for simplicity, I'm going to use eloquent's relationships

class Company extends Model
{
    public function places()
    {
        return $this->hasMany(Place::class);
    }
}

In the validation class

public function validate(string $attribute, mixed $values, Closure $fail): void
{
    // Retrieve the company with its associated places
    $company = Company::with(['places:id,company_id'])
        ->firstWhere('id', $this->data['company_id']);

    // If the company doesn't have places, the validation will pass
    if ($company->places->count() === 0) {
        return;
    }

    if (empty($values)) {
        $fail('Please select a place associated with the company.');
    }

    $placesIds = $company->places->pluck('id')->toArray();
    $difference = array_diff($values, $placesIds);

    // If one or more selected places are not associated with the company,
    // the validation will fail
    if (! empty($difference)) {
        $fail('One or more selected places are not associated with the company.');
    }

    // If the company has places and the selected places are associated with the company,
    // the validation will pass

}