How7o
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Reading: How to Call a Controller Method from Another Controller in Laravel
Share
How7oHow7o
Font ResizerAa
  • OS
Search
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Follow US
© 2024–2026 How7o. All rights reserved.
How7o > Free Laravel, PHP, WordPress & Server Tutorials > 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.
[mc4wp_form]
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
Most Popular
Laravel Eloquent ORM — a model class mapping to a database table with query methods
Laravel Eloquent ORM: The Complete Guide to Querying Your Database
June 16, 2026
Set vi as the default editor in Ubuntu — a terminal opening the vim editor
How to Set vi (Vim) as the Default Editor in Ubuntu
June 8, 2026
rsync says ALL DONE but files are missing — a terminal showing ALL DONE next to an empty folder
rsync Says “ALL DONE” but Files Are Missing: How to Verify
June 8, 2026
Migrate a website to a new server with rsync — files copying from an old server to a new one over SSH
How to Migrate a Website to a New Server With rsync
June 8, 2026
Bun runtime — faster JS toolkit replacing npm in Laravel projects
How to Install Bun Runtime on Ubuntu (And Use It in a Laravel Project)
May 24, 2026

You Might Also Like

Set A4 paper size in CSS for printing
Web Development

How to Set A4 Paper Size in CSS for Print

5 Min Read
MySQL 8 create user and grant privileges on Ubuntu
Web Development

How to Create Users and Grant Privileges in MySQL 8 on Ubuntu

8 Min Read
Store a PHP array in a MySQL database with JSON
Web Development

How to Store a PHP Array in a MySQL Database

5 Min Read
Laravel run project from GitHub — git clone through artisan serve pipeline
Web Development

How to Run a Laravel Project from GitHub

8 Min Read
How7o

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

Tools

  • Age Calculator
  • Word Counter
  • Image Upscaler
  • Password Generator
  • QR Code Generator
  • See all tools→

Pranks

  • Fake Blue Screen Prank
  • Hacker Typer
  • Fake iMessage Generator
  • Windows XP Crash Prank
  • Windows 11 Update Prank
  • See all prank screens →

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service
  • Sitemap
© 2024–2026 How7o. All rights reserved.
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?