Nette Documentation Preview

syntax
Главная страница блога
**********************

.[perex]
Давайте создадим главную страницу, на которой будут отображаться ваши последние посты.


Прежде чем мы начнем, вы должны знать хотя бы некоторые основы паттерна проектирования Model-View-Presenter (аналогичного MVC((Model-View-Controller))):

- **Модель** — уровень манипулирования данными. Он полностью отделен от остальной части приложения и общается только с презентерами.

- **Вид** (или _Представление_) — внешний уровень определения. Он отображает запрашиваемые данные пользователю с помощью шаблонов.

- **Презентер** (или _Контроллер_) — уровень соединения. Презентер соединяет модель и вид. Обрабатывает запросы, запрашивает данные у модели и затем передает их текущему представлению.


В случае очень простого приложения, такого как наш блог, слой Model фактически будет состоять только из запросов к самой базе данных — нам не нужен дополнительный PHP-код для этого. Нам нужно создать только слои Presenter и View. В Nette у каждого презентера есть свои представления, поэтому мы продолжим работу с ними обоими одновременно.


Создание базы данных с помощью Adminer .[#toc-creating-the-database-with-adminer]
=================================================================================

Для хранения данных мы будем использовать базу данных MySQL, поскольку это наиболее распространенный выбор среди веб-разработчиков. Но если вам это не нравится, не стесняйтесь использовать базу данных по своему выбору.

Давайте подготовим базу данных, в которой будут храниться записи нашего блога. Начнём с одной таблицы для постов.

Для создания базы данных мы можем скачать [Adminer |https://www.adminer.org], или вы можете использовать другой инструмент для управления базами данных.


Давайте откроем Adminer и создадим новую базу данных под названием `quickstart`.

Создайте новую таблицу с именем `posts` и добавьте в нее эти столбцы:
- `id` int, нажмите на автоинкремент (AI)
- `title` varchar, длина 255
- `content` text
- `created_at` timestamp

Это должно выглядеть следующим образом:

[* 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]
Очень важно использовать хранилище таблиц **InnoDB**. Причину вы увидите позже. Пока что просто создайте всё по инструкции и нажмите кнопку Сохранить. Либо используйте полный код создания таблицы и кнопку SQL-запрос в Adminer.

Попробуйте добавить несколько записей в блог, прежде чем мы реализуем возможность добавления новых записей непосредственно из нашего приложения.

```sql
INSERT INTO `posts` (`id`, `title`, `content`, `created_at`) VALUES
(1,	'Статья первая',	'Lorem ipusm dolor one',	CURRENT_TIMESTAMP),
(2,	'Статья вторая',	'Lorem ipsum dolor two',	CURRENT_TIMESTAMP),
(3,	'Статья третья',	'Lorem ipsum dolor three',	CURRENT_TIMESTAMP);
```


Подключение к базе данных .[#toc-connecting-to-the-database]
============================================================

Теперь, когда база данных создана и в ней есть несколько постов, самое время отобразить их на нашей новой блестящей странице.

Во-первых, нам нужно сообщить нашему приложению, какую базу данных использовать. Конфигурация подключения к базе данных хранится в файле `config/common.neon`. Установите соединение DSN((Имя источника данных)) и свои учётные данные. Это должно выглядеть следующим образом:

```neon .{file:config/common.neon}
database:
	dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
	user: *укажите здесь имя пользователя*
	password: *укажите здесь пароль*
```

.[note]
Помните об отступах при редактировании этого файла. [Формат NEON|neon:format] принимает и пробелы, и табуляцию, но не то и другое вместе! В файле конфигурации в веб-проекте по умолчанию используется табуляция.


Внедрение подключения к базе данных .[#toc-injecting-the-database-connection]
=============================================================================

Презентер (расположенный в `app/Presenters/HomePresenter.php`), который будет перечислять статьи, нуждается в подключении к базе данных. Для этого измените конструктор следующим образом:

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

use Nette;
use Nette\Application\UI\Form;

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

	// ...
}
```


Загрузка постов из базы данных .[#toc-loading-posts-from-the-database]
======================================================================

Теперь давайте извлечём посты из базы данных и передадим их в шаблон, который затем отобразит HTML-код. Для этого и предназначен так называемый метод *render*:

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

Теперь в презентере есть один метод рендеринга `renderDefault()`, который передает данные в представление под названием `default`. Шаблоны презентера можно найти в `app/Presenters/templates/{PresenterName}/{viewName}.latte`, поэтому в данном случае шаблон будет расположен в `app/Presenters/templates/Home/default.latte`. В шаблоне теперь доступна переменная `$posts`, которая содержит посты из базы данных.


Шаблон .[#toc-template]
=======================

Существует общий шаблон для всей страницы (называется *layout* (макет), с заголовком, таблицами стилей, нижним колонтитулом и т. д.), а также специфические шаблоны для каждого вида (например, для отображения списка записей блога), которые могут переопределять некоторые части шаблона макета.

По умолчанию шаблон макета располагается в файле `app/Presenters/templates/@layout.latte`, который содержит:

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

`{include content}` вставляет блок с именем `content` в основной шаблон. Вы можете определить его в шаблонах каждого представления. В нашем случае мы отредактируем файл `app/Presenters/templates/Home/default.latte` следующим образом:

```latte .{file:app/Presenters/templates/Home/default.latte}
{block content}
	Привет, мир!
{/block}
```

Он определяет [блок |latte:tags#block] *контента*, который будет вставлен в макет. Если вы обновите браузер, то увидите страницу с текстом «Привет, мир!» (в исходном коде также с HTML заголовком и колонтитулом, определенными в `@layout.latte`).

Давайте отобразим записи блога — для этого отредактируем шаблон следующим образом:

```latte .{file:app/Presenters/templates/Home/default.latte}
{block content}
	<h1 n:block="title">Мой блог</h1>

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

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

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

Если вы обновите браузер, вы увидите список записей вашего блога. Список не очень причудлив или красочен, поэтому не стесняйтесь добавить немного [блестящего CSS |https://github.com/nette-examples/quickstart/blob/v4.0/www/css/style.css] в `www/css/style.css`, а затем вставьте ссылку на этот файл в макет (файл `@layout.latte`):

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

Тег `{foreach}` перебирает все посты, переданные шаблону в переменной `$posts`, и выводит фрагмент HTML-кода для каждого поста. Точно так же, как это делается в PHP-коде.

Функция `|date` называется фильтром. Фильтры используются для форматирования вывода. Этот конкретный фильтр преобразует дату (например, `2013-04-12`) в более читаемую форму (`12.04.2013`). Фильтр `|truncate` усекает строку до указанной максимальной длины и добавляет многоточие в конец, если строка усечена. Поскольку это предварительный просмотр, нет смысла отображать полное содержание статьи. Другие фильтры по умолчанию [можно найти в документации |latte:filters] или вы можете создать свои собственные, если это необходимо.

И ещё одно. Мы можем сделать код немного короче и, следовательно, проще. Мы можем заменить *теги Latte* на *n:attributes* следующим образом:

```latte .{file:app/Presenters/templates/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}
```

`n:foreach` просто обертывает *div* блоком *foreach* (он делает точно то же самое, что и предыдущий блок кода).


Подведём итог .[#toc-summary]
=============================

У нас есть очень простая база данных MySQL с некоторыми записями в блоге. Приложение подключается к базе данных и отображает простой список постов.

{{priority: -1}}
{{sitename: Быстрый старт с Nette}}

Главная страница блога

Давайте создадим главную страницу, на которой будут отображаться ваши последние посты.

Прежде чем мы начнем, вы должны знать хотя бы некоторые основы паттерна проектирования Model-View-Presenter (аналогичного MVC):

  • Модель — уровень манипулирования данными. Он полностью отделен от остальной части приложения и общается только с презентерами.
  • Вид (или _Представление_) — внешний уровень определения. Он отображает запрашиваемые данные пользователю с помощью шаблонов.
  • Презентер (или _Контроллер_) — уровень соединения. Презентер соединяет модель и вид. Обрабатывает запросы, запрашивает данные у модели и затем передает их текущему представлению.

В случае очень простого приложения, такого как наш блог, слой Model фактически будет состоять только из запросов к самой базе данных — нам не нужен дополнительный PHP-код для этого. Нам нужно создать только слои Presenter и View. В Nette у каждого презентера есть свои представления, поэтому мы продолжим работу с ними обоими одновременно.

Создание базы данных с помощью Adminer

Для хранения данных мы будем использовать базу данных MySQL, поскольку это наиболее распространенный выбор среди веб-разработчиков. Но если вам это не нравится, не стесняйтесь использовать базу данных по своему выбору.

Давайте подготовим базу данных, в которой будут храниться записи нашего блога. Начнём с одной таблицы для постов.

Для создания базы данных мы можем скачать Adminer, или вы можете использовать другой инструмент для управления базами данных.

Давайте откроем Adminer и создадим новую базу данных под названием quickstart.

Создайте новую таблицу с именем posts и добавьте в нее эти столбцы:

  • id int, нажмите на автоинкремент (AI)
  • title varchar, длина 255
  • content text
  • created_at timestamp

Это должно выглядеть следующим образом:

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;

Очень важно использовать хранилище таблиц InnoDB. Причину вы увидите позже. Пока что просто создайте всё по инструкции и нажмите кнопку Сохранить. Либо используйте полный код создания таблицы и кнопку SQL-запрос в Adminer.

Попробуйте добавить несколько записей в блог, прежде чем мы реализуем возможность добавления новых записей непосредственно из нашего приложения.

INSERT INTO `posts` (`id`, `title`, `content`, `created_at`) VALUES
(1,	'Статья первая',	'Lorem ipusm dolor one',	CURRENT_TIMESTAMP),
(2,	'Статья вторая',	'Lorem ipsum dolor two',	CURRENT_TIMESTAMP),
(3,	'Статья третья',	'Lorem ipsum dolor three',	CURRENT_TIMESTAMP);

Подключение к базе данных

Теперь, когда база данных создана и в ней есть несколько постов, самое время отобразить их на нашей новой блестящей странице.

Во-первых, нам нужно сообщить нашему приложению, какую базу данных использовать. Конфигурация подключения к базе данных хранится в файле config/common.neon. Установите соединение DSN и свои учётные данные. Это должно выглядеть следующим образом:

database:
	dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
	user: *укажите здесь имя пользователя*
	password: *укажите здесь пароль*

Помните об отступах при редактировании этого файла. Формат NEON принимает и пробелы, и табуляцию, но не то и другое вместе! В файле конфигурации в веб-проекте по умолчанию используется табуляция.

Внедрение подключения к базе данных

Презентер (расположенный в app/Presenters/HomePresenter.php), который будет перечислять статьи, нуждается в подключении к базе данных. Для этого измените конструктор следующим образом:

<?php
namespace App\Presenters;

use Nette;
use Nette\Application\UI\Form;

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

	// ...
}

Загрузка постов из базы данных

Теперь давайте извлечём посты из базы данных и передадим их в шаблон, который затем отобразит HTML-код. Для этого и предназначен так называемый метод render:

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

Теперь в презентере есть один метод рендеринга renderDefault(), который передает данные в представление под названием default. Шаблоны презентера можно найти в app/Presenters/templates/{PresenterName}/{viewName}.latte, поэтому в данном случае шаблон будет расположен в app/Presenters/templates/Home/default.latte. В шаблоне теперь доступна переменная $posts, которая содержит посты из базы данных.

Шаблон

Существует общий шаблон для всей страницы (называется layout (макет), с заголовком, таблицами стилей, нижним колонтитулом и т. д.), а также специфические шаблоны для каждого вида (например, для отображения списка записей блога), которые могут переопределять некоторые части шаблона макета.

По умолчанию шаблон макета располагается в файле app/Presenters/templates/@layout.latte, который содержит:

...
{include content}
...

{include content} вставляет блок с именем content в основной шаблон. Вы можете определить его в шаблонах каждого представления. В нашем случае мы отредактируем файл app/Presenters/templates/Home/default.latte следующим образом:

{block content}
	Привет, мир!
{/block}

Он определяет блок контента, который будет вставлен в макет. Если вы обновите браузер, то увидите страницу с текстом «Привет, мир!» (в исходном коде также с HTML заголовком и колонтитулом, определенными в @layout.latte).

Давайте отобразим записи блога — для этого отредактируем шаблон следующим образом:

{block content}
	<h1 n:block="title">Мой блог</h1>

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

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

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

Если вы обновите браузер, вы увидите список записей вашего блога. Список не очень причудлив или красочен, поэтому не стесняйтесь добавить немного блестящего CSS в www/css/style.css, а затем вставьте ссылку на этот файл в макет (файл @layout.latte):

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

Тег {foreach} перебирает все посты, переданные шаблону в переменной $posts, и выводит фрагмент HTML-кода для каждого поста. Точно так же, как это делается в PHP-коде.

Функция |date называется фильтром. Фильтры используются для форматирования вывода. Этот конкретный фильтр преобразует дату (например, 2013-04-12) в более читаемую форму (12.04.2013). Фильтр |truncate усекает строку до указанной максимальной длины и добавляет многоточие в конец, если строка усечена. Поскольку это предварительный просмотр, нет смысла отображать полное содержание статьи. Другие фильтры по умолчанию можно найти в документации или вы можете создать свои собственные, если это необходимо.

И ещё одно. Мы можем сделать код немного короче и, следовательно, проще. Мы можем заменить теги Latte на n:attributes следующим образом:

{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}

n:foreach просто обертывает div блоком foreach (он делает точно то же самое, что и предыдущий блок кода).

Подведём итог

У нас есть очень простая база данных MySQL с некоторыми записями в блоге. Приложение подключается к базе данных и отображает простой список постов.