Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

musti132's avatar

Laravel Unnecessary query

Hello,

I have a FormRequest validation which has the exists validation like so

'event' => ['required', 'string', 'max:255', 'exists:events,slug'],

Because of the exists validation the app will run a query to check if the 'event' exists in the database, in the controller is there anyway I can access the query results (if it exists), instead of running another query like so

$event = Event::where('slug', $request->event)->first();

This creates an unnecessary query, since we already resolved the event in the FormRequest, is there any way I can pass that onto the controller?

I know there is route model binding, but that only works in the URL query

0 likes
3 replies
LaryAI's avatar
Level 58

One solution would be to create a custom validation rule that extends the Laravel's exists rule and returns the existing model instance instead of a boolean value. Here's an example:

  1. Create a new custom validation rule by running the following command in your terminal:
php artisan make:rule ExistingEvent
  1. Open the ExistingEvent class that was just created in the app/Rules directory and modify it as follows:
namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use App\Models\Event;

class ExistingEvent implements Rule
{
    protected $event;

    public function passes($attribute, $value)
    {
        $this->event = Event::where('slug', $value)->first();

        return $this->event !== null;
    }

    public function message()
    {
        return 'The selected event does not exist.';
    }

    public function getEvent()
    {
        return $this->event;
    }
}
  1. Modify your FormRequest validation rule to use the new ExistingEvent rule:
use App\Rules\ExistingEvent;

...

public function rules()
{
    return [
        'event' => ['required', 'string', 'max:255', new ExistingEvent],
    ];
}
  1. In your controller method, you can access the existing Event model instance by calling the getEvent method on the ExistingEvent instance:
use App\Rules\ExistingEvent;

...

public function store(Request $request)
{
    $validatedData = $request->validate([
        'event' => ['required', 'string', 'max:255', new ExistingEvent],
    ]);

    $event = (new ExistingEvent)->getEvent();

    // Do something with the $event model instance...
}

This way, you avoid running an unnecessary query to retrieve the Event model instance in your controller method.

musti132's avatar

I know it's a AI Response and that it respond to replies. This works, but I can't use a FormRequest doing this. Also it uses both FormRequest Validation and Validation in the Controller?

musti132's avatar

Here is what I came up with

EventExists Rule

class EventExists implements ValidationRule
{
    protected ?Event $event;
    /**
     * Run the validation rule.
     *
     * @param  \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString  $fail
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $this->event = Event::where('slug', $value)->first();

        if (!$this->event) {
            $fail('The event does not exist.');
        }
    }

    public function event() : ?Event
    {
        return $this->event;
    }
}

FormRequest validation

class CampaignEventStoreRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
     */
    public function rules(): array
    {
        return [
            'event' => ['required', 'string', 'max:255', new EventExists],
            'group_id' => ['sometimes', 'string', 'max:255', 'exists:groups,id']
        ];
    }

    protected function withValidator(Validator $validator): void
    {
        $validator->after(function (Validator $validator) {
            if ($validator->failed()) {
                return;
            }

            $event = $validator->getRules()['event'][3]->invokable()->event();
            
            $data = $validator->getData();

            $validator->setData([
                ...$data,
                'event' => $event
            ]);
        });
    }
}

Accessing it in the controller

$event = $request->validated()['event']:

If there is a easy and better way, please let me know

Please or to participate in this conversation.