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

gzai's avatar
Level 3

Calling validation FormRequest from controller is sometimes incorrect

Hello,

I have FormRequest, and I want to call FormRequest in other api controller

controller :


$request_tasks = app('App\Requests\TasksRequest');
$request_tasks->setValidator( Validator::make( $request->all(), $request_tasks->rules(), $request_tasks->messages() ) );

$result = $this->create( $request_tasks->validated() );

The process validation is correct, but sometime validation incorrect for some rule. does anyone know the issue?

0 likes
8 replies
rodrigo.pedra's avatar

As you are reusing all the methods from the TasksRequest, and even replacing the request validator with a TaskRequest instance, why not type-hinting it directly on this API controller?

Something like this:

public function store(\App\Requests\TasksRequest $request) {
  $result = $this->create( $request->validated() );

  return $result;
}

One thing that might be different is the authorize method, if that is the case you can extend TasksRequest and override just the authorize method:

class ApiTasksRequest extends TasksRequest {
  public function authorize() {
    // handle API authorization
  }

  // rules and messages will be inherited from TasksRequest
}

Then you would just need to type-hint it:

public function store(\App\Requests\ApiTasksRequest $request) {
  $result = $this->create( $request->validated() );

  return $result;
}
gzai's avatar
Level 3

I have store process just like that, and this process is correct.

use App\Requests\TasksRequest;

class TasksController extends Controller 
{

	public function store(TasksRequest $request) 
	{
		$result = $this->tasksRepository->create( $request->validated() );
		return $result;
	}

}

Then I have another function that require the TasksRequest

class TasksRepository 
{

	public function quick_add(Request $request)
	{

		$id = ( $request->has('id') ) ? $request->get('id') : 0 ;

		$suggest = TasksSuggests::find( $id );

		// here init data from suggest and merge to $request

		$request_tasks = app('App\Requests\TasksRequest');
        	$request_tasks->setValidator( Validator::make( $request->all(), $request_tasks->rules(), $request_tasks->messages() ) );

        	$result = $this->create( $request_tasks->validated() );

		return $result;

	}

	public function create($input)
	{
		return Tasks::create( $input ); 
	}

}

I can't do it like a store process for public function quick_add(TasksRequest $request), because before the validation process in function quick_add, I have to init the merge data with the request.

rodrigo.pedra's avatar

You can override the prepareForValidation method from the form request to merge data before the Form Request validation is triggered

https://laravel.com/docs/7.x/validation#prepare-input-for-validation

Even the example from the docs is something similar:

/**
 * Prepare the data for validation.
 *
 * @return void
 */
protected function prepareForValidation()
{
    $this->merge([
        'slug' => Str::slug($this->slug),
    ]);
}

In your case it would be something like this:

protected function prepareForValidation()
{
    // get accepts a default value when field is not present
    // also, as FormRequest extends request we can use $this here
    $id = $this->get('id', 0);

    $suggest = TasksSuggests::find( $id );

    $data = /* ... init data from suggest */

    $this->merge($data);
}

This prepareForValidation will be called before the form request validation is triggered.

gzai's avatar
Level 3

@rodrigo.pedra how I can use prepareForValidation only for public function quick_add and disable prepareForValidation for public function store(TasksRequest $request) ?

rodrigo.pedra's avatar

Sorry for the late response, these last days were busy to me.

As the form request extends the request you have access to all the normal request's methods.

For example you could check by route name:

protected function prepareForValidation()
{
    if ($this->routeIs('my.route.name')) return; // do nothing

    // process as above
}

by path:

protected function prepareForValidation()
{
    if ($this->is('/task/*')) return; // do nothing

    // process as above
}

Or by any other request method.

gzai's avatar
Level 3

It's okay @rodrigo.pedra. I am very grateful because you replied in your busy schedule.

We can set unique request too :

protected function prepareForValidation()
{
    if (!request()->has('enable')) return; // do nothing

    // process as above
}

I thought there is a method to enable or disable the custom request for prepareForValidation that we are calling.

ex:

public function store(TasksRequest(false) $request) // disable prepareForValidation

public function quick_add(TasksRequest(true) $request) // enable prepareForValidation
rodrigo.pedra's avatar
Level 56

Unfortunately passing arguments to class hints is not possible.

As FormRequest is a Request you don't need to use the request() helper inside of it. You could change your example as the following:

protected function prepareForValidation()
{
    if (!$this->has('enable')) return; // do nothing

    // process as above
}

Also you could have a QuickAddTasksRequest with the rules method and make TaskRequest extend that adding the prepareForValidation method.

Personally I avoid having deep class hierarchies, as they can become hard to maintain, but that is an option.

For example:

// namespace, use, etc...

class QuickAddTasksRequest extends FormRequest {
  public function rules() {
    return [
      // validation rules
    ];
  }

  // no prepareForValidation
}
// namespace, use, etc...

class TasksRequest extends QuickAddTasksRequest {
  // no need of a rules method as they are defined in the parent class

  public function prepareForValidation() {
    // pre-validation sanitizing logic
  }
}

And then on each controller you would have:

// quick add controller

public function store(QuickAddTasksRequest $request) {
  $validated = $request->validated();
  // do something with the validated data
}
// regular controller

public function store(TasksRequest $request) {
  $validated = $request->validated();
  // do something with the validated data
}

That way the prepareForValidation method would only be executed in the TasksRequest while it shares the same rules from the QuickAddTasksRequest

Please or to participate in this conversation.