MVC Applications & Presenters
We will learn, how to create applications in Nette Framework. After this chapter you will know:
- MVC, directory structure and
bootstrap.phpfile - what are presenters and actions
- how to use templates
- what are persistent parameters
Model-View-Controller (MVC)
Model-View-Controller is a software architecture that was created to satisfy the need to separate utility code (controller) from application logic code (model) and from code for displaying data (view) in applications with graphical user interface. With this approach we make the application better understandable, simplify future development and enable testing each unit of the application separately.
Model
Model is data and especially functional base of whole application. It contains application logic. Any user action (login, insertion of goods to basket, change of value in database) represents a model action. Model is managing its internal state and provides solid interface to outside. By calling methods of this interface, we can read or update its state. Model doesn't know anything about view or controller.
Concept of Model represents whole layer, not only a single class.
View
View is an application layer, that is taking care of displaying result of request. It usualy uses templating engine and knows, how should be each component rendered or result acquired from model.
Controller
Controller does handle requests from user, calls relevant application logic (model) and then asks view to display data. Analogically for controllers in Nette Framework there are presenters.
Directory structure
When you look at sandbox after downloading of Nette Framework
package, you will see recommended directory structure:
sandbox/
app/ ← directory with application
models/ ← model layer and it's classes
presenters/ ← presenter classes
HomepagePresenter.php ← Homepage presenter class
templates/ ← templates directory
@layout.latte ← template of shared layout
Homepage/ ← tempaltes for Homepage presenter
default.latte ← template for default action
config.neon ← application configuration file
bootstrap.php ← application boot file
libs/ ← directory with libraries (for example 3rd parties)
Nette/ ← your favourite framework
...
log/ ← contains logs, errors, etc.
temp/ ← for temporary files, cache, ...
www/ ← public directory, document root of project
.htaccess ← rules for mod_rewrite
index.php ← triggers the application
images/ ← another directories, images, styles, ..
Moreover in some directories, there are .htaccess and
web.config files, that denies access from browser (for Apache or
IIS). Make sure, that this is working, and you cannot reach app/
and libs/ directories from browser.
Don't forget to grant write privilege (chmod 0777)
to directories log/ and temp/.
index.php & bootstrap.php
Browser is sending all requests through one and only file, located in public
directory www/ and that is index.php. There are only
definitions in this file, describing directory structure of the application
(constants WWW_DIR and APP_DIR), and code that passes
the control to the application (that is the app/ directory), to a
boot file bootstrap.php.
Nette Framework saves all its paths consistently, without the right trailing slash.
Described directory structure is realy just recommended, because you can
easily change it however you want to. All you have to do, is rename directories
and change paths in index.php or bootstrap.php.
First, file bootstrap.php loads Nette Framework:
require LIBS_DIR . '/Nette/loader.php';
Activates debugger and logger in strict mode:
use Nette\Diagnostics\Debugger;
Debugger::$logDirectory = __DIR__ . '/../log';
Debugger::$strictMode = TRUE;
Debugger::enable();
Class Configurator creates so called DI context. Before that we activate autoloading,
that will automatically load all the PHP files:
$configurator = new Nette\Config\Configurator;
$configurator->setTempDirectory(__DIR__ . '/../temp');
$configurator->createRobotLoader()
->addDirectory(APP_DIR)
->addDirectory(LIBS_DIR)
->register();
And according to the configuration stored in config.neon it
generates a DI container. Everthing else depends on it.
$configurator->addConfig(__DIR__ . '/config/config.neon');
$container = $configurator->createContainer();
Sets rules for routing, to enable
translate the URL addresses into a
presenter action. This rule, among others, says, that default presenter
action will be Homepage:default.
$router = $container->router;
$router[] = new Route('index.php', 'Homepage:default', Route::ONE_WAY);
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
Sets application parameters, for example error presenter, that will be in production environment responsible for displaying appropriate messages, when an error occurs:
$application = $container->application;
$application->errorPresenter = 'Error';
If we wanted to execute any other tasks, like connecting to database,
it's appropriate to add this to the onStartup event of the
application: (note: it's generally better to let DI container take care of connecting to
database).
$application->onStartup[] = function() {
... we will connect to database ...
};
And we will run the application:
$application->run();
That's it.
Modules
When developing complex applications, we can separate directories with
presenters and templates to subdirectories. We call them modules. If our
application would contain, for example modules Front and
Admin, its structure could look like this:
sandbox/
app/ ← directory with application
models/ ← model layer and its classes
AdminModule/ ← Admin module
presenters/ ← its presenters
templates/ ← its templates
FrontModule/ ← Front module
presenters/ ← its presenters
templates/ ← its templates
config.neon ← application configuration file
bootstrap.php ← application boot file
...
Modules don't have to be arranged in flat structure, you can even create submodules.
Processing presenter action
Now listen up closely, please. Every request on our application will reach
through files index.php and bootstap.php into object
$application. But, that one doesn't understand to http requests,
because of that, it will ask the router, to
translate the request into something, that it can understand. Thus to tell him,
for what presenter is the request meant and what action should it
execute. For example, router answers, that user want's action show
of presenter Product (it's good habit to write it like
Product:show) and passes parameter id = 123. You can
read it like: user want's to show product with id 123.
This is finally understandable to $application and it will
proceed to fulfill the wishes. It will create an object of class
ProductPresenter, that represents presenter Product.
(To be completely accurate, application asks for creation of presenter the
presenterFactory service). And presenter will ask for execution of
action (show with parameter id).
Presenter is an object, that takes the request, translated by router and
devises the answer. Answer can be HTML page, image, XML document, file on hard
drive, JSON, redirection or anything that you need. Specifically
ProductPresenter asks model for data, that it will pass to template
for displaying. This is usually done in method renderShow, where
word Show corresponds to the name of action and request parameter
id will be passed to the method as argument:
class ProductPresenter extends Nette\Application\UI\Presenter
{
function renderShow($id)
{
// we will get data from model and pass it to template
$this->template->product = $this->model->getProduct($id);
}
}
Then the presenter will render the template.
Templates
Presenter will deduce the path to the template from simple logic. It will
try, for presenter Product and action show, if one of
these files exists:
- templates/Product/show.latte - templates/Product.show.latte
Besides the .latte extension, you can use the
.phtml extension too.
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 passes to the templates few useful variables:
$basePathis an absolute URL path to root dir (for example/CD-collection)$baseUrlis an absolute URL to root dir (for examplehttp://localhost/CD-collection)$useris a object representing the user$presenteris the current presenter$controlis the current component or presenter$flasheslist 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
HomepagePresenterwill be created - method
renderDefault()will be called (if it exists, but it doesn't have to) - template, for example
templates/Homepage/default.lattewith 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>
I think that making applications in Nette will be easy.
Modules
For more complex applications, which separates presenters into modules,
everything works very similarly. Lets say, that our application contains module
Front, and it contains presenter Product. Action
show can than be written as Front:Product:show and
class ProductPresenter will be placed into namespace
FrontModule:
namespace FrontModule;
class ProductPresenter extends Nette\Application\UI\Presenter
{
...
Link creation
Creation of links belongs to the strongest features of Nette Framework. Thanks to two-way routing you don't have to hardcode your URLs or nastily assemble them. You can just refer to actions of presenters, and pass them parameters and framework will generate URLs by itself. Creating links is as easy as calling a function. You will really like it!
When programming and coding templates, we don't have to care about URLs
design, we will refer directly to action of presenter, that's for example
already mentioned Product:show.
Links in templates
Most often we create links in templates. To make it as easy as possible,
framework does offer three macros. Smartest of them is
macro n:href
<a n:href="Product:show $productId">product detail</a>
Note, that instead of the HTML attribute href we've used n:macro n:href.
It's value isn't a URL, as you were used to at href attribute, but
directly an action of a presenter. The syntax is
[Presenter:]action [,] [arg1] [, arg2] [, ...]
After clicking on the link, method
ProductPresenter::renderShow() will get its word and as parameter
$id will get the value of $productId, We can pass even
more parameters, in the same way, as we call a method. Could it be even
easier?
It's better to follow convetion of first big letter for name of presenter and small for action. As separator is used colon.
Besides that, it's even possible to pass named parameters. Next link passes
parameter lang with value cs:
<a n:href="Product:show $productId, lang => cs">product detail</a>
Allthough method renderShow doesn't have $lang in
it's declaration, it can read the value of this parameter by calling
$lang = $this->getParam('lang').
If we have all parameters in array, we can expand them with
(expand) operator:
{var $args = [$productId, lang => cs]}
<a n:href="Product:show (expand) $args">product detail</a>
If the template, in which we are creating links, is part of
Product presenter, we can omit the name of the presenter and write
directly n:href="show $productId". Or the other way, if a link
leads to the an action named default, you can skip that and write
n:href="Product: $id" (don't forget the colon).
Links can even refer to other modules. Here we
distinguish, if it's refering “relatively” to submodule, or
“absolutely” to different module – then path begins with colon. Lets
assume, that actual presenter is part of module Front, then we
will write:
<a n:href="Shop:Product:show">link for Front:Shop:Product:show</a>
<a n:href=":Admin:Product:show">link for Admin:Product:show</a>
Special case is linking to itself, when we'll write this as the
target.
Generated link is in absolute path format. When you want to generate absolute
link including domain, for example http://example.com, we will
supply two slashes at the beginning n:href="//show $productId".
We can refer to specific part on page using so called fragments behind the
symbol of grid #:
<a n:href="show#comments">link to Product:show and fragment #comments</a>
Macro n:href is realy handy when we are creating a HTML tag
<a>. When we want to print link elsewhere, for example in
text of the template, we will use macro {link} with the same
internal syntax:
The address is: {link Product:show $productId}
Read more details about syntax of Latte templates.
Linking in presenter
Presenter and a
component have method link, which can be used to create links
just like in a template. First argument is presenters target action, followed by
passed arguments:
$url = $this->link(destination [,arg [,arg ...]]);
They can also be passed using an array. Examples:
$url = $this->link('Product:show', $productId);
$url = $this->link('Product:show', array($productId, 'lang' => 'en'));
Invalid links
It may happen that we create an invalid link – either because it refers to
non-existing presenter, or because it passes more parameters that the target
method receives in its definition, or when there can't be generated URL for
targeted action. What to do with invalid link is determined by static variable
Presenter::$invalidLinkMode. It can have one of these values
(constants):
Presenter::INVALID_LINK_SILENT– silent mode, there will be returned symbol#as URLPresenter::INVALID_LINK_WARNING– visual warningPresenter::INVALID_LINK_EXCEPTION– there will be thrown an exception InvalidLinkException
Default setup in production mode is INVALID_LINK_SILENT and in
development mode it's INVALID_LINK_WARNING. When setup to
INVALID_LINK_WARNING, presenter and components returns error
message as URL which stars with error:. To make such links visible,
we will add CSS rule to our stylesheet:
a[href^="error:"] {
background: red;
color: white;
}
Persistent parameters
Except classic parameters, that we know by now, there are so called persistent parameters. Those are different in a very essential feature: they are passed through requests automatically. That means, we doesn't have to explicitly mention them in links, but they are anyway passed.
When your application have multiple language variants, passing of 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>
will be automaticaly passed parameter lang => en. 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 class variable $lang in
object of ProductPresenter and it can be accessed through
$this->lang. We can even set the default value of persistent
parameter to presenter class. If the parameter value will correspond to default
value, it will not be passed in URL.
Persistent variable must be declared as public.
Persistence reflects hierarchy of presenter classes, thus parameter defined in specific presenter will be automaticaly taken into account in every single presenter that inheriting from it.
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 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 ancestors parent::startup().
action<Action>()
Analogy to method render<View>(). There are situations,
when presenter executes some specific action (authenticates the user, writes to
database) and then redirects to somewhere else. Name such a method
render would be inappropriate, because method doesn't render
anything. Because of that, there is alternative with name
action.
It's important to know, that method action<Action>()
get's called before render<View>() method. 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>()
Usualy 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 class Nette\Application\UI\Presenter, from which are presenters inherited most often. In general, presenter is any class implementing simple interface Nette\Application\IPresenter and one such alternative uses Micro-framework.
Termination of presenter
We can terminate presenter anytime during his life cycle. We usualy 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)
Presenter can be terminated also by redirecting or by throwing a BadRequestException.
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 database, we will redirect to the products detail by calling:
$this->redirect('Product:show', $id);
While forward() will pass to new action without redirecting,
method redirect() will redirect browser with HTTP code 302 or
303. If we would want to use different code, we will put it before the name of
the action of presenter:
$this->redirect(301, 'Product:show', $id);
To different URLs to outside of application, you can redirect using
redirectUrl():
$this->redirectUrl('http://nette.org');
Redirection immediately terminates activity of the presenter by throwing so
called terminating exception Nette\Application\AbortException.
Sometimes, before redirection, we want to send 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 database, we will throw an exception
Nette\Application\BadRequestException, which represents HTTP
error 404:
function renderShow($id)
{
$product = $this->model->getProduct($id);
if (!$product) {
throw new Nette\Application\BadRequestException;
}
...
}
When 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. Important feature of flash messages is, that they are available in template, even after redirection. Even when displayed, they are available next three seconds – in case that user would unintentionally refresh page – thus messages will not be lost.
Method flashMessage
takes care about passing to template. First argument is text of message and
second optional argument is it's type (error, warning, info etc.). 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}
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 different meaning in czech language 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 mainly UI\Control (and thus even
UI\Presenter) is so called component container. Which means, that
you can add to it another components. Just like we add to form inputs (text field, button, …). And just
like with forms, you can access them through brackets:
// attach component at 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 is an elegant way to create components only when they are
realy needed (lazy / on demand). Whole magic is in implementation of method with
name createComponent<Name>(), where <Name>
is the name of component, that will create and return desired component.
Component is then attached to presenter. To method
createComponent<Name>() is optionaly passed
$name of component, that is beeing created, as 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;
}
}
Component name always starts with lowercase letter, despite that they are with uppercased first letter in name of factory.
Because all components are created in separated methods, the code is cleaner and clearer.
We never call factories directly, it gets called automatically, when we use the component for the first time. Thanks to that, the 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 manualy 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 even 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 would be persistent automatically too.
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.

