Clean Architecture with Laravel
Tags: laravel, architecture, php, tutorial
Published: 2021-08-04 21:44:51

---
title: Clean Architecture with Laravel
published: true
description: learn how to decouple your business logic in your Laravel app
tags: [laravel, architecture, php, tutorial]
//cover_image: https://direct_url_to_image.jpg
---

[Uncle Bob](https://en.wikipedia.org/wiki/Robert_C._Martin)'s [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) is quite the hype right now in the architects' world. But when it comes to *actual implementations*, nothing notable has been proposed for [Laravel](https://laravel.com/).

And that's understandable: Laravel's [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) architecture and its tendency to let you cross layers all the time using [Facades](https://laravel.com/docs/8.x/facades) doesn't help designing clean, decoupled software parts.

So today, I'm going to present you a working implementation of the Clean Architecture principles **inside a Laravel app**, as explained in [The Clean Architecture](https://g.co/kgs/ktzWmJ) by [Robert C. Martin](https://en.wikipedia.org/wiki/Robert_C._Martin).

The complete, working implementation of the concepts explained here is available on my [GitHub repository](https://github.com/bdelespierre/laravel-clean-architecture-demo). I recommend you have a look at the actual code while reading this article.

For once, let's get our hands *clean* 👍

## It all started with a diagram

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1rvpoj6f7ynohc7nrtx.png) 

> The architecture must support the use cases. [...] This is the first concern of the architect, and the first priority of the architecture.

<small>([The Clean Architecture](https://g.co/kgs/ktzWmJ) chapter 16, p148.)</small>

If you've never heard of use cases, you can think of it as a *feature*, the capacity of a system to do something meaningful. [UML](https://en.wikipedia.org/wiki/Unified_Modeling_Language) let you describe them using the well-named [Use Case Diagrams](https://en.wikipedia.org/wiki/Use_case_diagram).

In <abbr title="Clean Architecture">CA</abbr>, use-cases are at the heart of the application. They're the **microchip** that controls the machinery of your app.

## So, how are we supposed to implement those use cases then?

Glad you asked! Here's a second diagram:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ui2ok52dr7zgxrygkmbi.png) 

Let me explain briefly, and we'll dive into the *actual code*.

The pink line is the *flow of control*; it represents the order in which the different *components* are being executed. First, the user changes something on the view (for instance, he submits a registration form). This interaction becomes a `Request` object. The controller reads it and produces a `RequestModel` to be used by the `UseCaseInteractor`.

The `UseCaseInteractor` then does its thing (for instance, creates the new user), prepares a response in the form of a `ResponseModel`, and passes it to the `Presenter`. Which in turn updates the view through a `ViewModel`.

Wow, that's a lot 😵 That's probably the main criticism made to <abbr title="Clean Architecture">CA</abbr>; it's **lenghty**!

The call hierarchy looks like this:

```
Controller(Request)
  ⤷ Interactor(RequestModel)
      ⤷ Presenter(ResponseModel)
          ⤷ ViewModel
```

## What about the ports?

I can see you're quite the observer! For the **low lever layers** (the Use Cases and the Entities, often referred to as the **Domain**, and represented as the red and yellow circles in the schema above) to be **decoupled** from the **high-level layers** (the framework, represented as the blue circle), we need **adapters** (the green circle). Their job is to convey messages between high and low layers using their respective API and contracts (or interfaces).

Adapters are absolutely crucial in <abbr title="Clean Architecture">CA</abbr>. They guarantee that changes in the framework won't *require* changes in the domain and vice-versa. In <abbr title="Clean Architecture">CA</abbr>, we want our use cases to be abstracted from the framework (the actual implementation) so that both can change at will without propagating the changes on other layers.

A traditional PHP/HTML application designed with clean architecture can therefore be transformed into a REST API **only** by changing its controllers and presenters - **the Use Cases would remain untouched!** Or you could have both HTML + REST side by side using the same Use Cases. That's pretty neat if you ask me 🤩

To do that, we need to *"force"* the adapter to *"behave"* the way each layer needs it to behave. We're going to use interfaces to define inputs and output **ports**. They say, in essence, *"if you want to talk to me, you're going to have to do it this way!"*

## Blah blah blah. I want to see some code!

Since the `UseCaseInteractor` will be at the heart of everything, let's start with this one:

```php
class CreateUserInteractor implements CreateUserInputPort
{
    public function __construct(
        private CreateUserOutputPort $output,
        private UserRepository $repository,
        private UserFactory $factory,
    ) {
    }

    public function createUser(CreateUserRequestModel $request): ViewModel
    {
        /* @var UserEntity */
        $user = $this->factory->make([
            'name' => $request->getName(),
            'email' => $request->getEmail(),
        ]);

        if ($this->repository->exists($user)) {
            return $this->output->userAlreadyExists(
                new CreateUserResponseModel($user)
            );
        }

        try {
            $user = $this->repository->create(
                $user, new PasswordValueObject($request->getPassword())
            );
        } catch (\Exception $e) {
            return $this->output->unableToCreateUser(
                new CreateUserResponseModel($user), $e
            );
        }

        return $this->output->userCreated(
            new CreateUserResponseModel($user)
        );
    }
}
```

There are 3 things we need to pay attention to here:

+ The interactor **implements** the `CreateUserInputPort` interface,
+ The interactor **depends on** the `CreateUserOutputPort`,
+ The interactor doesn't make the `ViewModel` himself, instead it **tells** the presenter to do it,

Since the `Presenter` (abstracted here by `CreateUserOutputPort`) is located in the adapters (green) layer, calling it from the `CreateUserInteractor` is indeed an excellent example of [**inversion of control**](https://en.wikipedia.org/wiki/Inversion_of_control): the framework isn't *controlling* the use cases, the use cases are *controlling* the framework.

If you find it too boringly complicated, forget all that and consider that all the *meaningful decisions* are being made at the use case level - including choosing the response *path* (`userCreated`, `userAlreadyExists`, or `unableToCreateUSer`). The controller and the presenters are just obedient slaves, devoid of business logic.

We can never rehearse it enough so sing it with me: **CONTROLLERS 👏 SHOULD 👏 NOT 👏 CONTAIN 👏 BUSINESS 👏 LOGIC 👏**

## So how does it look from the controller's perspective?

For the controller, life is simple:

```php
class CreateUserController extends Controller
{
    public function __construct(
        private CreateUserInputPort $interactor,
    ) {
    }

    public function __invoke(CreateUserRequest $request)
    {
        $viewModel = $this->interactor->createUser(
            new CreateUserRequestModel($request->validated())
        );

        return $viewModel->getResponse();
    }
}
```

You can see it relies on the `CreateUserInputPort` abstraction instead of the actual `CreateUserInteractor` implementation. It gives us the flexibility to change the use case at will and make the controller testable. More on that later.

## Okay, that's very simple and stupid indeed. What about the presenter?

Again, very straightforward:

```php
class CreateUserHttpPresenter implements CreateUserOutputPort
{
    public function userCreated(CreateUserResponseModel $model): ViewModel
    {
        return new HttpResponseViewModel(
            app('view')
                ->make('user.show')
                ->with(['user' => $model->getUser()])
        );
    }

    public function userAlreadyExists(CreateUserResponseModel $model): ViewModel
    {
        return new HttpResponseViewModel(
            app('redirect')
                ->route('user.create')
                ->withErrors(['create-user' => "User {$model->getUser()->getEmail()} alreay exists."])
        );
    }

    public function unableToCreateUser(CreateUserResponseModel $model, \Throwable $e): ViewModel
    {
        if (config('app.debug')) {
            // rethrow and let Laravel display the error
            throw $e;
        }

        return new HttpResponseViewModel(
            app('redirect')
                ->route('user.create')
                ->withErrors(['create-user' => "Error occured while creating user {$model->getUser()->getName()}"])
        );
    }
}
```

Traditionally, all that code would have been `ifs` at the controller's end. Which would have forced the use case to find a way to *"tell"* the controller what happened (using `$user->wasRecentlyCreated` or by throwing exceptions, for example.)

Using presenters controlled by the use case allows us to choose and change the outcomes without touching the controller. How great is that?

## So everything relies on abstractions, I imagine the container is going get involved at some point?

You're absolutely right, my good friend! It pleases me to be in good company today.

Here's how to wire all that in `app/Providers/AppServiceProvider.php`:

```php
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        // wire the CreateUser use case to HTTP
        $this->app
            ->when(CreateUserController::class)
            ->needs(CreateUserInputPort::class)
            ->give(function ($app) {
                return $app->make(CreateUserInteractor::class, [
                    'output' => $app->make(CreateUserHttpPresenter::class),
                ]);
            });


        // wire the CreateUser use case to CLI
        $this->app
            ->when(CreateUserCommand::class)
            ->needs(CreateUserInputPort::class)
            ->give(function ($app) {
                return $app->make(CreateUserInteractor::class, [
                    'output' => $app->make(CreateUserCliPresenter::class),
                ]);
            });
    }
}
```

I added the CLI variant to demonstrate how easy it is to swap the presenter to make the use case return different `ViewModel` instances. Have a look a [the actual implementation](https://github.com/bdelespierre/laravel-clean-architecture-demo) for more details 👍

## Can I test this?

Oh my! It's **begging you to!** Another good thing about <abbr title="Clean Architecture">CA</abbr> is that it relies so much on abstractions it makes testing a breeze.

```php
class CreateUserUseCaseTest extends TestCase
{
    use ProvidesUsers;

    /**
     * @dataProvider userDataProvider
     */
    public function testInteractor(array $data)
    {
        (new CreateUserInteractor(
            $this->mockCreateUserPresenter($responseModel),
            $this->mockUserRepository(exists: false),
            $this->mockUserFactory($this->mockUserEntity($data)),
        ))->createUser(
            $this->mockRequestModel($data)
        );

        $this->assertUserMatches($data, $responseModel->getUser());
    }
}
```

The complete test class is available [here](https://github.com/bdelespierre/laravel-clean-architecture-demo/blob/master/tests/Unit/CreateUserUseCaseTest.php).

I use [Mockery](https://github.com/mockery/mockery) for, well, mocking, but it will work with anything. It might seem like a lot of code, but it's actually quite simple to write, and it will give you 100% coverage of your use cases effortlessly.

## Isn't this implementation slightly different from the book?

Yes, it is. You see <abbr title="Clean Architecture">CA</abbr> has been designed by Java people. And, in most cases, in a Java program, if you want to update the view, you can do so directly from the `Presenter`.

But not in PHP. Because we don't fully control the view and because the frameworks are structured around the concept of controllers returning a response.

So I had to adapt the principles and make the `ViewModel` *climb the call stack* up to the controller to return a proper response. If you can come up with a better design, please let me know in the comments 🙏

---

Would you please let me know what you think in the comments? **Your opinion matters to me**, for I write those articles to challenge my vision and learn new things every day.

You are, of course, welcome to suggest changes to the demo repository by submitting a [pull-request](https://github.com/bdelespierre/laravel-clean-architecture-demo/pulls). Your contribution is much appreciated 🙏

This article took me four days of research, implementation, testing, and writing. I would really appreciate a like, a follow, and maybe a share on your social networks 🙏

Thanks, guys, you contribution helps to keep me motivated to write more articles for you 👍

---

Further reading:

+ [Clean Coder Blog](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
+ [Entity-Control-Boundary](https://en.wikipedia.org/wiki/Entity-control-boundary)
+ [Clean Architecture: Use case containing the presenter or returning data?](https://softwareengineering.stackexchange.com/questions/357052/clean-architecture-use-case-containing-the-presenter-or-returning-data)
+ [A button, as a “Clean Architecture” plugin](https://codereview.stackexchange.com/questions/148809/a-button-as-a-clean-architecture-plugin)
+ [UML Diagrams cheatsheet](http://www.ivencia.com/index.html?/softwarearchitect/chapter1/chapter1.htm)