Home » Code » Model Presenters in Laravel 4

Model Presenters in Laravel 4

Posted by on March 3rd, 2014

Model Presenters in Laravel 4
When working with data in a web application, it is often desirable to display data differently from how it is stored in your database. Two common scenarios I encounter in just about every project I work on is displaying dates and money values. Generally speaking you will want to store dates as a timestamp, and money as integers, but that is not how you want to display them on the user interface.

However knowing where to deal with this issue isn’t really that obvious, particularly when you are just starting out as a developer.

At first you probably deal with it in the View, but that means you will repeat the same logic whenever you need to display the same field on a different page. Abstracting the logic to the model is one option, but your model shouldn’t care how the data is presented in the View.

Instead of adding extra responsibility to your Models, Views or Controllers, you should slip in an extra layer to deal with presenting the data of your application. This keeps all of your presentation logic in one place and it ensures you keep to the single responsibility principle.

In this tutorial I’m going to look at dealing with Model Presenters in Laravel 4.

What is a Model Presenter?

Before I jump into the code, first a little explanation as to what the hell I’m talking about.

A Model Presenter is basically a class that accepts an object from the database and then wraps it in some specific logic to alter the returned values without having to modify the original object.

If you’ve been following along with this series, you might remember that this process sounds oddly familiar to how we implemented caching as a service.

This process is known as the The Decorator Pattern. It is where you are able to modify an instance of an object without affecting any other instances of the same object.

This would be in contrast to extending an abstract class that held the presentation logic. If you extended an abstract class, then all instances of the object would be affected where we don’t necessarily want that side effect.

Creating the Presenter structure

So the first thing to do is to establish a little bit of structure. If you’ve been following along with this series you will know that this means creating a new namespace to hold these specific classes.

In this tutorial I’m going to create a new directory under my Cribbb namespace called Presenters.

Next I will create an AbstractPresenter to hold all of basic logic of all of the specific presenter instances:

<?php namespace Cribbb\Presenters;

abstract class AbstractPresenter {}

Using ArrayAccess

The first thing I’m going to do is implement the ArrayAccess interface:

<?php namespace Cribbb\Presenters;

use ArrayAccess;

abstract class AbstractPresenter implements ArrayAccess {}

This allows you to use an object as if it was an array for setting, unsetting and getting data from it. This basically means you can get and set values on this object in the same way that you do with an array. This is often useful when using the object in the View.

It’s important to note that implementing the ArrayAccess interface does not magically turn an object into an array. The interface simply forces you to implement the methods. The benefit is you can inspect the object and determine if you can access it like an array or not.

The ArrayAccess interface specifies that we need to implement the following four methods:

offsetExists

The offsetExists method allows to check to see if a property is set on the project using the isset function.

/**
 * Check to see if the offset exists
 * on the current object
 *
 * @param string $key
 * @return boolean
 */
public function offsetExists($key)
{
  return isset($this->object[$key]);
}

// Example
isset($object['name']); // true / false

offsetGet

The offsetGet method allows you to retrieve a key from the object using the square bracket syntax:

/**
 * Retrieve the key from the object
 * as if it were an array
 *
 * @param string $key
 * @return boolean
 */
public function offsetGet($key)
{
  return $this->object[$key];
}

// Example
echo $object['name']; // Philip Brown

offsetSet

The offsetSet method allows you to set a property on an object using the square bracket syntax:

/**
 * Set a property on the object
 * as if it were any array
 *
 * @param string $key
 * @param mixed $value
 */
public function offsetSet($key, $value)
{
  $this->object[$key] = $value;
}

// Example
$object['name'] = 'Philip Brown';

offsetUnset

And finally offsetUnset allows you to unset a property on the object using the unset method that you would normally use for arrays:

/**
 * Unset a key on the object
 * as if it were an array
 *
 * @param string $key
 */
public function offsetUnset($key)
{
  unset($this->object[$key]);
}

// Example
unset($object['name']);

Injecting the object

Now that we’ve set up the boilerplate ArrayAccess we can get down to actually creating the Presenter functionality using a couple of PHP’s Magic methods.

