How7o
  • Home
  • Tools
  • Prank Screens
  • Contact
  • Blog
Reading: How to Call a Controller Method from Another Controller in Laravel
Share
Subscribe Now
How7oHow7o
Font ResizerAa
  • Marketing
  • OS
  • Features
  • Guide
  • Complaint
  • Advertise
Search
  • Home
  • Tools
  • Prank Screens
  • Contact
  • Blog
Follow US
Copyright © 2014-2023 Ruby Theme Ltd. All Rights Reserved.
How7o > Blog > Web Development > How to Call a Controller Method from Another Controller in Laravel
Web Development

How to Call a Controller Method from Another Controller in Laravel

how7o
By how7o
Last updated: May 3, 2026
8 Min Read
Laravel call controller from another controller — app() and constructor injection patterns
SHARE

Calling one controller method from another in a Laravel app comes up most often when you’re extending a third-party codebase — a point-of-sale, a CMS, a marketplace plugin — and you want to hook additional logic onto an existing endpoint without editing its controller directly. This guide covers two container-aware patterns (the app() helper and constructor injection), explains why new SaleController() breaks, and points out when a redirect or a shared service class is the better answer.

Contents
  • TL;DR
  • Option 1 — Resolve via app()
  • Option 2 — Constructor inject
  • Why new SaleController() breaks
  • When a redirect is the better answer
  • The cleaner long-term answer — a service or action class
  • Frequently asked questions
  • Related guides
  • References

Last verified: 2026-04-23 on Laravel 11 with PHP 8.3. Originally published 2024-03-17, rewritten and updated 2026-04-23.

TL;DR

Resolve the target controller through Laravel’s service container and call the method on it: app(SaleController::class)->store($request). For long-lived dependencies, inject it via the constructor: public function __construct(protected SaleController $saleController) {}. Never instantiate with new — that bypasses the container and breaks constructor injection on the target.

Option 1 — Resolve via app()

The shortest path. The app() helper hands back a container-resolved instance with all constructor dependencies already wired up, so calling a method on it works the same as if Laravel had routed to it directly:

use App\Http\Controllers\SaleController;

class DeliveryController extends Controller
{
    public function addDelivery(Request $request)
    {
        // Delegate to the sale flow
        app(SaleController::class)->store($request);

        // Then layer on delivery-specific logic
        // ...
    }
}

The $request in addDelivery is the same Illuminate\Http\Request instance Laravel built for the incoming call; forwarding it to store($request) costs nothing. If store type-hints a form-request class (for example StoreSaleRequest), Laravel re-resolves and re-validates it when the method is invoked — so the target’s validation rules still run.

Option 2 — Constructor inject

When the caller needs the other controller in more than one method — or you want the dependency visible in the class signature — declare it as a constructor parameter. Laravel resolves it automatically:

use App\Http\Controllers\SaleController;

class DeliveryController extends Controller
{
    public function __construct(protected SaleController $saleController)
    {
    }

    public function addDelivery(Request $request)
    {
        $this->saleController->store($request);

        // Delivery extras
    }
}

PHP 8 constructor-promotion (protected SaleController $saleController) keeps the boilerplate minimal — you skip the separate property declaration and the manual assignment.

laravel call controller from another controller — app() vs constructor injection vs redirect decision

Why new SaleController() breaks

Most Laravel controllers have constructor-injected dependencies — a repository, a service, a mailer. Instantiating with new SaleController() bypasses the container entirely and skips that injection; the first time the controller tries to use one of those dependencies you’ll hit:

TypeError: Argument #1 ($saleRepository) to App\Http\Controllers\SaleController::__construct()
  must be of type App\Repositories\SaleRepository, none given

Always reach for app(SaleController::class) or injection. Both funnel through the container so dependencies resolve cleanly.

When a redirect is the better answer

If what you actually want is “after processing, continue into the other controller’s full HTTP handling” — middleware, throttling, validation, route-model binding — return a redirect to that route instead of calling the method directly:

return redirect()
    ->route('sales.store')
    ->withInput();

The browser makes a fresh POST to the target route, and Laravel runs the full request lifecycle. Pick this when the two controllers correspond to user-visible workflows (form A finishes at B); pick the method-call patterns above when you want in-process reuse on a single request.

The cleaner long-term answer — a service or action class

If you control both controllers, the Laravel-idiomatic move is to extract the shared logic into a service class (for reusable behavior) or an action class (for a single verb). Both controllers then inject the service:

// app/Actions/StoreSale.php
class StoreSale
{
    public function execute(Request $request): Sale
    {
        // Shared logic that used to live in SaleController@store
    }
}

// Both controllers depend on StoreSale, not on each other
class SaleController extends Controller
{
    public function store(Request $request, StoreSale $action)
    {
        $sale = $action->execute($request);
        return response()->json($sale);
    }
}

