← BACK
Laravel / Routing

Simplify Complex Actions with Single-Action Invokable Controllers

Punyapal Shah • • 1 min read
edit this tip →

Use __invoke() in dedicated Single-Action Controllers to encapsulate complex domain operations into isolated, focused classes.

As controllers grow, large multi-action classes often accumulate disparate dependencies and private helper methods used by only one endpoint.

Single-action controllers implement PHP's magic __invoke() method, focusing on one specific responsibility.

Generating an Invokable Controller

Generate an invokable controller using Artisan:

php artisan make:controller GenerateInvoiceReportController --invokable

Controller Implementation

namespace App\Http\Controllers;

use App\Models\Invoice;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class GenerateInvoiceReportController extends Controller
{
    public function __invoke(Request $request): Response
    {
        $invoices = Invoice::whereBetween('created_at', [
            $request->date('start_date'),
            $request->date('end_date'),
        ])->get();

        return response()->view('reports.invoices', compact('invoices'));
    }
}

Clean Route Registration

When registering an invokable controller in your routes file, pass the class name directly without specifying a method:

use App\Http\Controllers\GenerateInvoiceReportController;
use Illuminate\Support\Facades\Route;

// Clean, single-class route mapping
Route::get('/reports/invoices', GenerateInvoiceReportController::class);

Summary

  • Encapsulates isolated, high-complexity operations (reports, checkouts, webhooks).
  • Keeps dependency injection minimal and focused on that single action.
  • Route definitions map cleanly to the class name without requiring method strings.

Related Tips

View all tips →
Laravel Routing

Handle Unmatched Routes with Route::fallback()

Use Route::fallback() at the end of your routes file to serve custom 404 views, API error payloads, or Single Page Application (SPA) entry points.

READ >

// Got a tip in mind? Contributions are always welcome