How Do Applications Work?
You are currently reading the basic document of the Nette documentation. You will learn all the principle of web applications. Nice from A to Z, from the moment of birth until the last breath of the PHP script. After reading you will know:
- how it all works
- what is Bootstrap, Presenter and DI container
- what the directory structure looks like
Open a skeleton example of a web application called WebProject and you can watch the files being written about.
The directory structure looks something like this:
web-project/ ├── app/ ← directory with application │ ├── Presenters/ ← presenter classes │ │ ├── HomePresenter.php ← Home presenter class │ │ └── templates/ ← templates directory │ │ ├── @layout.latte ← template of shared layout │ │ └── Home/ ← templates for Home presenter │ │ └── default.latte ← template for action `default` │ ├── Router/ ← configuration of URL addresses │ └── Bootstrap.php ← booting class Bootstrap ├── bin/ ← scripts for the command line ├── config/ ← configuration files │ ├── common.neon │ └── services.neon ├── log/ ← error logs ├── temp/ ← temporary files, cache, … ├── vendor/ ← libraries installed by Composer │ ├── ... │ └── autoload.php ← autoloading of libs installed by Composer ├── www/ ← public directory, document root of project │ ├── .htaccess ← mod_rewrite rules etc │ └── index.php ← initial file that launches the application └── .htaccess ← prohibits access to all directories except www
You can change the directory structure in any way, rename or move folders, and then just edit the paths to
temp/ in the
Bootstrap.php file and the path to this file in
composer.json in the
autoload section. Nothing more, no complicated reconfiguration, no constant changes. Nette has a smart autodetection.
For slightly larger applications, we can divide folders with presenters and templates into subdirectories (on disk) and into namespaces (in code), which we call modules.
www/ directory is the public directory or document-root of the project. You can rename it without having to
set anything else on the application side. You just need to configure the hosting so
that the document-root goes to this directory.
You can also download the WebProject directly, including Nette, using Composer:
composer create-project nette/web-project
On Linux or macOS, set the write
permissions for directories
The WebProject application is ready to run, there is no need to configure anything else at all and you can view it directly in
the browser by accessing the folder
It all begins when a user opens the page in a browser and browser knocks on the server with an HTTP request. The request goes
to a PHP file located in the public directory
www/, which is
index.php. Let's suppose that this is a
https://example.com/product/123. Thanks to the appropriate server settings, this URL is also
mapped to the
index.php file and will be executed.
Its task is:
- initialize the environment
- get the factory
- launch the Nette application that handles the request
What kind of factory? We do not produce tractors, but websites! Hold on, it'll be explained right away.
By “initialize the environment” we mean, for example, that Tracy is activated, which is an amazing tool for logging or visualizing errors. It logs errors on the production server and displays them directly on the development server. Therefore, initialization also needs to decide whether the site is running in production or developer mode. To do this, Nette uses autodetection: if you run the site on localhost, it runs in developer mode. You don't have to configure anything and the application is ready for both development and production deployment. These steps are performed and described in detail in the chapter about Bootstrap class.
The third point (yes, we skipped the second, but we will return to it) is to start the application. The handling of HTTP
requests in Nette is done by the class
Nette\Application\Application (hereinafter referred to as the
Application), so when we say “run an application”, we mean to call a method with the name
an object of this class.
Nette is a mentor who guides you to write clean applications by proven methodologies. And the most proven is called
dependency injection, abbreviated DI. At the moment we don't want to burden you with explaining DI, since there is a separate chapter, the important thing here is that the key
objects will usually be created by a factory for objects called DI container (abbreviated DIC). Yes, this is the factory
that was mentioned a while ago. And it also creates the
Application object for us, so we need a container first. We
get it using the
Configurator class and let it produce
Application object, call the method
run() and this starts Nette application. This is exactly what happens in the index.php file.
The Application class has a single task: to respond to an HTTP request.
Applications written in Nette are divided into many so-called presenters (in other frameworks you may come across the term controller, which is the same), which are classes representing a specific website page: eg homepage; product in e-shop; sign-in form; sitemap feed, etc. The application can have from one to thousands of presenters.
The application starts by asking the so-called router to decide which of the presenters to pass the current request for
processing. The router decides whose responsibility it is. It looks at the input URL
and, based on how it is set up, decides that this is a job, for example, for presenter
Product, who wants to
show a product with
id: 123 as an action. It is a good habit to write a pairs of presenter + action
separated by a colon as
So the router transformed the URL into a pair
Presenter:action + parameters, in our case
id: 123. You can see how a router looks like in file
app/Router/RouterFactory.php and we will describe
it in detail in chapter Routing.
Let's move on. The application already knows the name of the presenter and can continue. By creating an object
ProductPresenter, which is the code of presenter
Product. More precisely, it asks the DI container for
creating the presenter, because producting objects is its job.
The presenter might look like this:
class ProductPresenter extends Nette\Application\UI\Presenter
public function __construct(
private ProductRepository $repository,
public function renderShow(int $id): void
// we obtain data from the model and pass it to the template
$this->template->product = $this->repository->getProduct($id);
The request is handled by the presenter. And the task is clear: do action
id: 123. Which in
the language of presenters means that the method
renderShow() is called and in the parameter
$id it gets
A presenter can handle multiple actions, ie have multiple methods
render<Action>(). But we recommend
designing presenters with one or as few actions as possible.
So, the method
renderShow(123) was called, whose code is fictional example, but you can see on it how the data is
passed to the template, ie by writing to
Subsequently, the presenter returns the answer. This can be an HTML page, an image, an XML document, sending a file from disk,
JSON or redirecting to another page. Importantly, if we do not explicitly say how to respond (which is the case of
ProductPresenter), the answer will be to render the template with an HTML page. Why? Well, because in 99% of cases we
want to draw a template, so the presenter takes this behavior as the default and wants to make our work easier.
That's Nette's point.
We don't even have to state which template to draw, he derives the path to it according to simple logic. In the case of
Product and action
show, it tries to see if one of these template files exists relative to the
directory where class
ProductPresenter is located:
It will also try to find the layout in file
@layout.latte and then it renders the template. Now the task of the
presenter and the entire application is completed. If the template does not exist, a page with error 404 will be returned. You
can read more about presenters on the Presenters page.
Just to be sure, let's try to recap the whole process with a slightly different URL:
- the URL will be
- we boot the application, create a container and run
- the router decodes the URL as a pair
HomePresenterobject is created
renderDefault()is called (if exists)
- a template
templates/Home/default.lattewith a layout
You may have come across a lot of new concepts now, but we believe they make sense. Creating applications in Nette is a breeze.
When it comes to the templates, Nette uses the Latte template system. That's why the
files with templates ends with
.latte. Latte is used because it is the most secure template system for PHP, and at
the same time the most intuitive system. You don't have to learn much new, you just need to know PHP and a few Latte tags. You
will find out everything in the documentation.
In template we create a links to other presenters & actions as follows:
<a n:href="Product:show $productId">product detail</a>
Simply write the familiar
Presenter:action pair instead of the real URL and include any parameters. The trick is
n:href, which says that this attribute will be processed by Nette. And it will generate:
<a href="/product/456">product detail</a>
The previously mentioned router is in charge of generating the URL. In fact, routers in Nette are unique in that they can perform not only transformations from a URL to a pair of presenter:action, but also vice versa generate a URL from the name of the presenter + action + parameters. Thanks to this, in Nette you can completely change the form of the URL in the whole finished application without changing a single character in the template or presenter just by modifying the router. And thanks to this, the so-called canonization works, which is another unique feature of Nette, which improves SEO (optimization of searchability on the internet) by automatically preventing the existence of duplicate content at different URLs. Many programmers find this amazing.
We have one more thing to tell you about presenters: they have a built-in component system. Older of you may remember something similar from Delphi or ASP.NET Web Forms. React or Vue.js is built on something remotely similar. In the world of PHP frameworks, this is a completely unique feature.
Components are separate reusable units that we place into pages (ie presenters). They can be forms, datagrids, menus, polls, in fact anything that makes sense to use repeatedly. We can create our own components or use some of the huge range of opensource components.
Components fundamentally change the approach to application development. They will open up new possibilities for composing pages from pre-defined units. And they have something in common with Hollywood.
DI Container and Configuration
DI container (factory for objects) is the heart of the whole application.
Don't worry, it's not a magical black box, as it might seem from the previous words. Actually, it's one pretty boring PHP
class generated by Nette and stored in a cache directory. It has a lot of methods named as
each of them creates and returns an object. Yes, there is also a method
createServiceApplication() that will produce
Nette\Application\Application, which we needed in the file
index.php to run the application. And there
are methods for producing individual presenters. And so on.
The objects that the DI container creates are called services for some reason.
What is really special about this class is that it is not programmed by you, but by the framework. It actually generates the
PHP code and saves it to disk. You just give instructions on what objects the container should be able to produce and how exactly.
And these instructions are written in configuration files in the NEON format and therefore have the extension
The configuration files are used purely to instruct the DI container. So, for example, if I specify the
expiration: 14 days option in the session
section, the DI container when creating the
Nette\Http\Session object representing the session will call its method
setExpiration('14 days'), and thus configuration becomes a reality.
Once you get into the creation of services, you will come across the word autowiring. This is a gadget that will make your life incredibly easier. It can automatically pass objects where you need them (in the constructors of your classes, for example) without having to do anything. You will find that the DI container in Nette is a small miracle.
We went through the basic principles of applications in Nette. So far, very superficially, but you will soon delve into the depths and eventually create wonderful web applications. Where to continue? Have you tried the tutorial Create Your First Application?
In addition to the above, Nette has a whole arsenal of useful classes, database layer, etc. Try purposely just click through documentation. Or visit blog. You will discover a lot of interesting things.
Let the framework bring you a lot of joy 💙