Nette Documentation Preview

syntax
Создание и редактирование постов
********************************

Какое замечательное время. У нас появился новый суперкрутой блог, люди спорят в комментариях, и у нас наконец-то появилось время для программирования. Хотя нам нравится Adminer, писать в нем статьи для блога не очень удобно. Возможно, сейчас самое время добавить простую форму для добавления новых постов прямо из нашего приложения. Давайте сделаем это.

Начнём с разработки пользовательского интерфейса:

1. На главной странице добавим ссылку «Написать новый пост».
2. Она отобразит форму с заголовком и текстовой областью для содержимого.
3. Когда вы нажмете кнопку «Сохранить», она сохранит запись в блоге.

Позже мы также добавим аутентификацию и разрешим добавлять новые сообщения только вошедшим в систему пользователям. Какой код нам нужно написать, чтобы он работал?

1. Создайте новый презентер с формой для добавления постов.
2. Определите обратный вызов, который будет срабатывать после успешной отправки формы и который сохранит новое сообщение в базе данных.
3. Создайте новый шаблон для формы.
4. Добавьте ссылку на форму в шаблон главной страницы.


Новый презентер .[#toc-new-presenter]
=====================================

Назовите новый презентер `EditPresenter` и сохраните его в `app/UI/Edit/`. Ему также необходимо подключиться к базе данных, поэтому здесь мы снова пишем конструктор, который потребует подключения к базе данных:

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

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

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


Форма для сохранения сообщений .[#toc-form-for-saving-posts]
============================================================

Формы и компоненты уже рассматривались, когда мы добавляли поддержку комментариев. Если вы запутались в теме, посмотрите [как работают формы и компоненты |comments#Form-for-Commenting] ещё раз, мы подождем здесь ;)

Теперь добавьте этот метод в `EditPresenter`:

```php .{file:app/UI/Edit/EditPresenter.php}
protected function createComponentPostForm(): Form
{
	$form = new Form;
	$form->addText('title', 'Заголовок:')
		->setRequired();
	$form->addTextArea('content', 'Содержание:')
		->setRequired();

	$form->addSubmit('send', 'Сохранить и опубликовать');
	$form->onSuccess[] = $this->postFormSucceeded(...);

	return $form;
}
```


Сохранение нового поста из формы .[#toc-saving-new-post-from-form]
==================================================================

Добавим метод обработчика:

```php .{file:app/UI/Edit/EditPresenter.php}
private function postFormSucceeded(array $data): void
{
	$post = $this->database
		->table('posts')
		->insert($data);

	$this->flashMessage('Пост опубликован!', 'success');
	$this->redirect('Post:show', $post->id);
}
```

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


Страница для создания нового поста .[#toc-page-for-creating-a-new-post]
=======================================================================

Давайте просто создадим шаблон (`app/UI/Edit/create.latte`):

```latte .{file:app/UI/Edit/create.latte}
{block content}
<h1>Новый пост</h1>

{control postForm}
```

Теперь всё должно быть ясно. Последняя строка показывает форму, которую мы собираемся создать.

Мы могли бы также создать соответствующий метод `renderCreate`, но это не обязательно. Нам не нужно получать данные из базы данных и передавать их в шаблон, поэтому этот метод будет пустым. В таких случаях метод может вообще не существовать.


Ссылка для создания постов .[#toc-link-for-creating-posts]
==========================================================

Вы, вероятно, уже знаете, как добавить ссылку на `EditPresenter` и его действие `create`. Попробуйте.

Просто добавьте в файл `app/UI/Home/default.latte`:

```latte
<a n:href="Edit:create">Создать пост</a>
```


Редактирование постов .[#toc-editing-posts]
===========================================

Давайте также добавим возможность редактировать существующие сообщения. Это будет довольно просто — у нас уже есть `postForm`, и мы можем использовать её и для редактирования.

Мы добавим новую страницу `edit` в `EditPresenter`:

```php .{file:app/UI/Edit/EditPresenter.php}
public function renderEdit(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);

	if (!$post) {
		$this->error('Пост не найден');
	}

	$this->getComponent('postForm')
		->setDefaults($post->toArray());
}
```

И создайте шаблон `Edit/edit.latte`:

```latte .{file:app/UI/Edit/edit.latte}
{block content}
<h1>Редактирование поста</h1>

{control postForm}
```

И обновите метод `postFormSucceeded`, который сможет либо добавлять новый пост (как сейчас), либо редактировать существующие:

```php .{file:app/UI/Edit/EditPresenter.php}
private function postFormSucceeded(array $data): void
{
	$id = $this->getParameter('id');

	if ($id) {
		$post = $this->database
			->table('posts')
			->get($id);
		$post->update($data);

	} else {
		$post = $this->database
			->table('posts')
			->insert($data);
	}

	$this->flashMessage('Пост опубликован', 'success');
	$this->redirect('Post:show', $post->id);
}
```

Если указан параметр `id`, это означает, что пост редактируется. В этом случае мы проверим, действительно ли пост существует, и если да, то обновим его в базе данных. Если `id` не указан, это означает, что будет добавлен новый пост.

Но откуда берется `id`? Это параметр, передаваемый методу `renderEdit`.

Теперь вы можете добавить ссылку для изменения поста в шаблон `app/UI/Post/show.latte`:

```latte
<a n:href="Edit:edit $post->id">Изменить пост</a>
```


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

Блог работает, люди быстро комментируют, и мы больше не полагаемся на Админа для добавления новых постов. Блог полностью независим, и даже обычные люди могут размещать там свои сообщения. Но подождите, это, наверное, не нормально, что любой, я имею в виду действительно любой человек в Интернете, может написать в нашем блоге. Требуется определенная форма аутентификации, чтобы только вошедшие в систему пользователи могли размещать сообщения. Мы добавим это в следующей главе.

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

Создание и редактирование постов

Какое замечательное время. У нас появился новый суперкрутой блог, люди спорят в комментариях, и у нас наконец-то появилось время для программирования. Хотя нам нравится Adminer, писать в нем статьи для блога не очень удобно. Возможно, сейчас самое время добавить простую форму для добавления новых постов прямо из нашего приложения. Давайте сделаем это.

Начнём с разработки пользовательского интерфейса:

  1. На главной странице добавим ссылку «Написать новый пост».
  2. Она отобразит форму с заголовком и текстовой областью для содержимого.
  3. Когда вы нажмете кнопку «Сохранить», она сохранит запись в блоге.

Позже мы также добавим аутентификацию и разрешим добавлять новые сообщения только вошедшим в систему пользователям. Какой код нам нужно написать, чтобы он работал?

  1. Создайте новый презентер с формой для добавления постов.
  2. Определите обратный вызов, который будет срабатывать после успешной отправки формы и который сохранит новое сообщение в базе данных.
  3. Создайте новый шаблон для формы.
  4. Добавьте ссылку на форму в шаблон главной страницы.

Новый презентер

Назовите новый презентер EditPresenter и сохраните его в app/UI/Edit/. Ему также необходимо подключиться к базе данных, поэтому здесь мы снова пишем конструктор, который потребует подключения к базе данных:

<?php
namespace App\UI\Edit;

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

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

Форма для сохранения сообщений

Формы и компоненты уже рассматривались, когда мы добавляли поддержку комментариев. Если вы запутались в теме, посмотрите как работают формы и компоненты ещё раз, мы подождем здесь ;)

Теперь добавьте этот метод в EditPresenter:

protected function createComponentPostForm(): Form
{
	$form = new Form;
	$form->addText('title', 'Заголовок:')
		->setRequired();
	$form->addTextArea('content', 'Содержание:')
		->setRequired();

	$form->addSubmit('send', 'Сохранить и опубликовать');
	$form->onSuccess[] = $this->postFormSucceeded(...);

	return $form;
}

Сохранение нового поста из формы

Добавим метод обработчика:

private function postFormSucceeded(array $data): void
{
	$post = $this->database
		->table('posts')
		->insert($data);

	$this->flashMessage('Пост опубликован!', 'success');
	$this->redirect('Post:show', $post->id);
}

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

Страница для создания нового поста

Давайте просто создадим шаблон (app/UI/Edit/create.latte):

{block content}
<h1>Новый пост</h1>

{control postForm}

Теперь всё должно быть ясно. Последняя строка показывает форму, которую мы собираемся создать.

Мы могли бы также создать соответствующий метод renderCreate, но это не обязательно. Нам не нужно получать данные из базы данных и передавать их в шаблон, поэтому этот метод будет пустым. В таких случаях метод может вообще не существовать.

Вы, вероятно, уже знаете, как добавить ссылку на EditPresenter и его действие create. Попробуйте.

Просто добавьте в файл app/UI/Home/default.latte:

<a n:href="Edit:create">Создать пост</a>

Редактирование постов

Давайте также добавим возможность редактировать существующие сообщения. Это будет довольно просто — у нас уже есть postForm, и мы можем использовать её и для редактирования.

Мы добавим новую страницу edit в EditPresenter:

public function renderEdit(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);

	if (!$post) {
		$this->error('Пост не найден');
	}

	$this->getComponent('postForm')
		->setDefaults($post->toArray());
}

И создайте шаблон Edit/edit.latte:

{block content}
<h1>Редактирование поста</h1>

{control postForm}

И обновите метод postFormSucceeded, который сможет либо добавлять новый пост (как сейчас), либо редактировать существующие:

private function postFormSucceeded(array $data): void
{
	$id = $this->getParameter('id');

	if ($id) {
		$post = $this->database
			->table('posts')
			->get($id);
		$post->update($data);

	} else {
		$post = $this->database
			->table('posts')
			->insert($data);
	}

	$this->flashMessage('Пост опубликован', 'success');
	$this->redirect('Post:show', $post->id);
}

Если указан параметр id, это означает, что пост редактируется. В этом случае мы проверим, действительно ли пост существует, и если да, то обновим его в базе данных. Если id не указан, это означает, что будет добавлен новый пост.

Но откуда берется id? Это параметр, передаваемый методу renderEdit.

Теперь вы можете добавить ссылку для изменения поста в шаблон app/UI/Post/show.latte:

<a n:href="Edit:edit $post->id">Изменить пост</a>

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

Блог работает, люди быстро комментируют, и мы больше не полагаемся на Админа для добавления новых постов. Блог полностью независим, и даже обычные люди могут размещать там свои сообщения. Но подождите, это, наверное, не нормально, что любой, я имею в виду действительно любой человек в Интернете, может написать в нашем блоге. Требуется определенная форма аутентификации, чтобы только вошедшие в систему пользователи могли размещать сообщения. Мы добавим это в следующей главе.