Single Action Controller in Laravel

There are some magical functions in PHP, and __invoke is one of them.

Through this __invoke method, we can create classes with just one function __invoke in them, and whenever their object is called it will directly call the __invoke method, it means you don’t have to manually say $obj->someFunction() .

You can always find the documentation for this method on the official documentation page.

Where can I use it?

That’s a fair question. Whenever we get a new functionality anywhere, we need to know where I can use it. The one use case I am going to show here is SRP.

SRP

It stands for Single Responsibility Principle and it is defined in PHP as any class should only have one reason to change. It makes our application more robust and testable. And anytime we want to change in our application, we only need to change at one place.

How is it relevant with Laravel?

For implementing SRP in Laravel, one way is to use, Single Action Controllers. The controller will have only one method __invoke and you can directly use controller name in route, rather than specifying its method too in route.

Previously you will have to do something like below:

Route::get('posts', 'PostController@index');

Now you can:

Route::get('posts', 'PostIndexController');

Note: It is not a new feature in Laravel. It is just a way you can use PHP magic function to implement SRP in your Laravel project. This feature was made available from PHP v5.3.

How to use it in a Laravel Project?

Let’s just a create quick demo to understand, how we can use the __invokemethod in a laravel application.

  1. Create Model and Migration for posts. (Let’s go with posts).

php artisan make:model Post -m

The above command will create a model App\Post and also it’s migration.

2. Change the migration file accordingly and run php artisan migrate.

Schema::create('posts', function (Blueprint $table) {
    $table->increments('id');
    $table->string('title');
    $table->text('body');
    $table->timestamps();
});

3. Create a view for creating a post with two fields, title and body.

@extends('layouts.app')
@section('content')
<form action="{{ route('posts.store') }}" method="POST">
    {{ csrf_field() }}
    <div class="form-group">
        <label for="title">Title</label>
        <input name="title" type="text" class="form-control" id="title" placeholder="Enter Title" value="{{ old('title') }}">
    </div>
    <div class="form-group">
        <label for="body">Body</label>
        <textarea name="body" id="body" class="form-control" placeholder="Body">{{ old('body') }}</textarea>
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
</form>
@endsection

4. Create a controller for this view. PostCreateController

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PostCreateController extends Controller
{
   /**
    * Display a listing of the resource.
    *
    * @return \Illuminate\Http\Response
    */
    public function __invoke()
    {
        return view('posts.create');
    }
}

5. And now the route.

Route::get('posts/create', 'PostCreateController');

Notice that, you don’t have to specify the method name with route definition.

Note: I know, I create my routes way earlier than step 5 or maybe it’s my first step to create a module. But you have to take care when using SAC’s in your routes, you have to first define the controller and then create a route for this or it will result in an error.

Now, if you look, it will render the view as it will do when using a regular controller.

Just like above, you can create a controller class for every method for your resource.

Drawbacks

Until now, we only talked about benefits of using __invoke . Now we will talk about one drawback of using it.

You can not use resource route

If you use this method, you will not be able to use the Route::resourcemethod, you have to define every route of your resource and it’s corresponding controller. You can only use Route::resource if you have a single controller handling all of your resource methods.

It would look something like this:

invoke code example

Conclusion

You can use SAC in your laravel application to implement SRP.

There are both the benefits and also a drawback of creating controllers this way.

But it sure is a better way to architect your application.

I also have created a demo for this application, if you have any doubts on it’s implementation.

single action controller demo

You can find it here.

Interesting Links

Single Action Controller in Laravel

You May Also Like

Leave a Reply

Your email address will not be published.