Presenters
We will learn how to write presenters and templates in Nette. After reading you will know:
- how the presenters works
- what are components and persistent parameters
- how to render a template
Life Cycle of Presenter
We know by now that a presenter action causes invoking render<Action>
method, thus for example
renderShow
. But it's not the only method that gets invoked. When writing presenters, we can write the following
methods:

Life cycle of presenter
startup()
Method startup()
gets invoked immediately after the presenter is created. It initializes variables or checks user
privileges.
If you write your own startup()
method, don't forget to call its parent
parent::startup()
.
action<Action>()
Analogous to the method render<View>()
. There are situations when the presenter executes some specific
action (authenticates the user, writes to database) and then redirects to somewhere else. To call it render
would be
inappropriate, because nothing is rendered. Because of that, there is an alternative called action
.
It's important to know that the method action<Action>()
gets called before
render<View>()
. It can even decide to change what render method gets invoked, by calling
$this->setView('otherView')
(renderOtherView()
will get invoked).
handle<Signal>()
Method handles so called signals aka subrequests. Designed mainly for components and handling of AJAX requests.
beforeRender()
Method beforeRender
, as the name suggests, gets invoked before render<View>()
and it can
contain for example setup of template, passing variables to template common for more views and so on.
render<View>()
Usually passes required data to templates.
shutdown()
Gets invoked at the end of the presenters life cycle.
More accurate would be to say, that we were talking about life cycle of the class Nette\Application\UI\Presenter, from which presenters are inherited most often. In general, a presenter is any class implementing the simple interface Nette\Application\IPresenter.
Termination of presenter
We can terminate a presenter anytime during its life cycle. We usually do this to prevent rendering a template.
- termination of presenter directly by method:
$presenter->terminate()
- termination of presenter and immediate render the template:
$presenter->sendTemplate()
- termination of presenter and dispatch of the payload:
$presenter->sendPayload()
(for AJAX) - termination of presenter and dispatch of own response:
$presenter->sendResponse($response)
A presenter can be terminated also by redirecting or by throwing a BadRequestException
.
Templates
The presenter will deduce the path to the template file from a few simple rules. It will try, for presenter
Product
and action show
, if one of these files exists:
- templates/Product/show.latte
- templates/Product.show.latte
Presenter will also try to search for a layout (that is optional):
- templates/Product/@layout.latte
- templates/Product.@layout.latte
- templates/@layout.latte layout shared by multiple presenters
You can change the way of searching the templates by overriding the formatTemplateFiles or formatLayoutTemplateFiles methods.
Presenters and its components pass a few useful variables to the templates:
$basePath
is an absolute URL path to root dir (for example/CD-collection
)$baseUrl
is an absolute URL to root dir (for examplehttp://localhost/CD-collection
)$user
is a object representing the user$presenter
is the current presenter$control
is the current component or presenter$flashes
list of messages sent by methodflashMessage()
You can read more details about template rendering in a separate chapter.
Actually it's not hard at all! When you're requesting an action, for example Homepage:default
, then
- an object of class
HomepagePresenter
will be created - method
renderDefault()
will be called (if it exists, but it doesn't have to) - template, for example
templates/Homepage/default.latte
with layout, for exampletemplates/@layout.latte
, will be rendered
and in template we can create a link to mentioned Product:show($id)
, roughly
like this:
<a n:href="Product:show $productId">product detail</a>
It looks like creating applications in Nette Framework will be child's play.
Redirection
There are two methods redirect()
and forward()
for jumping to another presenter, which have similar
syntax as mentioned link(). For example, after submitting a form and writing to the database, we will
redirect to the product's detail by calling:
$this->redirect('Product:show', $id);
While forward()
will pass to new action without redirecting, method redirect()
will redirect the
browser with HTTP code 302 or 303. If we would want to use a different code, we will put it before the name of the action of a
presenter:
$this->redirect(301, 'Product:show', $id);
To go to URLs outside of your application, you can redirect using redirectUrl()
:
$this->redirectUrl('https://nette.org');
Redirection immediately terminates activity of the presenter by throwing the so called terminating exception
Nette\Application\AbortException
.
Sometimes, before redirection, we want to send a so called flash message. That's a message that will appear after redirection in template.
Error 404, etc.
When we can't fulfill the request, because for example the record is missing in the database, we will throw an exception
Nette\Application\BadRequestException
, which represents HTTP error 404:
public function renderShow($id)
{
$product = $this->model->getProduct($id);
if (!$product) {
throw new Nette\Application\BadRequestException;
}
// ...
}
When a user is not authorized to see the page, we will throw a Nette\Application\ForbiddenRequestException
exception (error 403). Other error codes can be returned using second argument of
Nette\Application\BadRequestException
.
Flash messages
These are messages informing about a result of some operation. An important feature of flash messages is that they are available in template, even after redirection. Even when displayed, they are available for three seconds – in case that a user would unintentionally refresh the page – thus messages will not be lost.
Just call the flashMessage() method and
presenter will take care about passing the message to template. First argument is the text of the message and second optional
argument is its type (error, warning, info etc.). The method flashMessage()
returns an instance of flash message, to
allow us to add more information.
public function deleteFormSubmitted($form)
{
// ... model asks for deletion of record ...
// we will pass the flash message
$this->flashMessage('Item was removed.');
$this->redirect(...); // and redirect
}
These messages are available in templates variable $flashes
as anonymous objects, that contains
message
and type
properties and they can even contain previously mentioned user-defined information.
They can be rendered for example like this:
{foreach $flashes as $flash}
<div class="flash {$flash->type}">{$flash->message}</div>
{/foreach}
Usage of model classes
As we've said before, model is a whole layer composed of many classes, where each one is taking care of one part of application
logic. If we'd have for example a model App\Articles
, which would take care of loading and saving articles, we may
ask for it in a presenter using Dependency Injection, assuming we've properly registered it as a service in DI Container.
class ArticlePresenter extends Presenter
{
/** @var \App\Articles @inject */
public $articles;
public function renderShow($id)
{
$this->template->article = $this->articles->find($id);
}
}
What just happened? Let's go through it together. As we've said before, instances of presenters are created using the PresenterFactory and what this class does after
creation, is that it checks if the presenter has some public properties, that are annotated with @inject
and if so,
it tries to find a service that implements or is instance of the type, that is in @var
and passes this service to the
property from DI Container.
Thanks to this mechanism, we can use the service right away, without caring where it came from or trying to instantiate it, because we're sure that it will be passed to the property, as long as it's correctly registered in the DI Container.
You can only inject into public properties of classes.
Persistent parameters
Except classic parameters, that we know by now, there are so called persistent parameters. Those are different in a very essential way: they are passed through requests automatically. That means, we don't have to explicitly mention them in links, but they are passed anyway.
When your application has multiple language variants passing the actual language in every link will be incredibly tiring. But
that's not needed with Nette Framework. You can simply mark the $lang
parameter as persistent just like this:
class ProductPresenter extends Presenter
{
/** @persistent */
public $lang;
...
If the actual value of parameter $lang
will be 'en'
, the into the link
<a n:href="Product:show $productId">product detail</a>
the parameter lang => en
will be passed automatically. Great!
But we can also add parameter lang
and by that, change its value:
<a n:href="Product:show $productId, lang => cs">detail in Czech language</a>
The parameter will be accessible in the class variable $lang
in objects of ProductPresenter
and it
can be accessed through $this->lang
. We can even set the default value of the persistent parameter to presenter
class. If the parameter value will correspond to the default value, it will not be passed in a URL.
A persistent variable must be declared as public.
Persistence reflects hierarchy of presenter classes, thus parameter defined in specific presenter will be automatically taken into account in every single presenter inheriting from it.
Presenter and components
When we talk about presenters, then under the term components we usually mean descendants of class Control. More accurate would be to use term “controls”, but it has a different meaning in czech and “components” did better catch on.
Presenter Nette\Application\UI\Presenter
by itself, is descendant of class Control
, so there is major
similarity between components and presenter. But UI\Control
(and thus even UI\Presenter
) is primarily a
so called component container. Which means that you can add to it other components. Just like we add to form inputs (text field, button, …). And just like with forms, you can access them through
brackets:
// attach component to presenter
$presenter['mymenu'] = new MenuControl;
// get component from presenter and render it
$presenter['mymenu']->render();
Attaching the component to the presenter (binding them) you will be able to:
- create links in component
- use signals
- use persistent parameters in components
When you don't need any of these features, you don't have to bind the component with the presenter.
Component factories
Component factories are an elegant way to create components only when they are really needed (lazy / on demand). The whole
magic is in implementation of a method called createComponent<Name>()
, where <Name>
is the
name of component, that will create and return the desired component. This component is then attached to the presenter. The method
createComponent<Name>()
is optionaly passed the $name
of the component, that is being created, as
an argument.
class DefaultPresenter extends Nette\Application\UI\Presenter
{
public function renderDefault()
{
$menu = $this['menu']; // access to component
// if this was the first access, method createComponentMenu() will be called
// ...
}
protected function createComponentMenu()
{
// create and configure component
$menu = new MenuControl;
$menu->items = $this->item;
// and return it
return $menu;
}
}
The first letter of a component name is always lower case, despite that the first letter in the factory name is upper case.
Because all components are created in separate methods, the code is cleaner and easier to read.
We never call factories directly, they get called automatically, when we use components for the first time. Thanks to that, a component is created at the right moment, and only if it's really needed. If we wouldn't use the component (for example on some AJAX request, where we return only part of the page, or when parts are cached), it wouldn't even be created and we save performance of the server.
You can access and render component using macro {control}. So there is no need of manually passing the components to template.
<h2>Edit form</h2>
{control editForm}
You can read more detailed information about components on a separate page.
Persistent components
Not only parameters, but also components can be persistent. Their state is then passed around when jumping to another
presenter, just like with persistent parameters. We mark persistent components with this
annotation (here we mark components calendar
and menu
):
/**
* @persistent(calendar, menu)
*/
class DefaultPresenter extends Presenter
{
// ...
}
You don't have to mark subcomponents as persistent, they are persistent automatically.
Where can i get some components?
On page Add-ons, plugins and components you can find some open-source components that were made and shared by community of Nette Framework. Nette Foundation is not liable for them.