Nette Documentation Preview

syntax
Blog Home Page
**************

.[perex]
Let’s create the home page displaying your recent posts.


Before we start, you should know at least some basics about Model-View-Presenter design pattern (similar to MVC((Model-View-Controller))):

- **Model** - data manipulation layer. It is completely separated from the rest of the application. It only communicates with presenters.

- **View** - a front-end definition layer. It renders requested data to the user using templates.

- **Presenter** (or Controller) - a connection layer. Presenter connects Model and View. Handles requests, asks Model for data and then passes them to the current View.


In case of a very simple application like our blog, the Model layer will actually consist only of queries to the database itself - we don't need any extra PHP code for it. We only need to create Presenter and View layers. In Nette, each Presenter has its own Views, so we will continue with both simultaneously.


Creating the Database with Adminer
==================================

To store the data, we will use the MySQL database because it is the most common choice among web developers. But if you don’t like it, feel free to use a database of your choice.

Let’s prepare the database which will store our blog posts. We can start very simply - just with a single table for posts.

To create the database we can download [Adminer |https://www.adminer.org], or you can use another tool for database management.


Let’s open Adminer and create a new database called `quickstart`.

Create a new table named `posts` and add these columns:
- `id` int, click on autoincrement (AI)
- `title` varchar, length 255
- `content` text
- `created_at` timestamp

It should look like this:

[* adminer-posts.webp *]

```sql
CREATE TABLE `posts` (
	`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`title` varchar(255) NOT NULL,
	`content` text NOT NULL,
	`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARSET=utf8;
```

.[caution]
It’s very important to use the **InnoDB** table storage. You will see the reason later. For now, just choose that and submit. You can hit Save now.

Try adding some sample blog posts before we implement the capability of adding new posts directly from our application.

```sql
INSERT INTO `posts` (`id`, `title`, `content`, `created_at`) VALUES
(1,	'Article One',	'Lorem ipusm dolor one',	CURRENT_TIMESTAMP),
(2,	'Article Two',	'Lorem ipsum dolor two',	CURRENT_TIMESTAMP),
(3,	'Article Three',	'Lorem ipsum dolor three',	CURRENT_TIMESTAMP);
```


Connecting to the Database
==========================

Now, when the database is created and we have some posts in it, it’s the right time to display them on our new shiny page.

First, we need to tell our application about which database to use. The database connection configuration is stored in `config/common.neon`. Set the connection DSN((Data Source Name)) and your credentials. It should look like this:

```neon .{file:config/common.neon}
database:
	dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
	user: *enter user name*
	password: *enter password here*
```

.[note]
Be aware of indenting while editing this file. [NEON format|neon:format] accepts both spaces and tabs but not both together! The configuration file in the Web Project uses tabs as default.


Injecting the Database Connection
=================================

The presenter `HomePresenter`, which will list the articles, needs a database connection. To receive it, write a constructor like this:

```php .{file:app/UI/Home/HomePresenter.php}
<?php
namespace App\UI\Home;

use Nette;

final class HomePresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	// ...
}
```


Loading Posts from the Database
===============================

Now let’s fetch the posts from the database and pass them to the template, which will then render the HTML code. This is what the so-called *render* method is for:

```php .{file:app/UI/Home/HomePresenter.php}
public function renderDefault(): void
{
	$this->template->posts = $this->database
		->table('posts')
		->order('created_at DESC')
		->limit(5);
}
```

The presenter now has one render method `renderDefault()` that passes data to a view called `default`. Presenter templates can be found in `app/UI/{PresenterName}/{viewName}.latte`, so in this case the template will be located in `app/UI/Home/default.latte`. In the template, a variable named `$posts` is now available, which contains the posts from database.


Template
========

There is a generic template for the whole page (called *layout*, with header, stylesheets, footer, ...) and then specific templates for each view (e.g. for displaying the list of blog posts), which can override some of layout template parts.

By default, the layout template is located in `app/UI/@layout.latte`, which contains:

```latte .{file:app/UI/@layout.latte}
...
{include content}
...
```

`{include content}` inserts a block named `content` into the main template. You can define it in the templates of each view. In this case, we will edit the file `Home/default.latte` like this:

```latte .{file:app/UI/Home/default.latte}
{block content}
	Hello World
{/block}
```

It defines the *content* [block |latte:tags#block], which will be inserted into the layout. If you refresh the browser, you’ll see a page with text "Hello world" (in source code also with HTML header and footer defined in `@layout.latte`).

Let’s display the blog posts - we will edit the template like this:

```latte .{file:app/UI/Home/default.latte}
{block content}
	<h1>My blog</h1>

	{foreach $posts as $post}
	<div class="post">
		<div class="date">{$post->created_at|date:'j. n. Y'}</div>

		<h2>{$post->title}</h2>

		<div>{$post->content|truncate:256}</div>
	</div>
	{/foreach}
{/block}
```

If you refresh your browser, you’ll see the list of your blog posts. The list isn't very fancy or colorful, so feel free to add some [shiny CSS |https://github.com/nette-examples/quickstart/blob/v4.0/www/css/style.css] to `www/css/style.css` and link it in a layout:

```latte .{file:app/UI/@layout.latte}
	...
	<link rel="stylesheet" href="{$basePath}/css/style.css">
</head>
...
```

The `{foreach}` tag iterates over all posts passed to the template in `$posts` variable and displays a piece of HTML code for each post. Just like a PHP code would.

The `|date` thing is called a filter. Filters are used to format the output. This particular filter converts a date (e.g. `2013-04-12`) to its more readable form (`12. 4. 2013`). The `|truncate` filter truncates the string to the specified maximum length, and adds a ellipsis to the end if the string is truncated. Since this is a preview, there is no point in displaying the full content of the article. Other default filters [can be found in the documentation |latte:filters] or you can create your own if needed.

One more thing. We can make the code a little bit shorter and thus simpler. We can replace *Latte tags* with *n:attributes* like this:

```latte .{file:app/UI/Home/default.latte}
{block content}
	<h1>My blog</h1>

	<div n:foreach="$posts as $post" class="post">
		<div class="date">{$post->created_at|date:'F j, Y'}</div>

		<h2>{$post->title}</h2>

		<div>{$post->content}</div>
	</div>
{/block}
```

The `n:foreach`, simply wraps the *div* with a *foreach* block (it does exactly the same thing as the previous block of code).


Summary
=======

We have a very simple MySQL database with some blog posts in it. The application connects to the database and displays a simple list of the posts.

{{priority: -1}}
{{sitename: Nette Quickstart}}

Blog Home Page

Let’s create the home page displaying your recent posts.

Before we start, you should know at least some basics about Model-View-Presenter design pattern (similar to MVC):

  • Model – data manipulation layer. It is completely separated from the rest of the application. It only communicates with presenters.
  • View – a front-end definition layer. It renders requested data to the user using templates.
  • Presenter (or Controller) – a connection layer. Presenter connects Model and View. Handles requests, asks Model for data and then passes them to the current View.

In case of a very simple application like our blog, the Model layer will actually consist only of queries to the database itself – we don't need any extra PHP code for it. We only need to create Presenter and View layers. In Nette, each Presenter has its own Views, so we will continue with both simultaneously.

Creating the Database with Adminer

To store the data, we will use the MySQL database because it is the most common choice among web developers. But if you don’t like it, feel free to use a database of your choice.

Let’s prepare the database which will store our blog posts. We can start very simply – just with a single table for posts.

To create the database we can download Adminer, or you can use another tool for database management.

Let’s open Adminer and create a new database called quickstart.

Create a new table named posts and add these columns:

  • id int, click on autoincrement (AI)
  • title varchar, length 255
  • content text
  • created_at timestamp

It should look like this:

CREATE TABLE `posts` (
	`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`title` varchar(255) NOT NULL,
	`content` text NOT NULL,
	`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARSET=utf8;

It’s very important to use the InnoDB table storage. You will see the reason later. For now, just choose that and submit. You can hit Save now.

Try adding some sample blog posts before we implement the capability of adding new posts directly from our application.

INSERT INTO `posts` (`id`, `title`, `content`, `created_at`) VALUES
(1,	'Article One',	'Lorem ipusm dolor one',	CURRENT_TIMESTAMP),
(2,	'Article Two',	'Lorem ipsum dolor two',	CURRENT_TIMESTAMP),
(3,	'Article Three',	'Lorem ipsum dolor three',	CURRENT_TIMESTAMP);

Connecting to the Database

Now, when the database is created and we have some posts in it, it’s the right time to display them on our new shiny page.

First, we need to tell our application about which database to use. The database connection configuration is stored in config/common.neon. Set the connection DSN and your credentials. It should look like this:

database:
	dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
	user: *enter user name*
	password: *enter password here*

Be aware of indenting while editing this file. NEON format accepts both spaces and tabs but not both together! The configuration file in the Web Project uses tabs as default.

Injecting the Database Connection

The presenter HomePresenter, which will list the articles, needs a database connection. To receive it, write a constructor like this:

<?php
namespace App\UI\Home;

use Nette;

final class HomePresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	// ...
}

Loading Posts from the Database

Now let’s fetch the posts from the database and pass them to the template, which will then render the HTML code. This is what the so-called render method is for:

public function renderDefault(): void
{
	$this->template->posts = $this->database
		->table('posts')
		->order('created_at DESC')
		->limit(5);
}

The presenter now has one render method renderDefault() that passes data to a view called default. Presenter templates can be found in app/UI/{PresenterName}/{viewName}.latte, so in this case the template will be located in app/UI/Home/default.latte. In the template, a variable named $posts is now available, which contains the posts from database.

Template

There is a generic template for the whole page (called layout, with header, stylesheets, footer, …) and then specific templates for each view (e.g. for displaying the list of blog posts), which can override some of layout template parts.

By default, the layout template is located in app/UI/@layout.latte, which contains:

...
{include content}
...

{include content} inserts a block named content into the main template. You can define it in the templates of each view. In this case, we will edit the file Home/default.latte like this:

{block content}
	Hello World
{/block}

It defines the content block, which will be inserted into the layout. If you refresh the browser, you’ll see a page with text „Hello world“ (in source code also with HTML header and footer defined in @layout.latte).

Let’s display the blog posts – we will edit the template like this:

{block content}
	<h1>My blog</h1>

	{foreach $posts as $post}
	<div class="post">
		<div class="date">{$post->created_at|date:'j. n. Y'}</div>

		<h2>{$post->title}</h2>

		<div>{$post->content|truncate:256}</div>
	</div>
	{/foreach}
{/block}

If you refresh your browser, you’ll see the list of your blog posts. The list isn't very fancy or colorful, so feel free to add some shiny CSS to www/css/style.css and link it in a layout:

	...
	<link rel="stylesheet" href="{$basePath}/css/style.css">
</head>
...

The {foreach} tag iterates over all posts passed to the template in $posts variable and displays a piece of HTML code for each post. Just like a PHP code would.

The |date thing is called a filter. Filters are used to format the output. This particular filter converts a date (e.g. 2013-04-12) to its more readable form (12. 4. 2013). The |truncate filter truncates the string to the specified maximum length, and adds a ellipsis to the end if the string is truncated. Since this is a preview, there is no point in displaying the full content of the article. Other default filters can be found in the documentation or you can create your own if needed.

One more thing. We can make the code a little bit shorter and thus simpler. We can replace Latte tags with n:attributes like this:

{block content}
	<h1>My blog</h1>

	<div n:foreach="$posts as $post" class="post">
		<div class="date">{$post->created_at|date:'F j, Y'}</div>

		<h2>{$post->title}</h2>

		<div>{$post->content}</div>
	</div>
{/block}

The n:foreach, simply wraps the div with a foreach block (it does exactly the same thing as the previous block of code).

Summary

We have a very simple MySQL database with some blog posts in it. The application connects to the database and displays a simple list of the posts.