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

fdusautoir's avatar

Trigger controller's action

Hi there.

I have a CartController with a getFinish method. In this one, I want to call the OrderController create method. What's the cleaner way to proceed ?

0 likes
11 replies
Jeffberry's avatar

This is how I do it, I have a "controllerReroute" method in my BaseControlelr

    /**
     * @param       $class
     * @param       $method
     * @param array $arguments
     *
     * @return mixed
     */
    public function controllerReroute($class, $method, array $arguments = [])
    {
        $controller = $this->app->make($class);
        return $this->app->call([$controller, $method], $arguments);
    }

You would need to inject the Application as $this->app into your Controller for that snippet to work (or use the alternative app() which I try to avoid).

If you don't want to create a helper method you can just throw this snippet into your getFinish method though:

$controller = app()->make('App\Http\Controllers\OrderController');
$arguments = []; // you need to put the arguments that the "create" method requires in here
return  app()->call([$controller, 'create'], $arguments);
Jeffberry's avatar

@pmall He is not calling the controller from something other than an HTTP request. Calling a controller method from another controller method (while a little odd) is still valid. It's staying within the same layer, and it's technically still being called by the HTTP request. That's why my helper method calls it a controllerReroute. You're just rerouting the controller/method that Laravel chose to call.

Sometimes this can be useful though. A command would be useful if he was trying to make something happen. He is just asking how to call Controller A from Controller B.

Granted even though I have the helper method I haven't found any uses for it yet in my Laravel project(s); but this is something I used at times on my old non-Laravel projects.

colourmill's avatar

Ideally, nothing happens in your controller other than it being an intermediary between the request with the data that goes in or out and your underlying functionality, the meat of your application. Since you want to "run" this controller method from another controller, it probably means you have a lot of functionality in there that is best placed somewhere else so that it becomes reusable.

There are many ways to do this, the use of a a repository being one, and possibly the most straight forward. You can inject the repository in your method or the constructor inside the/any controller.

// CartController.php
public function finish(Request $request, Order $order) {
    $order->create($request->all());
}
thepsion5's avatar

If Controller B isn't making anything happen, there'd be no reason to call it, would there? If it's just generating HTML you'd use a redirect.

Jeffberry's avatar

Agreed, this is not the ideal setup and it usually means something is wrong. However, I do a lot of development work for XenForo and they use this methodology extensively, which is where I got my "controllerReroute" helper from. I have yet to use the Reroute feature in my Laravel project because it is usually not needed, but here is a use case where XenForo implements it:

public function actionIndex()
{
    $forumId = $this->_input->filterSingle('node_id', XenForo_Input::UINT);
    $forumName = $this->_input->filterSingle('node_name', XenForo_Input::STRING);
    if ($forumId || $forumName)
    {
        return $this->responseReroute(__CLASS__, 'forum');
    }

    ... Show the index of ALL forums
}   

Basically what this is doing is allowing the "index" route to serve as both the view for a specific forum as well as all forums. If no forum_id is provided in the URI, then the true "index" is shown where all forums are listed. If however a forum id is provided, then the controller is rerouted to a method that displays only that forum.

Is there better ways to do this? Absolutely. Especially in Laravel (XenForo is written on top of Zend). But still, there can sometimes be a use for this functionality.

thepsion5's avatar

Why wouldn't you just do this?

$forumIdentifier = ($forumId) ?: null;
$forumIdentifier = ($forumIdentifier) ?: $forumName;
if($forumIdentifier) {
    return $this->forum($forumIdentifier);
}
Jeffberry's avatar

If I remember correctly, they allow both routes to be accessed (index route and "forum" route). I am not the author of XenForo though so I cannot answer that question for you. I only do paid work for the software :) I'm sure there are at least twelve different ways to skin this cat. That is just the way they chose to do it. Not ideal, but not forbidden either.

fidgetwidget's avatar

Just to put another case for doing this out there, and ask if maybe there is a better/more elegant way to solve for this.

I have a ThreadsController and a CommentsController Comments being children of Threads, you typically get at a comment through the thread it belongs to (thread_id, comment_id) However, when you are looking at the context of a single comment (when reviewing it for moderation for example), the thread_id isn't necessarily as easy to get at. So having a way to get at the Comment actions without having to go through the thread meant I was going to have to duplicate some of the actions in the ThreadsController into a CommentsController that DIDNT have the thread context requirement (e.g. CommentModerationController)

The same view is being rendered, the same eloquent requests are being made, so instead of writing the 5 or 6 lines twice, wouldn't it be more elegant to just write the ONE App:make('CommentsController)->action("show", ["", $comment_id]);

martinbean's avatar

@fdusautoir You should never call a controller action from another. If you have cross-cutting logic like this, wrap it up into a service object and then call that in your controller action. Something like this:

class CartController extends Controller
{
    public function __construct(OrderService $orderService)
    {
        $this->orderService = $orderService;
    }

    public function complete()
    {
        // Pass in whatever data you need to place an order as parameters
        $this->orderService->placeOrder();

        // Redirect etc.
    }
}
1 like
devartpro's avatar

Hey, I used @Jeffberry method, but I can't return a view from the called controller. What I get is an empty page, no errors in laravel or server/php logs. Any idea why?

...
class PageController extends Controller {

    public function show(PageInterface $page, $slug)
    {       
        $data = Cache::remember($slug, 60, function() use ($page, $slug) {

            return $page->getPageBySlug($slug);
            
        });

        //dump($data); exit; /* I get the data well */

        return view('frontend.pages.page')->with('page', $data);
    }
}

Dumping the return view() i get the following: I get the full view object, but returning the view gives empty page, and no errors..

Please or to participate in this conversation.