So the first thing to do so it to inject the object we want to work with. Normally you would do this through the constructor, but in this case I’m going to create a set method instead. The reasoning behind this decision will become clear later in this tutorial.

/**
 * The object to present
 *
 * @var mixed
 */
protected $object;

/**
 * Inject the object to be presented
 *
 * @param mixed
 */
public function set($object)
{
  $this->object = $object;
}

This is essentially exactly the same as doing it through the constructor however it gives us the flexibility to not supply the dependency when the object is instantiated.

Get or pass through

The next method is where the magic really happens. On each Presenter class I’ll be making a method that corresponds with a particular property on the object.

So for example, if I wanted to transform the created_at property, I would make a created_at method on my Presenter.

When I call $object->created_at, first I want to check to see if there is a presenter method available. If the method is available I will use that method. If it is not available I can simply pass the call to the original object.

To listen for property accessor calls we can use the __get() magic method:

/**
 * Check to see if there is a presenter
 * method. If not pass to the object
 *
 * @param string $key
 */
public function __get($key)
{
  if (method_exists($this, $key))
  {
    return $this->{$key}();
  }

  return $this->object->$key;
}

This magic method listens for calls such as $object->created_at. The property that you are trying to access will be passed to the method as the $key argument.

Next we can use the method_exists function to determine if the $key exists on the current object ($this).

If the method does exist we can return the value from that method. If it doesn’t exist, we can pass the call to the original object.

Creating an interface

I’m also going to implement the individual Presenter classes with an interface:

<?php namespace Cribbb\Presenters;

interface Presentable {}

Whilst this empty interface seems a bit pointless, it will ensure that when working with Presenter classes at runtime you can determine if the object is “presentable”.

At some point in the future I will likely need to have methods available on these classes. Setting up this kind of structure will ensure future development remains consistent.

Creating your model presenters

Now that we have the basic boiler plate set up, we can extend the AbstractPresenter to create specific rules for each model in the application.

For example, here is how I would modify the created_at date on the User object:

<?php namespace Cribbb\Presenters;

class UserPresenter extends AbstractPresenter implements Presentable {

  /**
   * Present the created_at property
   * using a different format
   *
   * @return string
   */
  public function created_at()
  {
    return $this->object->created_at->format('Y-m-d');
  }

}

If you wanted to always use a specific format for displaying dates in your application it would probably make sense to abstract this method to the AbstractPresenter so all of your individual presenters will pick up this functionality.

Creating the Presenter service

Now that I’ve set up the AbstractPresenter and the UserPresenter classes I can start using them in my Controllers.

To do this I will create a service wrapper class that will do the heavy lifting for me.

<?php namespace Cribbb\Presenters;

class Presenter {}

The first method to create on the Presenter service is for presenting a single Model instance:

/**
 * Return an instance of a Model wrapped
 * in a presenter object
 *
 * @param Model $model
 * @param Presentable $presenter
 * @return Model
 */
public function model(Model $model, Presentable $presenter)
{
  $object = clone $presenter;

  $object->set($model);

  return $object;
}

In this method I will pass the instance of the $model and an instance of the $presenter.

Next I will clone the $presenter and then set the $object and return it.

You might be thinking, “why have you cloned the $presenter rather than just setting the $model on it directly?” This is because I want to use the same method to present multiple model instances in a Collection or a Paginator.

The clone keyword is an interesting aspect of PHP that doesn’t get used that often. When you make a copy of an object in PHP, the copied object maintains a reference to the original object. When you use the clone keyword, the clone is a shallow copy of the original object.

Run the following code to see the difference for yourself:

$dolly = new stdClass;

$polly = $dolly;
$molly = clone $dolly;

$dolly->name = "dolly";

echo 'Polly is called ' . $polly->name;
echo 'Molly is called ' . $molly->name;

In the code above, $polly maintains a reference to $dolly whereas $molly does not.

Next I can create a method for presenting Collections:

/**
 * Return an instance of a Collection with each value
 * wrapped in a presenter object
 *
 * @param Collection $collection
 * @param Presentable $presenter
 * @return Collection
 */
