You are browsing the unmaintained documentation for old Nette 2.2. See documentation for current Nette.

How do applications work?

We will learn how to create applications in Nette Framework. After this chapter you will know:

  • MVC, directory structure and bootstrap.php file
  • 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 separate utility code (controller) from application logic code (model) and from code for displaying data (view) in applications with a graphical user interface. With this approach the application is easier to understand, it will simplify future development and enables us to test each unit of the application separately.

Model

Model is data and it is the functional base of the whole application. It contains application logic. Any user action (login, insertion of goods to basket, a change of value in the database) represents a model action. The Model is managing its internal state and provides a stable interface to the outside. By calling methods on this interface, we can read or update its state. The 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. It usually uses the templating engine and knows how each component should be rendered by getting data from the model.

Controller

A controller handles requests from the user, calls relevant application logic (Model) and then asks the View to display data. In Nette Framework, controllers are represented by presenters.

Directory structure

When you look at sandbox after downloading the Nette Framework package you will see the following recommended directory structure:

<b>sandbox/</b>
├── <b>app/</b>                  ← directory with application
│   ├── <b>config/</b>           ← configuration files
│   │   └── <b>config.neon</b>   ← main config file
│   │   └── <b>config.local.neon</b>
│   │
│   ├── <b>model/</b>            ← model layer and its classes
│   ├── <b>presenters/</b>       ← presenter classes
│   │   └── <b>HomepagePresenter.php</b>  ← Homepage presenter class
│   │
│   ├── <b>templates/</b>        ← templates directory
│   │   ├── <b>@layout.latte</b> ← template of shared layout
│   │   └── <b>Homepage/</b>     ← templates for Homepage presenter
│   │       └── <b>default.latte</b>  ← template for default action
│   │
│   └── <b>bootstrap.php</b>     ← application boot file
│
├── <b>log/</b>                  ← contains logs, errors, etc.
├── <b>temp/</b>                 ← for temporary files, cache, ...
│
├── <b>vendor/</b>               ← directory with libraries (for example 3rd party)
│   ├── <b>nette/</b>            ← all Nette Framework libraries
│   │   └── <b>nette/Nette</b>   ← Nette Framework itself installed by Composer
│   ├── ...
│   │
│   └── <b>autoload.php</b>      ← script that handles autoloading of all classes from installed packages
│
└── <b>www/</b>                  ← public directory, document root of project
    ├── <b>.htaccess</b>         ← rules for mod_rewrite
    ├── <b>index.php</b>         ← triggers the application
    └── <b>images/</b>           ← other directories, images, styles, ..

Moreover in some directories, there are .htaccess and web.config files, which deny access from browser (for Apache or IIS). Make sure that these are working, and that you cannot reach app/ and libs/ directories from your browser.

Don't forget to grant write privilege (chmod 0777) to directories log/ and temp/.

index.php & bootstrap.php

The browser is sending all requests through one and only one file, located in public directory www/ and that is index.php. It only 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.

The described directory structure is only a recommendation. You can easily change it to whatever you want. All you have to do is rename directories and change paths in bootstrap.php.

Firstly, the file bootstrap.php loads Nette Framework and all libraries that we depend on:

require __DIR__ . '/../vendor/autoload.php';

The class Configurator creates so called DI context and handles application initialization.

$configurator = new Nette\Configurator;

Activates debugger and logger in strict mode:

//$configurator->setDebugMode(TRUE);
$configurator->enableDebugger(__DIR__ . '/../log');

Setup directory for temporary files

$configurator->setTempDirectory(__DIR__ . '/../temp');

Activate autoloading, that will automatically load all the files with our classes:

$configurator->createRobotLoader()
	->addDirectory(__DIR__)
	->addDirectory(__DIR__ . '/../vendor/others')
	->register();

And according to the configuration files it generates a DI container. Everything else depends on it.

We will return this DI Container as a result of calling app/boostrap.php

$configurator->addConfig(__DIR__ . '/config/config.neon');
$configurator->addConfig(__DIR__ . '/config/config.local.neon');
return $configurator->createContainer();

and we will store it as a local variable in www/index.php and run the application:

$container = require __DIR__ . '/../app/bootstrap.php';
$container->getService('application')->run();

That's it.

Processing presenter action

So how are requests handled? Every request to our application will pass via index.php and bootstrap.php to the $application object. But this object does not understand http requests, so it will ask the router to translate the request. The router will look at the request, and tells what presenter is needed, and what action it should execute. For example, the router answers, that the user wants action show of presenter Product (it's a good habit to write it like Product:show) and pass it parameter id = 123. You can read it like: user wants to show product with id 123.

This is finally understandable to the $application and it will proceed to fulfill the request. It will create an object of class ProductPresenter, that represents presenter Product. (To be completely accurate, the application asks the presenterFactory service for creation of a presenter). This new presenter will be asked for execution of action (show with parameter id).

The presenter is an object that takes the request, translated by router, and computes the answer. This can be an HTML page, an image, an XML document, a file, JSON, redirection or anything that you need. In detail, the ProductPresenter will query the model for data, and pass that data to the template for displaying. This is usually done in method renderShow, where the word Show must match the name of the action and request parameter id will be passed to the method as argument:

class ProductPresenter extends Nette\Application\UI\Presenter
{
	public function renderShow($id)
	{
		// we will get data from model and pass it to template
		$this->template->product = $this->model->getProduct($id);
	}
}

If you really want, you can get an array of all the GET request parameters by calling $this->request->getParameters(), but usually you shouldn't need them, bu instead use routing and action parameters.

Similarly you can get all received POST parameters by calling $this->request->getPost(). And normally, neither should you need this method. Mostly you're processing form requests and there is a form component for that.

Then the presenter will render the template.

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:

<b>sandbox/</b>
	<b>app/</b>                ← directory with application
		<b>AdminModule/</b>    ← Admin module
			<b>presenters/</b> ← its presenters
			<b>templates/</b>  ← its templates

		<b>FrontModule/</b>    ← Front module
			<b>presenters/</b> ← its presenters
			<b>templates/</b>  ← its templates

		...

Modules don't have to be arranged in flat structures, you can even create submodules.

If module Front would contain 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
{
	// ...
}
Improve this page