DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 968,873 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Massive  brains
Massive brains

Posted on

Single Method Controllers in Laravel

We all agree that methods and function should do one thing only. We call this Single Responsibility Principle.

However, the fact that methods should follow SRP does not imply that we should have a controller housing many (almost) independent methods which would result in a very unstructured business logic.

Having a single method controller is a fantastic way of upholding the Single Responsibility Principle. For example, take a look at the controller below

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Plan;

class PlansController extends Controller
{
    public function index()
    {
        //Logic to Get All Plans
    }

    public function create(Request $request)
    {
        //Logic to create new Plan
    }


    public function inviteUser(Request $request)
    {
        //Logic to invite user to plan
    }
}

The first thought that would come to mind is that the inviteUser method does not belong to this controller. We should have something like InviteUserController. And that is absolutely what we should do.

From the name of this controller, it is expected to do one thing only - Invite a user to a specific plan.

So we can simply have something like

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class InviteUserController extends Controller
{

    public function inviteUser(Request $request)
    {
        //Logic to invite user to plan
    }
}

and we should be done right? - Well how about if this could be done better? - Introducing Magic Method __invoke :)

PHP has several Magic methods. Magic methods are named with two underscores at the start, which get called automatically when a particular event happens.

The __invoke() method gets called when the object is called as a function. When you declare it, you say which arguments it should expect. Here's a trivially simple example:

class Human {

  public function __invoke() {

    echo "Sophisticated creature";
  }
}

We can instantiate a Human object, and then just use it like a function:

$victor = new Human();
$victor(); // Sophisticated creature

With this understanding, we can simply rename the inviteUser method of the InviteUserController to __invoke as seen below

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class InviteUserController extends Controller
{

    public function __invoke(Request $request)
    {
        //Logic to invite user to plan
    }
}

And in the routes file we would no more use the string literal convention to map a route to this controller instead we add the class like

use App\Http\Controllers\Api;

Route::get('/invite', InviteUserController::class)

Let me know what you think about single method controllers!

Credit: lornajane

PS: This is my first blog post on Dev.to

Top comments (9)

Collapse
 
alexparra profile image
Alex Parra

I’ve never did this before... but I do agree that Controllers should be kept lean.
What specific benefits have you found in this pattern? I’m assuming easier debugging but can’t see performance benefits and in my opinion it’s not better developer experience compared to several controllers with a handful of methods that are common to a resource or domain.

Collapse
 
dealloc profile image
Wannes Gennar • Edited on

You'll place all related controllers in the same namespace (App\Http\Controllers\Users{Register,Invite, ...}UserController.php)

As indicated in this article, it adheres more closely to the single responsibility principle, that a given class should only do a specific thing.

Personally, I'm leaning more and more towards ADR where a single method controller ties in perfectly.
I highly recommend looking into ADR more, and see for yourself where the advantages lie for your project.

Collapse
 
nyc4m profile image
Baptiste Prunot

I have used single method controller once in a symfony project, and I've got to admit that it's indeed much more clear/easy to read !

Collapse
 
bertheyman profile image
Bert Heyman • Edited on

Good write up!

I read about this technique before - have to admit I didn't use it yet, as I think I'll end up needing more functions from the controller and thus editing everything back.

Collapse
 
slifin profile image
Adrian Smith

methods !== functions

Collapse
 
jorge_rockr profile image
Jorge RamΓ³n

Sounds totally nice to me, I will try it in my next project!

Collapse
 
carlosas profile image
Carlos Alandete Sastre

I think what you are naturally looking for is the command/handler pattern to encapsulate use cases.

πŸ‘‹ Every week new members join DEV and share a bit about them in our Welcome Thread

Welcome them to DEV and share a bit about yourself