Laravel Invokable Controllers: A Complete Guide for Modern PHP Development


Laravel Invokable Controllers are a powerful feature that can significantly improve your application's architecture and code organization. In this comprehensive guide, we'll explore what invokable controllers are, why you should use them, and how to implement them effectively in Laravel 12.
What are Laravel Invokable Controllers?
Invokable Controllers in Laravel are single-action controllers that contain only one public method: the __invoke()
method. Unlike traditional controllers that may handle multiple actions, invokable controllers follow the Single Responsibility Principle by focusing on one specific task.
When Laravel encounters an invokable controller in your routes, it automatically calls the __invoke()
method, making your routing cleaner and more intuitive.
Why Should You Use Invokable Controllers in Laravel?
1. Enhanced Code Organization
Invokable controllers promote better code organization by separating concerns. Each controller handles exactly one action, making your codebase more modular and easier to navigate.
2. Improved Readability and Maintainability
With single-purpose controllers, developers can quickly understand what each controller does without scanning through multiple methods. This improves code readability and reduces maintenance overhead.
3. Better Testing Strategy
Testing becomes more straightforward when each controller has a single responsibility. You can write focused unit tests that cover one specific functionality without worrying about side effects from other methods.
4. Cleaner Route Definitions
Invokable controllers make your route definitions more elegant and self-documenting. Instead of specifying both controller and method, you only need to reference the controller class.
5. Follows SOLID Principles
Invokable controllers naturally adhere to the Single Responsibility Principle, one of the core SOLID principles of object-oriented programming.
When Should You Use Invokable Controllers?
Perfect Use Cases:
1. Single-Purpose Actions
User registration
Password reset requests
File uploads
Email sending
API endpoints with one specific function
2. Form Handling When you have forms that perform one specific action, invokable controllers are ideal:
// ContactFormController handles only contact form submissions
Route::post('/contact', ContactFormController::class);
3. API Endpoints For RESTful APIs where each endpoint has a single, well-defined purpose:
// GetUserProfileController returns user profile data
Route::get('/api/user/profile', GetUserProfileController::class);
4. Command-like Operations Actions that represent commands in your domain:
ProcessPaymentController
SendNotificationController
GenerateReportController
When NOT to Use Invokable Controllers:
1. CRUD Operations For traditional CRUD operations, resource controllers are more appropriate as they handle multiple related actions (index, show, create, store, edit, update, destroy).
2. Complex Workflows If your controller needs to handle multiple related actions or has complex branching logic, a traditional controller might be more suitable.
How to Create and Use Invokable Controllers in Laravel 12
Creating an Invokable Controller
Use the Artisan command with the --invokable
flag:
php artisan make:controller SendNewsletterController --invokable
This generates a controller with the following structure:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class SendNewsletterController extends Controller
{
/**
* Handle the incoming request.
*/
public function __invoke(Request $request)
{
// Your controller logic here
}
}
Practical Example: User Registration Controller
Here's a real-world example of an invokable controller for user registration:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\RegisterRequest;
use App\Models\User;
use App\Services\UserRegistrationService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
class RegisterUserController extends Controller
{
public function __construct(
private UserRegistrationService $registrationService
) {}
/**
* Handle user registration request.
*/
public function __invoke(RegisterRequest $request): JsonResponse|RedirectResponse
{
$user = $this->registrationService->register(
$request->validated()
);
if ($request->expectsJson()) {
return response()->json([
'message' => 'User registered successfully',
'user' => $user
], 201);
}
return redirect()->route('dashboard')
->with('success', 'Registration successful!');
}
}
Route Definition
// routes/web.php
use App\Http\Controllers\Auth\RegisterUserController;
Route::post('/register', RegisterUserController::class)
->name('register');
Best Practices for Laravel Invokable Controllers
1. Use Descriptive Naming
Name your controllers based on the action they perform:
SendWelcomeEmailController
ProcessPaymentController
UpdateUserProfileController
2. Leverage Dependency Injection
Use Laravel's service container to inject dependencies:
public function __construct(
private EmailService $emailService,
private UserRepository $userRepository
) {}
3. Use Form Request Validation
Always validate input using Form Request classes:
public function __invoke(CreatePostRequest $request)
{
// Request is automatically validated
$validatedData = $request->validated();
}
4. Keep Controllers Thin
Move business logic to service classes:
public function __invoke(ProcessOrderRequest $request)
{
$order = $this->orderService->process($request->validated());
return response()->json($order);
}
5. Return Appropriate Responses
Handle both web and API responses gracefully:
public function __invoke(Request $request)
{
$result = $this->service->performAction($request->all());
if ($request->expectsJson()) {
return response()->json($result);
}
return redirect()->back()->with('success', 'Action completed!');
}
Performance Benefits in Laravel 12
Laravel 12 includes several optimizations that make invokable controllers even more efficient:
1. Improved Route Caching Invokable controllers work seamlessly with Laravel's route caching, resulting in faster route resolution.
2. Better Memory Usage Single-purpose controllers typically have smaller memory footprints compared to large controllers with multiple methods.
3. Enhanced Auto-loading Laravel 12's improved auto-loading mechanisms work more efficiently with focused, single-purpose classes.
Common Patterns and Examples
File Upload Controller
class HandleFileUploadController extends Controller
{
public function __invoke(FileUploadRequest $request)
{
$file = $request->file('upload');
$path = $file->store('uploads', 'public');
return response()->json(['path' => $path]);
}
}
API Resource Controller
class GetUserPostsController extends Controller
{
public function __invoke(User $user)
{
return PostResource::collection(
$user->posts()->published()->paginate(15)
);
}
}
Command Handler Controller
class ProcessRefundController extends Controller
{
public function __invoke(ProcessRefundRequest $request)
{
$refund = $this->refundService->process($request->validated());
event(new RefundProcessed($refund));
return redirect()->route('orders.show', $refund->order_id)
->with('success', 'Refund processed successfully');
}
}
Testing Invokable Controllers
Testing invokable controllers is straightforward and focused:
class RegisterUserControllerTest extends TestCase
{
public function test_user_can_register_successfully()
{
$userData = [
'name' => 'John Doe',
'email' => 'john@example.com',
'password' => 'password123',
'password_confirmation' => 'password123'
];
$response = $this->post('/register', $userData);
$response->assertRedirect('/dashboard');
$this->assertDatabaseHas('users', [
'email' => 'john@example.com'
]);
}
}
Conclusion
Laravel Invokable Controllers are a powerful tool for creating clean, maintainable, and focused code. They work exceptionally well for single-purpose actions and help enforce good architectural practices. In Laravel 12, they're more performant and easier to work with than ever before.
Consider using invokable controllers when you have single-purpose actions, want to improve code organization, or need to create focused, testable units of functionality. They're particularly valuable in modern Laravel applications that emphasize clean architecture and separation of concerns.
By following the best practices outlined in this guide, you'll be able to leverage invokable controllers effectively in your Laravel 12 applications, resulting in more maintainable and professional code.
Subscribe to my newsletter
Read articles from Asfia Aiman directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Asfia Aiman
Asfia Aiman
Hey Hashnode community! I'm Asfia Aiman, a seasoned web developer with three years of experience. My expertise includes HTML, CSS, JavaScript, jQuery, AJAX for front-end, PHP, Bootstrap, Laravel for back-end, and MySQL for databases. I prioritize client satisfaction, delivering tailor-made solutions with a focus on quality. Currently expanding my skills with Vue.js. Let's connect and explore how I can bring my passion and experience to your projects! Reach out to discuss collaborations or learn more about my skills. Excited to build something amazing together! If you like my blogs, buy me a coffee here https://www.buymeacoffee.com/asfiaaiman