The Power of Presenters

In recent years with Rails, Presenters have really surfaced as a clean and useful pattern to commit to inside of an application. This article takes a look at what they are, how they can help you and a simple implementation.

MVC

What are they and why should I care?

Presenters are simple classes which sit between controllers and views and deal with processing data and making it ready for the view.
This is good for 4 main reasons.

1) Skinny Controllers:

In order to stick to SRP (single responsibility principle) it is very important that we keep as much logic as possible outside of the controllers.
They should only contain:

- Model selection. Logic for finding the right model object given the parameters passed in from the request.

- Processing with reqest parameters.

- Selecting correct Models. Based on params from request determine correct model.

- Redirects and rendering views.

- Cookie and Session handling, possible including auth.

2) Logicless views:

The more logic found in a view the harder it is to test but also read. They can become a minefield of complexity with large blocks of logic followed by markup.
Seperation of logic and markup works in tandem with seperation of concerns.

3) Models dealing with business logic:

There is a tendency to have too much logic inside of models when they are intended to be used just for collecting data and parsing it in forms the application can use. NOT specific to views.
There should be certain methods which can be used from different controllers but with the data manipulated in different ways via Presenters for the view.
Models should not be overly complex.

4) Testing:

With seperate clases holding view logic they can be tested in isolation. This will produce higher code coverage as focus is put on the logic itself.

An EXAMPLE:

To get started, if you are using PHP you can use the Presenter Library found at https://github.com/robclancy/presenter. Or if using Ruby can use the SimpleDelegator found at http://www.ruby-doc.org/stdlib-2.0.0/libdoc/delegate/rdoc/SimpleDelegator.html.
But Presenters are a generic design pattern and so they are very easy to implement without third party help.
They can be tied to a page or a component. In the below example we tie it to a slide-show component found on the homepage.

# presenters/SlideShow.php

<?php
namespace OurApp/Presenters;

class SlideShow extends Base {

    public function getItems() {
        $newArray = array();
        foreach ($this->_view->items as $items) {
            if (SOME LOGIC) {
                $newArray[] = $items->getElement()
            } 
        }

        return $newArray;
    }
}

# presenters/Base.php

<?php
namespace OurApp/Presenters;

class Base extends {
    protected $_view;

    public function __construct($this) {
        $this->_view = $this;
    }
}

# views/homepage/index.php

<? $presenter = new OurApp/Presenters/SlideShow($this); ?>

<h1></h1>

<? foreach($presenter->getItems() as $item) : ?>

    <p><?= $item->getText(); ?></p>

<? endforeach; ?>

# controllers/HomepageController.php

$this->view->slideItems = $...;

# presenters/Tests/SlideShowTest.php

<?php
namespace OurApp/Presenters/Tests;

class SlideShowTest extends PHPUnit_Framework_TestCase {

    private $_presenter;

    public function setup() {
        $viewObject = (object) array(<DATA HERE>);
        $this->_presenter = new OurApp/Presenters/SlideShow($viewObject);  
    }

    public function getItemsTest() {
        $items = $_presenter->getItems();
        $this->assertEquals(
            10, 
            count($items)
        );
        $this->assertEquals(
            'First Item Text', 
            $items[0]->getText()
        );  
    }
}

TO WRAP UP:

There are many different ways to do this, above is one of many.
Presenters are incredibly powerful when used correctly. They can really improve things all over inside an app.
If you are looking for ways to improve your Presenters why not invest in a Dependency Injection Container to deal with Presenter dependencies. Something like Pimple can help with that.

Leave a Reply