public function collection(Collection $collection, Presentable $presenter)
{
  foreach($collection as $key => $value)
  {
    $collection->put($key, $this->model($value, $presenter));
  }

  return $collection;
}

In this method I’m simply iterating over the collection and resetting the key with the wrapped $value.

And finally I can create a method for presenting pagination:

/**
 * Return an instance of a Paginator with each value
 * wrapped in a presenter object
 *
 * @param Paginator $paginator
 * @param Presentable $presenter
 * @return Paginator
 */
public function paginator(Paginator $paginator, Presentable $presenter)
{
  $items = array();

  foreach($paginator->getItems() as $item)
  {
    $items[] = $this->model($item, $presenter);
  }

  $paginator->setItems($items);

  return $paginator;
}

Again in this method I’m iterating over the paginator and resetting the values.

Using the Presenter Service in your Controller

Now that we’ve set up the UserPresenter and the Presenter service we can use start to use them in the Controller to pass the presented data to the View.

The first thing to do is to inject the Presenter into the Controller through the constructor:

<?php

use Cribbb\Presenters\Presenter;
use Cribbb\Presenters\UserPresenter;
use Cribbb\Repositories\User\UserRepository as User;

class UserController extends BaseController {

  /**
   * @var Cribbb\Repositories\User\UserRepository
   */
  protected $user;

  /**
   * @var Cribbb\Presenters\Presenter
   */
  protected $presenter;

  /**
   * Construct
   */
  public function __construct(User $user, Presenter $presenter)
  {
    $this->user = $user;
    $this->presenter = $presenter;
  }

Next, in your methods you simply pass the returned object from the Repository into the Presenter service:

/**
 * Show
 *
 * @param int $id
 * @return View
 */
public function show($id)
{
  $user = $this->user->find($id);

  if($user)
  {
    $user = $this->presenter->model($user, new UserPresenter);

    return View::make('users.show', compact('user'));
  }

  App::abort(404);
}

If you wanted to use a Collection or a Paginator, all you have to do is to use the correct method on the Presenter:

Using a Collection:

/**
 * Index
 *
 * @return View
 */
public function index()
{
  $users = $this->users->all();

  $users = $this->presenter->collection($users, new UserPresenter);

  return View::make('users.index', compact('users'));
}

Using a Paginator:

/**
 * Index
 *
 * @return View
 */
public function index()
{
  $page = Input::get('page', 1);

  $data = $this->user->getByPage($page, 50);

  $users = Paginator::make($data->items, $data->totalItems, 50);

  $users = $this->presenter->paginator($users, new UserPresenter);

  return View::make('users.index', compact('users'));
}

Now when you fire up your View, the properties that you want to present differently will automatically be converted for you.

Conclusion

The Presenter pattern is really a perfect solution to the problem of too much presentation logic in your View files. It can be tempting to copy the same chunk of code or stuff it in the model, but this will quickly become unmaintainable.

The Presenter pattern allows you to maintain appropriate separation of concerns whilst also allowing you to create self contained classes that have the single responsibility to present the data of your application in a specific way. This makes having different forms of presentation possible for the different ways of using the data in your application whilst also making it obvious and self documented when you or someone else needs to alter that presentation logic.

If you want to use Presenters, but you don’t want to set them up yourself you should take a look at the following Laravel PHP packages from Shawn McCool and Robert Clancy.

These two packages also allow you to do some fancy things like automatically calling your Presenters when the View file is loaded. Personally I’m not a huge fan of this approach because I don’t want to have to set a Presenter in the model and I’d rather manually create the Presenter in the Controller, but I do think this would be a very good solution in smaller projects.

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.

To view a full listing of the tutorials in this series, click here.

Philip Brown

Hey, I'm Philip Brown, a designer and developer from Durham, England. I create websites and web based applications from the ground up. In 2011 I founded a company called Yellow Flag. If you want to find out more about me, you can follow me on Twitter or Google Plus.

  • I just added Presenters to my stack. Very nice way to separate the presentation logic of a Model from the View. Thanks for another great tutorial!

