fetzi.dev

Using Laravel's Responsable Interface

3 minutes

In the next Laravel version 5.5 a new interface called Responseable gets introduced. It is a simple interface that defines one method called toResponse that returns an instance of Illuminate\Http\Response.

This new feature is looking really nice. Especially for the project I’m currently working on at work. We use a variety of datasources (php api’s, elasticsearch, cache, …) in our controllers. This leads to a very unstructured and big controller file.

In addition to multiple datasources we use Handlebars for template rendering on the server side and (of course) on the client side to rerender parts of our application. To be able to use handlebars in PHP we need to convert all our view data into arrays.

This situation led us to use a Laravel anti pattern - View Models 😱. We need this extra layer to be able to prepare our models (from the different sources) for our views.

Now let’s look at a simple example:

<?php

class DemoController {

    public function index()
    {
        // ...

        $user = $api->fetch($userId);
        $company = $elasticsearch->find($companyId);

        // ...

        $viewData = $demoIndexViewModel->prepare($user, $company);

        if (request()->ajax()) {
            return response()->json($viewData);
        } else {
            return response()->view('demo.index', $viewData);
        }
    }
}

At first we fetch our data, then we call our controller view model (or multiple if the controller is too simple). The last if-else structure can be found in every controller and is needed to either send the view data directly to client for rerendering or to fully render the page.

How Responsable can help us

First thing would be to introduce ControllerActionResponse classes that will be responsible for the View Model stuff and the response preparation. To be able to remove the code duplications a BaseResponse class is used that does the Responsable implementation and defines an abstract method for preparing our data.

<?php

abstract class BaseResponse implements Responsable {

    /**
     * @var string
     */
    protected $view;

    abstract protected function prepare() : array;

    public function toResponse()
    {
        $data = $this->prepare();

        if (request()->ajax()) {
            return response()->json($data);
        } else {
            return response()->view($this->view, $data);
        }
    }
}

For our DemoController@index action we can now implement a DemoIndexResponse that extends BaseResponse. It is responsible for doing the model to view transformation, in our case with view models.

<?php

class DemoIndexResponse extends BaseResponse {

    // ... variables and ViewModel initialization

    public function __construct(User $user, Company $company)
    {
        $this->user = $user;
        $this->company = $company;

        $this->view = 'demo.index';
    }

    protected function prepare()
    {
        return array_merge(
            $this->userViewModel->prepare($this->user),
            $this->companyViewModel->prepare($this-company)
        );
    }
}

This leads to a clean controller action that is responsible for fetching the required data and passing it to the custom response class.

<?php

class DemoController {

    public function index()
    {
        // ...

        $user = $api->fetch($userId);
        $company = $elasticsearch->find($companyId);

        // ...

        return new DemoIndexResponse($user, $company);
    }
}

Conclusion

The Responsable feature helps a lot to clean up our controller actions. It moves the response logic from the controller into its own layer. Of course it does not solve the problem with the view models but it gives us a starting point for rethinking the whole data preparation layer.

Resources

This might be also interesting

Do you enjoy reading my blog?

sponsor me at ko-fi