cult3

Using View Composers in Laravel 4

Feb 10, 2014

Table of contents:

  1. The Problem of repetition
  2. What is a View Composer?
  3. Class View Composers in Laravel 4
  4. Hooking it up with the database
  5. Conclusion

Two important mantras of writing good quality code are Don’t Repeat Yourself and Abstraction. Every component in a computer system should only have one representation. If you find that you are repeating yourself, it’s time to perform an abstraction.

Don’t Repeat Yourself is a well understood concept in computer programming and something that you are taught as a good practice early on. However it can be easy to slip into bad practices.

In this post I’m going to be looking at the concept of View Composers in Laravel 4.

The Problem of repetition

One common area where I see a lot of repetition that should be abstracted is the layer between the Controller and the View.

Generally speaking your layout will probably require a lot of the same data on every page. This presents the problem of repeating the same query in multiple Controllers and adding it to multiple Views throughout your project. This is a bad idea because if you decide to update or modify how that data is generated, you are going to have to make changes in multiple places.

A View Composer allows you to abstract this code into a single location and then make it available for many different Views. By abstracting this procedure away from the Controller, you prevent repetition and you create a nice little single responsibility that can be utilised in many of your View files.

So let’s take a look at creating View Composers.

What is a View Composer?

A View Composer is essentially just a piece of code that is executed and bound to a View whenever that View is requested.

The Laravel Documentation has a perfect example:

View::composer("profile", function ($view) {
    $view->with("count", User::count());
});

In this example, whenever the profile View is loaded, the $count variable will be available with the latest number of users in the system.

You can also make this data available on multiple pages by adding a comma separated listed of Views.

View::composer(["profile", "dashboard"], function ($view) {
    $view->with("count", User::count());
});

Now whenever the profile or dashboard pages are loaded, the $count variable will be available on the View.

Class View Composers in Laravel 4

I love that Laravel 4 allows you to create a little closure like the ones above to test a bit of functionality. In all honestly, a lot of my experimentation is creating a test route and then just dumping a chunk of code in to test it.

However you really need to enforce strict organisation for your code or your project will end up being a nightmare to work with.

Laravel does not enforce that you store your View Composer in any particular place. In order to keep Cribbb organised in a logical way, I will create a new directory under app/Cribbb called Composers.

Instead of using a Closure based View Composer, Laravel 4 also allows you to create a class based View Composer. Using a class for a View Composer ensures that you don’t have random Closures dotted around your project, but it also gives you the added goodness of the Laravel IoC container, which I’m sure will come in handy at some point.

I want to make a View Composer that will generate a dynamic list of the Cribbbs the current user is a member of. This will appear in the sidebar on every page.

So the first thing to do is to create the Composer:

<?php namespace Cribbb\Composers;

class CribbbListComposer
{
    public function compose($view)
    {
        $view->with("cribbbs", ["first", "second", "third"]);
    }
}

The Composer class has a single compose method. As you can see in the example above, currently I’m just adding an array of data to the $cribbbs variable. Once I have this working I can go back and replace it with real data from the database.

Next, the Laravel documentation recommends that you add your composer class to the view using the following syntax:

View::composer("profile", "CribbbListComposer");

However once again, I don’t really want these random bits of code floating around my project because tracking them down in the future will be a nightmare.

Fortunately Laravel provides us with a ready made solution to “bootstrap” our code using Service Providers.

In order to bind my Composer to the View, I created the following Service Provider:

<?php namespace Cribbb\Composers;

use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->view->composer(
            "partials.side",
            "Cribbb\Composers\CribbbListComposer"
        );
    }
}

Note: The first argument is the actual view file and the second argument is the full namespace to the Composer class. In my case I want this variable to be available in my sidebar which is stored in a partial. It probably makes more sense to just put whatever you want into a partial rather than having a long list of View files in this method.

Next go into <codeo>app/config/app.php and add the following line to your Service Providers array:

"Cribbb\Composers\ComposerServiceProvider";

And finally add the following to your View file (in my case partials.side) to output the array of items:

<ul>
@foreach ($cribbbs as $cribbb)
<li>{{ $cribbb }}</li>
@endforeach
</ul>

Now if you fire up your application and load the correct View, you should see an unordered list of the items from your array.

Hooking it up with the database

So now that I can see that the Composer is actually working, I can hook it up with the database to insert the correct data. If you have been following a long with this series hopefully you will already be able to guess what I need to do in order to make this work.

1. Add a method to the Repository Firstly I will add a method to my Repository that will pull a list of the Cribbbs that this current user is a member of.

/**
 * Cribbbs
 *
 * @param int $id
 * @return Illuminate\Database\Eloquent\Collection
 */
public function cribbbs($id)
{
    $user = $this->find($id);

    if ($user)
    {
        return $user->cribbbs();
    }
}

2. Add caching Next I will add the method to the Cache Decorator to ensure that the database is not hit for each request.

/**
 * Cribbbs
 *
 * @param int $id
 * @return Illuminate\Database\Eloquent\Collection
 */
public function cribbbs($id)
{
    $key = md5('cribbbs.'.$id);

    if ($this->cache->has($key)) {
        return $this->cache->get($key);
    }

    $cribbbs = $this->user->cribbbs($id);

    $this->cache->put($key, $cribbbs);

    return $cribbbs;
}

3. Inject into the Composer Next I will add a construct method to the Composer to inject the Repository as a dependency. I will then use the injected Repository to replace the static array with the return value of the method.

/**
 * Construct
 *
 * @param Cribbb\Respository\User\UserRepository $user
 */
public function __construct(UserRepository $user)
{
    $this->user = $user;
}

/**
 * Compose
 *
 * @param View
 */
public function compose($view)
{
    $user = Auth::user();
    $view->with('cribbbs', $this->user->cribbbs($user->id));
}

5. Resolve from the IoC container Finally I will inject the dependency into the Composer through the Service Provider.

/**
 * Register the binding
 *
 * @return void
 */
public function register()
{
    $this->app->bind('Cribbb\Composer\CribbbListComposer', function($app) {
        new CribbbListComposer($this->app->make('Cribbb\Repository\User\UserRepository'));
    });
}

/**
 * Bootstrap the application events.
 *
 * @return void
 */
public function boot()
{
    $this->app->view->composer('partials.side', $this->app->make('Cribbb\Composer\CribbbListComposer'));
}

Notice how I bind the CribbbListComposer class in the register method, but I add it to the view composer in the boot method. This is because of the way Laravel fires the Service Provider. If I were to bind the Composer to the View in the register method I would get an error to say the cache was not available.

Conclusion

View Composers are an excellent way of abstracting repeated presentation code into a single responsibility class. This means you don’t have to repeat the code in multiple places throughout your project.

Preventing repetition is something that is easy to neglect. Often it is so much easier to dump a chunk of code in multiple places to solve the problem. However, it is inevitable that this is going to come back and bite you. With a little bit of prior thought and organisation, you can build a logical, clean and well organised application that is not a nightmare to work on.

In large projects you are likely going to need a lot of little nuggets of code like this throughout your application. By using this View Composer pattern you are able to abstract that logic into one place whilst also ensuring your code is easy to work with and pick up by other developers (or your future self!).

This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.