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

LearningLaravelYai's avatar

Refactor: Request in Controller & Calling other methods, any ideas?

I often find myself in situation where I have a method in a controller like:

public function store(ProfileRequest $request){
    // ....
}

Good thing: I can validate the data before it hits the controller.

Sometimes I want to call the same store method, from another method in the same class. In reality, in this situation I would like to call the store method like:

store($name, $age, $city) 

and not with the Request object.

If just php had method overloading :D

How do you handle these two situations?

Possible solutions:

Solution A: create two methods

public function storeRequest(ProfileRequest $request){ 
    $this->store($request['name]', $request['age'], $request['city']);
}
public function store($name, $age, $city)

Solution B: I guess its possible to move the Request/Validation to the api.php/web.php and then in the call the method in the controller with its parameter... but I dont know how it should look??????

Route::put('/update', function (ProfileRequest $request) {
    \App\ProfileControlller::store($request ['name'], $request ['age'], $request ['city'])  ???????????????????????????
});

How do I do this?

What are other approaches, you can recommend?

Thanks :-)

0 likes
7 replies
bugsysha's avatar

But you already get request object in that method from which you want to call store from. Why is it a problem to pass it? Never had this issue where I want to call store method from another method in same controller.

Have you seen this? https://www.youtube.com/watch?v=MF0jFKvS4SI

jlrdw's avatar

And to put it another way laravel is a PHP framework you can use just like PHP.

Even though it's best to stick to conventions.

Just curious what use case do you have where you would call store from another method, not counting an API that's different.

LearningLaravelYai's avatar

I got it working... alt text

By doing the validation in the middleware, its possible, to both do validation, but also calling the Store method directly.

And now I finally got rid of the "store(ExampleRequest $...)" and now can use normal parameters in the store method like store($param1, param2), that makes it easier to call the method, from other places.

@bugsysha I've seen it for some time ago, but the timing was perfect for a refresh :D ;-) Just what I needed, thanks!!

Now, I would prefer, if the validation logic is not in the middleware, but in a separate file located at: app/Http/Requests/ExampleRequest.php

How would I modify the middleware file to make that possible?

LearningLaravelYai's avatar

Just include the files here, so its easier to copy paste:

routes\web.php

<?php

use App\MyModel;
use App\Http\Middleware\ExampleMiddlware;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::post('create/{a}/{b}', 'ExampleController@store')->middleware(ExampleMiddlware::class);

app\Http\Middleware\ExampleMiddlware.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Http\Requests\HestRequest;
use Illuminate\Support\Facades\Validator;

class ExampleMiddlware
{
    /**
     * Handle an incoming request.
     * Will change validation language on response. 
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        Validator::make($request->all(), [
            'my_example' => 'nullable|string',
            'extra1' => 'nullable|string',
            'extra2' => 'nullable|string',
            'extra3' => 'nullable|string',
        ])->validate();

        return $next($request);
    }
}

app/Http/Kernel.php

...

    protected $routeMiddleware = [
        'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'ExampleMiddlware' => \App\Http\Middleware\ExampleMiddlware::class,  // <<-- HERE
    ];

...

tests\Feature\ExampleTest.php

<?php

// https://laravel.com/docs/5.7/http-tests#testing-json-apis

namespace Tests\Feature;

use Tests\TestCase;
use App\Http\Controllers\ExampleController;
use Illuminate\Foundation\Testing\RefreshDatabase;


class ExampleTest extends TestCase
{
    public function testBasicTest()
    {

        // PART1: Call the method Directly -------------
        $direct = (new ExampleController())->store('foo', 'bar');

        // PART2: Call the method with Route and Validation -------------
        $method = 'POST';
        $endpoint = 'create/hello/world';

        $response = $this->json($method, $endpoint, 

            [
                'my_example' => 'called with request', 
                'extra' => 'called with request', 
            ]
        );

       dump('PART1: CALL THE METHOD DIRECTLY', $direct);
       dump('PART2: CALL THE METHOD WITH ROUTE AND VALIDATION',  $response->json());
     

       // PART3: Simulate wrong input for validation -------------------------------
       $method = 'POST';
       $endpoint = 'create/hello/world';

       $response = $this->json($method, $endpoint, 
           [
               // Type is number, should be String
               'my_example' => 2321313, 
           ]
       );

       dump('PART3: WRONG INPUT IN VALIDATION',  $response->json());

       
    }
}

app\Http\Controllers\ExampleController.php

<?php

namespace App\Http\Controllers;

use App\FunModel;
use Illuminate\Http\Request;

class ExampleController extends Controller
{

    public function store($a, $b)
    {
        $strategy = null;
        if (request()->has('my_example')) {
            $strategy = "Was called with request";
        }
        return [$a, $b, request('my_example'), $strategy];
    }
}

bugsysha's avatar

Since all middleware are resolved via the service container, so you may type-hint any dependencies you need within a middleware's constructor.

But two things come to my mind.

class ExampleMiddlware
{
    public function handle(ExampleRequest $request, Closure $next)
    {
    // validate here.

        return $next($request);
    }
}

Or this

class ExampleMiddlware
{
    protected ExampleRequest $request;

    public function __construct(ExampleRequest $request) {
        $this->request = $request;
    }

    public function handle($request, Closure $next)
    {
    // validate here.

        return $next($request);
    }
}

Second one is ugly but that is what you want to do so...

LearningLaravelYai's avatar

Thanks, that's so perfect.. and adding this will get the values easy - for both situations:

        public function store($a, $b)
        {
            $a = request('my_example',  $a);
            $b = request('example',  $b);

Now it is just a question if it is worth, scattering it out in all these files :D

Please or to participate in this conversation.