Invokable Single Action Controllers in Laravel
Saturday, November 30, 2024
// 2 min read
Table of Contents
A single action controller in Laravel is a controller that does one job. It is particularly useful to have this type of controller if your route needs to handle complex logic.
The invoke method
The single action controller uses PHP's __invoke
magic method. If a class has an invoke method, you can call the class as an object.
For example:
<?php
class Greeting
{
public function __invoke($name)
{
return "Hello, $name! ";
}
}
// Create an instance of the class
$greeting = new Greeting();
// Call the object as a function
echo $greeting("Gergory"); // Outputs: Hello, Gergory!
?>
Creating a single action Controller
Let's assume that in your application, the user has an option to delete his/her account. Upon deletion, there are a couple of jobs that your application must run:
send a notification email about account deletion
clean up any user-related data
delete the user
finally, log out the user
You may use the make:controller
artisan command with the --invokable
option to generate a single action controller.
php artisan make:controller DeleteUserAccountController --invokable
This creates a controller file with the __invoke
method:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DeleteUserAccountController extends Controller
{
/**
* Handle the incoming request.
*/
public function __invoke(Request $request)
{
//
}
}
After adding the necessary scripts for each step, this is how my controller looks like:
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Mail\AccountDeleted;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
class DeleteUserAccountController extends Controller
{
public function __invoke(Request $request)
{
// Validate confirmation input
$request->validate([
'confirm' => 'required|boolean', // Ensure a confirm checkbox is checked
]);
/** @var User */
$user = Auth::user();
// Send a notification email about the account deletion
Mail::to($user->email)->send(new AccountDeleted($user));
// Log the user out
Auth::logout();
// Invalidate the session
$request->session()->invalidate();
// Regenerate the session token
$request->session()->regenerateToken();
// Perform user-related cleanup tasks (if required)
$user->cleanUpData();
// Delete the user account
$user->delete();
// Redirect to the front page with a flash message
return redirect('/')
->with('status', 'Your account has been deleted successfully.');
}
}
Single action Route
Now you need to create your route, in the case of a single action controller, you only need to reference the class name without specifying the controller action.
Route::delete('/delete-account', App\Http\Controllers\DeleteUserAccountController::class)
->middleware('auth')
->name('delete-account');
You can assign middleware, give it a name, and add route parameters as you normally do with other routes. Because this route is only available for logged-in users, I added the auth middleware.
Advantages of Single Action Controllers
simplicity: it only does one job, this way makes the code more focused and easier to understand
maintainability: for the same reason, it is easy to change and maintain
testability: and simple to test
Disadvantages of Single Action Controller
A Single Action Controller offers numerous advantages, but they are not always the best choice for every scenario.
increased files: if each action requires its own controller, that leads to more files in the project. It is recommended to only use this type of controller for more complex route actions.
reduced conceptual unity: grouping related methods in one controller provides a sense of context and cohesion. For instance, all user-related CRUD operations in a Resource Controller with index, store, update, and destroy methods make more sense than using four separate invoke controllers.
If you want to support my work, you can donate using the button below. Thank you!