Presenters
Presenters help you organize view layer (presentation) logic for the objects. Logic in the presenter
should only be for display purposes.
An important secondary purpose for presenters is to map the decorated object's API in a clean way for views. This is why the __get
method has logic in it which you'll read about further down.
Basic Usage
The \Robbo\Presenter\PresentableInterface
interface tells the Streams Platform that the class is presentable
and has a getPresenter
method. By default getPresenter
return an instance of \Anomaly\Streams\Platform\Support\Presenter
or the nearest presenter to the class.
public function newPresenter()
{
return new Presenter($this);
}
Presenter::getObject()
The getObject
returns the decorated object instance.
Returns: mixed
Example
$presenter->getObject();
Twig
{{ presenter.getObject() }}
Presenter::__get()
The __get
magic method will look for the following available methods in order from top to bottom and return the first matching scenario:
Check the presenter for a method where the method is the camel case of the {attribute_name}
.
$presenter->display_name; // Returns: $presenter->displayName();
{{ presenter.display_name }} // Returns: {{ presenter.displayName() }}
Check the presenter for a getter method where the method is the camel case of get_{attribute_name}
.
$presenter->display_name; // Returns: $presenter->getDisplayName();
{{ presenter.display_name }} // Returns: {{ presenter.getDisplayName() }}
Check the presenter for a getter method where the method is the camel case of is_{attribute_name}
.
$presenter->enabled; // Returns: $presenter->isEnabled();
{{ presenter.enabled }} // Returns: {{ presenter.isEnabled() }}
Check the decorated object for a getter method where the method is the camel case of get_{attribute_name}
.
$presenter->display_name; // Returns: $presenter->getObject()->getDisplayName();
{{ presenter.display_name }} // Returns: {{ presenter.getObject().getDisplayName() }}
Check the decorated object for a boolean getter method where the method is the camel case of is_{attribute_name}
.
$presenter->enabled; // Returns: $presenter->getObject()->isEnabled();
{{ presenter.enabled }} // Returns: {{ presenter.getObject().isEnabled() }}
Check the decorated object for a method where the method is the camel case of the {attribute_name}
.
$presenter->display_name; // Returns: $presenter->getObject()->displayName();
{{ presenter.display_name }} // Returns: {{ presenter.getObject().displayName() }}
Check the decorated object for a getter style hook where the hook is get_{attribute_name}
.
$presenter->display_name; // Returns: $presenter->getObject()->call('get_display_name');
{{ presenter.display_name }} // Returns: {{ presenter.getObject().call('get_display_name') }}
Check the decorated object for a standard hook where the hook is {attribute_name}
.
$presenter->display_name; // Returns: $presenter->getObject()->call('display_name');
{{ presenter.display_name }} // Returns: {{ presenter.getObject().call('display_name') }}
Return the decorated object's attribute named {attribute_name}
.
$presenter->display_name; // Returns: $presenter->getObject()->display_name;
{{ presenter.display_name }} // Returns: {{ presenter.getObject().display_name }}
Returns: mixed
Arguments
Key | Required | Type | Default | Description |
---|---|---|---|---|
$name |
true |
string |
none |
The attribute name being attempted. |
Example
$presenter->example; // Where example is not a property of $presenter
Twig
{{ presenter.example }}
Presenter::__call()
The __call
magic method will try running the method
on the decorated object. Remember the __call
function is only invoked when the method does not exist on the presenter itself. So this effectively maps decorated object methods to the presenter.
Returns: mixed
Arguments
Key | Required | Type | Default | Description |
---|---|---|---|---|
$method |
true |
string |
none |
The method name. |
$arguments |
true |
array |
null |
An array of method arguments passed. |
Example
$presenter->exampleMethod(); // Returns: $presenter->getObject()->exampleMethod();
Twig
{{ presenter.exampleMethod() }}
Manually Decorating Objects
You can manually decorate
an object with the \Anomaly\Streams\Platform\Support\Decorator
class.
Decorator::decorate()
The decorate
method decorates the object. It can also decorate an entire collection of presentable items.
Returns: \Anomaly\Streams\Platform\Support\Presenter
or \Illuminate\Database\Eloquent\Collection
Arguments
Key | Required | Type | Default | Description |
---|---|---|---|---|
$value |
true |
mixed |
none |
The presentable object or collection of presentable items. |
Example
$decorated = $decorator->decorate($model);
Undecorating Values
The \Anomaly\Streams\Platform\Support\Decorator
class can also be used for obtaining the original undecorated values.
Decorator::undecorate()
The undecorate
reverses the decoration method's action. This is helpful for wrapping API methods for objects inside the view layer.
Returns: mixed
Arguments
Key | Required | Type | Default | Description |
---|---|---|---|---|
$value |
true |
mixed |
none |
The presenter or collection of presenters. |
Example
$original = $decorator->undecorate($model);
Writing Presenters
Presenters are automatically generated for you when using the make stream command:
php artisan make:stream stream_slug example.module.test
You can also create your own addon presenter in most cases by transforming the model class name into it's corresponding presenter class name:
TestModel -> TestPresenter
In all other cases all you need to do is define your own newPresenter
method on the presentable
class:
<?php namespace Anomaly\ExampleModule\Test;
use Robbo\Presenter\PresentableInterface;
use Anomaly\Streams\Platform\Support\Presenter;
class TestObject implements PresenterInterface
{
/**
* Return the presenter.
*
* @return string
*/
public function newPresenter()
{
return new Presenter($this);
}
}
An example presenter looks like this:
<?php namespace Anomaly\ExampleModule\Test;
use Anomaly\Streams\Platform\Support\Presenter;
class TestPresenter extends Presenter
{
/**
* Return the full name.
*
* @return string
*/
public function name()
{
return implode(' ', array_filter([$this->object->getFirstName(), $this->object->getLastName()]));
}
}
Now you can use this method in your API:
$test->name();
Or view layer:
{{ test.name() }}