class DeliveryController extends Controller
{
    public function addDelivery(Request $request, StoreSale $action)
    {
        $sale = $action->execute($request);
        // ...delivery logic using $sale
    }
}

No controller-to-controller call, no container gymnastics — just two thin HTTP boundaries sharing an action. Reach for the cross-controller patterns only when the caller can’t modify the other controller’s file.

Frequently asked questions

Is calling a controller from another controller a laravel anti-pattern?

Usually, yes. Controllers are HTTP glue — they’re meant to receive a request, delegate to a service, and return a response. When you need to reuse logic across controllers, the Laravel-idiomatic answer is to extract that logic into a service class, action class, or trait and have both controllers call it. The cross-controller-call patterns in this post are pragmatic when you’re extending a third-party codebase you can’t refactor, not a general-purpose technique.

What’s the difference between app(SaleController::class) and constructor injection?

Both resolve the controller through Laravel’s service container, so dependencies (Request, services, repositories) are auto-wired correctly in both cases. Constructor injection is cleaner when you always need the instance — it’s declarative and shows up in the class signature. app(...) is better when the dependency is used in only one method, or when you want to resolve it lazily to avoid a hard coupling at class-load time.

Should I call new SaleController() directly?

No. Controllers have constructor-injected dependencies, and new bypasses the container entirely — any type-hinted parameters in __construct won’t resolve, and you’ll hit a TypeError the moment the controller tries to use them. Always go through app() or dependency injection.

How do I pass the current Request to the other controller’s method?

Just forward it: app(SaleController::class)->store($request). The $request in your current controller is the same Illuminate\Http\Request instance Laravel built for the incoming HTTP call; passing it across is free. If the target method uses a form request (StoreSaleRequest), Laravel resolves it when you call the method if you type-hint it — it re-validates the payload against the target’s rules.

What about just redirecting to the other controller’s route?

For a full HTTP-style handoff — fresh request lifecycle, middleware, validation — use a redirect: return redirect()->route('sales.store')->withInput();. This is the right answer when the two controllers correspond to user-visible workflows (submit form A, finish at B). Cross-controller method calls are for cases where you want in-process reuse, not a new request.

Related guides

  • How to Install Laravel on Ubuntu — fresh Laravel 11 setup before refactoring controllers.
  • Best Way to Insert or Update Records in Laravel Eloquent — the kind of logic that usually belongs in an action class, not a controller.
  • How to Retrieve Inputs with a Specific Prefix in Laravel Request — shaping the $request before you hand it off.
  • Laravel Nullable Exists Validation — form-request validation that stays put when controllers delegate.

References

Official Laravel container docs (app(), automatic resolution, constructor injection): laravel.com/docs/container.

TAGGED:configurationLaravelphp

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Copy Link Print
Previous Article Laravel Carbon not found error — namespace import fix Fix “Class Carbon not found” in Laravel
Next Article Laravel get config variable — config() helper and Config facade resolving dotted keys How to Get Config Variables in Laravel
Leave a Comment

Leave a Reply Cancel reply

You must be logged in to post a comment.

FacebookLike
XFollow
PinterestPin
InstagramFollow

Subscribe Now

Subscribe to our newsletter to get our newest articles instantly!
Most Popular
Laravel get config variable — config() helper and Config facade resolving dotted keys
How to Get Config Variables in Laravel
May 3, 2026
Laravel call controller from another controller — app() and constructor injection patterns
How to Call a Controller Method from Another Controller in Laravel
May 3, 2026
Laravel Carbon not found error — namespace import fix
Fix “Class Carbon not found” in Laravel
May 3, 2026
Laravel unknown column CONCAT fix — DB::raw and selectRaw bypass identifier escaping
How to Fix “Unknown column ‘CONCAT'” in Laravel
May 3, 2026
Laravel validate in rule — restricting input to an allow-list with in: and Rule::in
Laravel Validate Input to Specific Values (in Rule)
May 3, 2026

You Might Also Like

Dynamically set site title and tagline in WordPress by country
Web Development

How to Dynamically Set Site Title and Tagline in WordPress (By Country)

6 Min Read
CSS print styles shown in a clean print preview layout
Web Development

How to Add CSS Print Styles for Printer and Print Screen

7 Min Read
WooCommerce homepage filter to hide out of stock products
Web Development

Hide Out of Stock Products from Homepage in WooCommerce (Keep Them Visible Elsewhere)

5 Min Read
Step-by-step guide to upgrading the Linux kernel in CentOS 7 using ELRepo
Server Management

How to Upgrade the Linux Kernel in CentOS 7

9 Min Read
How7o

We provide tips, tricks, and advice for improving websites and doing better search.

Latest News

  • SEO Audit Tool
  • Client ReferralsNew
  • Execution of SEO
  • Reporting Tool

Resouce

  • Google Search Console
  • Google Keyword Planner
  • Google OptimiseHot
  • SEO Spider

Get the Top 10 in Search!

Looking for a trustworthy service to optimize the company website?
Request a Quote
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?