Формы с ActiveForm
ActiveForm — виджет, который строит форму HTML по модели: сам создаёт поля с подписями, показывает ошибки проверки и добавляет защиту от подделки запросов. Виджетом в Yii называют готовый блок интерфейса, который вызывают в шаблоне.
Действие контроллера
Одно действие и показывает форму, и принимает её. Добавьте в controllers/PostController.php:
// controllers/PostController.php
public function actionCreate()
{
$post = new Post();
if ($post->load(Yii::$app->request->post()) && $post->save()) {
return $this->redirect(['post/view', 'id' => $post->id]);
}
return $this->render('create', ['post' => $post]);
}load() заполняет модель данными формы и возвращает false, если форма не отправлена. save() проверяет и записывает. При успехе посетитель уходит на страницу статьи, иначе форма показывается снова — уже с ошибками.
Шаблон формы
Создайте файл views/post/create.php:
<?php
// views/post/create.php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$this->title = 'Новая статья';
?>
<h1><?= Html::encode($this->title) ?></h1>
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($post, 'title') ?>
<?= $form->field($post, 'body')->textarea(['rows' => 8]) ?>
<?= Html::submitButton('Сохранить', ['class' => 'btn btn-primary']) ?>
<?php ActiveForm::end(); ?>Откройте /post/create. Вызов field() создаёт подпись из attributeLabels(), поле ввода и место для ошибки. Отправьте пустую форму — под полями появятся сообщения из правил модели. В стандартном проекте можно подключить yii\bootstrap5\ActiveForm вместо yii\widgets\ActiveForm — форма получит оформление Bootstrap.
Столбцы user_id, created_at и updated_at пока не заполняются. До урока о поведениях задайте их в действии перед save() или дайте им значения по умолчанию в миграции.
Виды полей
| Вызов | Поле |
|---|---|
$form->field($post, 'title') | Текстовая строка |
->textarea(['rows' => 8]) | Многострочный текст |
->passwordInput() | Пароль |
->dropDownList([0 => 'Черновик', 1 => 'Опубликована']) | Выпадающий список |
->checkbox() | Флажок |
->hint('До 255 символов') | Подсказка под полем |
->label('Название') | Своя подпись |
Изменение записи
Форма изменения отличается только тем, что модель берут из базы:
public function actionUpdate(int $id)
{
$post = Post::findOne($id);
if ($post === null) {
throw new NotFoundHttpException('Статья не найдена.');
}
if ($post->load(Yii::$app->request->post()) && $post->save()) {
return $this->redirect(['post/view', 'id' => $post->id]);
}
return $this->render('update', ['post' => $post]);
}Поля окажутся заполненными текущими значениями. Чтобы не повторять разметку, поля выносят в общий файл views/post/_form.php и вставляют его в create.php и update.php вызовом $this->render('_form', ['post' => $post]).
Защита от подделки запросов
ActiveForm добавляет в форму скрытое поле _csrf со случайным значением. Yii сверяет его при каждом запросе POST и отклоняет формы, отправленные с чужих сайтов.
Частая ошибка
Форма, написанная тегами вручную, отправляет поля с именами вроде title. А load() ждёт данные, сгруппированные по имени модели: Post[title], Post[body]. Такая форма «не сохраняется» без единой ошибки. Стройте поля через $form->field() — имена получатся правильными.