    • Thank you Nathaniel, glad you found it useful! :)

  • elit

    Why dont you inject the controller presenter attribute to the model or collection methods ? Or why did you need the injection of presenter in the controller ?

    • I’m sorry, I don’t think I understand what you mean?

  • Samuel De Backer

    Many thanks for this post, It gives me the solution I was looking for.

  • I’ve been reading this series in the latest weeks. Thx and keep with the great work.

    Laravel community is awesome, but I think it is still hard to find some quality readings like these.

  • Muhamed Didovic

    Can we use Model Presenters as mutators (setters), basicly when we insert/update the db?

    • Yes, but that’s a different thing. There is a section on the Laravel docs for doing that

      • Muhamed Didovic

        You mean mutators or can you give me a link or hint?
        I like mutators, but I have special case where I use same model for different “packages”, so is it possbile to have different setters and getters for same model, and what is best approach,
        Thx

  • martinczerwi

    Great article, helped me a lot.

    I’m working on an API, with clients, that a user can add to his favorites. I solved this using a relation, but I don’t want the user to query the relation, so the presenter comes in quite handy. I check for relations to the current user, and simply add a flag like “faved” if present.

    One thing though, in this line “When you use the clone keyword, the clone is a shallow copy of the original object.”, should probably say “deep copy”, right?

    • Thank you :)

      No I do mean shallow copy. Take a look at this http://www.php.net/manual/en/language.oop5.cloning.php

      “When an object is cloned, PHP 5 will perform a shallow copy of all of the object’s properties. Any properties that are references to other variables, will remain references.”

      • martinczerwi

        Ok, I see. I always understood shallow copies as beeing references to objects, not real clones, but this one goes a bit deeper. Thanks ;)

  • micz123

    What about eager loading relation?
    Can we do $post->author->created_at?
    Or we have to make it like $post->authorCreatedAt?

  • coderabbi

    Unless I’m mistaken offsetGet() should reference __get() lest the undecorated value be returned when accessing it as $object[‘attribute’] rather than $object->attribute;

    public function offsetGet($key)
    {
    return $this->__get($key);
    }

  • Can you think of any reason why this would fail when using Twig as the view parser?

  • Great tutorial as usual thanks!

  • I have to say that I really prefer this approach to the other libraries. Just seems more pragmatic.

    • Yeah, I sometimes I prefer writing my own code rather than pulling in an additional package.

      • hehe, I say this and I’ve just started committing in a big way to Shawn McCool’s auto presenter library – big changes coming to support APIs :)

  • Hello, when we should using Presenter over getAttribute in eloquent?

    Thanks

    • It’s up to you really. If you just need to concatenate a first name and last name together, I would use getAttribute(). If you need to do more I would use a Presenter.

  • Supersam

    I’m trying to get my head around when to use Composer and when to user Presenter. There seems to be a lot overlap or am I missing something?

    • A Presenter is for formatting something like a price, whereas a Composer allows you to abstract a certain part of your View to prevent repetition.

      • Supersam

        You need to add the dummies intro paragraph with this exact type explanation. Call for the Nolan types :) You laugh, but I finally got it. Thanks

  • theGrammarPolice

    I’m having trouble with this particular post, namely when I try to implement my presenters in the relevant controller I get this error: “Argument 1 passed to PresentersPresenter::model() must be an instance of PresentersModel, instance of Post given”

    An example of the code I’ve written can be seen here: https://gist.github.com/denjin/b7fd765e2e98154a627b

    Can you help me work out what’s happening?

    • theGrammarPolice

      If anyone finds the same problem in the future, I fixed the problem by soft typing $model in the model() method of the Presenter service:

      public function model(Model $model, Presentable $presenter) {

      becomes

      public function model($model, Presentable $presenter) {

      this lets the method accept any model instance.

      • You need to add the Model namespace to use the typehint.

  • theGrammarPolice

    Hi, I’m having trouble with this particular post and trying to implement my own presenters. I get the following error when I try to wrap a model in a presenter:

    Argument 1 passed to PresentersPresenter::model() must be an instance of PresentersModel, instance of Post given

    You can see my code here: https://gist.github.com/denjin/b7fd765e2e98154a627b

    Can you help me work out what’s going wrong?