Yii2. Валидация формы. Часть 2
Теперь, когда мы задали правила валидации полей формы, настало время их проверять при отправке данных пользователем. В этом нам поможет метод модели validate()
. Посмотрим, как можно получить массив сообщений об ошибках, сохранить данные в сессии и выполнить редирект.
Простой вариант
Класс модели:
<?php namespace app\models; use yii\base\Model; /** * Модель для формы обратной связи */ class FeedbackForm extends Model { public $name, $email, $body; public function attributeLabels() { return [ 'name' => 'Ваше имя', 'email' => 'Ваш email', 'body' => 'Сообщение', ]; } public function rules() { return [ // удалить пробелы для полей name и email [['name', 'email'], 'trim'], // поле name обязательно для заполнения ['name', 'required', 'message' => 'Поле «Ваше имя» обязательно для заполнения'], // поле email обязательно для заполнения ['email', 'required', 'message' => 'Поле «Ваш email» обязательно для заполнения'], // поле email должно быть корректным адресом почты ['email', 'email', 'message' => 'Поле «Ваш email» должно быть адресом почты'], /* * Поле формы обязательно должно проходить валидацию, даже если оно не обязательное. * В противном случае, поле не пройдет валидацию, независимо от того, пустое оно или * нет. Здесь мы просто говорим, что поле безопасное (safe). Можно было вместо safe * использовать trim или default — главное, чтобы хоть какой-нибудь валидатор был * использован. */ ['body', 'safe'] ]; } }
Класс контроллера:
<?php namespace app\controllers; use Yii; use yii\web\Controller; use app\models\FeedbackForm; class PageController extends Controller { public function actionIndex() { return $this->render('index'); } public function actionFeedback() { $model = new FeedbackForm(); // если пришли post-данные, загружаем их в модель... if ($model->load(Yii::$app->request->post())) { // ...и проверяем эти данные if ($model->validate()) { // данные прошли валидацию, отмечаем этот факт Yii::$app->session->setFlash( 'validate', true ); // перезагружаем страницу, чтобы избежать повторной отправки формы return $this->refresh(); } else { // данные не прошли валидацию, отмечаем этот факт Yii::$app->session->setFlash( 'validate', false ); // не перезагружаем страницу, чтобы сохранить пользовательские данные } } return $this->render('feedback', ['model' => $model]); } }
Шаблон формы:
<?php /* @var $this yii\web\View */ use yii\widgets\ActiveForm; use yii\helpers\Html; $this->title = 'Обратная связь'; ?> <?php if (Yii::$app->session->hasFlash('validate')): ?> <?php if (Yii::$app->session->getFlash('validate')): ?> <p>Данные формы прошли валидацию</p> <?php else: ?> <p>Данные формы не прошли валидацию</p> <?php endif; ?> <?php endif; ?> <div class="site-feedback"> <h1><?= Html::encode($this->title) ?></h1> <?php $form = ActiveForm::begin(['id' => 'feedback-form', 'options' => ['novalidate' => '']]); ?> <?= $form->field($model, 'name')->textInput(); ?> <?= $form->field($model, 'email')->textInput(); ?> <?= $form->field($model, 'body')->textarea(['rows' => 5]); ?> <?= Html::submitButton('Отправить', ['class' => 'btn btn-primary']); ?> <?php ActiveForm::end(); ?> </div>
Чтобы ошибки валидации на стороне клиента не мешали тестированию, есть смысл отключить в браузере поддержку JavaScript.
Вывести в шаблоне все сообщения об ошибках можно с помощью метода errorSummary()
класса Html
или класса ActiveForm
:
<div class="alert alert-warning alert-dismissible" role="alert"> <?= Html::errorSummary($model); ?> </div>
<?php $form = ActiveForm::begin(); ?> <?= $form->errorSummary($model); ?> .......... <?= Html::submitButton('Отправить'); ?> <?php ActiveForm::end(); ?>
Вариант посложнее
Класс модели:
<?php namespace app\models; use yii\base\Model; /** * Модель для формы обратной связи */ class FeedbackForm extends Model { public $name, $email, $body; public function attributeLabels() { return [ 'name' => 'Ваше имя', 'email' => 'Ваш email', 'body' => 'Сообщение', ]; } public function rules() { return [ // удалить пробелы для полей name и email [['name', 'email'], 'trim'], // поле name обязательно для заполнения ['name', 'required', 'message' => 'Поле «Ваше имя» обязательно для заполнения'], // поле email обязательно для заполнения ['email', 'required', 'message' => 'Поле «Ваш email» обязательно для заполнения'], // поле email должно быть корректным адресом почты ['email', 'email', 'message' => 'Поле «Ваш email» должно быть адресом почты'], // поле body не проверяем ['body', 'safe'], ]; } }
Класс контроллера:
<?php namespace app\controllers; use Yii; use yii\web\Controller; use app\models\FeedbackForm; class PageController extends Controller { public function actionIndex() { return $this->render('index'); } public function actionFeedback() { $model = new FeedbackForm(); // если пришли post-данные, загружаем их в модель... if ($model->load(Yii::$app->request->post())) { // ...и проверяем эти данные if ( ! $model->validate()) { // данные не прошли валидацию, отмечаем этот факт Yii::$app->session->setFlash( 'validate', false ); // сохраняем в сессии введенные пользователем данные Yii::$app->session->setFlash( 'form-data', [ 'name' => $model->name, 'email' => $model->email, 'body' => $model->body ] ); /* * Сохраняем в сессии массив сообщений об ошибках. Массив имеет вид * [ * 'name' => [ * 'Поле «Ваше имя» обязательно для заполнения', * ], * 'email' => [ * 'Поле «Ваш email» обязательно для заполнения', * 'Поле «Ваш email» должно быть адресом почты' * ] * ] */ Yii::$app->session->setFlash( 'form-errors', $model->getErrors() ); } else { // данные прошли валидацию, отмечаем этот факт Yii::$app->session->setFlash( 'validate', true ); } // выполняем редирект, чтобы избежать повторной отправки формы return $this->refresh(); } return $this->render('feedback', ['model' => $model]); } }
Шаблон формы:
<?php /* @var $this yii\web\View */ use yii\widgets\ActiveForm; use yii\helpers\Html; $this->title = 'Обратная связь'; // Если форма не прошла проверку на сервере, мы должны снова показать форму, // заполненную введенными ранее данными, не заставляя вводить их повторно $data = [ 'name' => '', 'email' => '', 'body' => '', ]; ?> <?php if (Yii::$app->session->hasFlash('validate')): /* данные формы были отправлены? */ ?> <?php if ( ! Yii::$app->session->getFlash('validate')): /* форма не прошла валидацию */ ?> <?php // Если данные не прошли валидацию, получаем из сессии сохраненные данные, чтобы // заполнить ими поля формы, не заставляя пользователя заполнять форму повторно if (Yii::$app->session->hasFlash('form-data')) { $data['name'] = Html::encode(Yii::$app->session->getFlash('form-data')['name']); $data['email'] = Html::encode(Yii::$app->session->getFlash('form-data')['email']); $data['body'] = Html::encode(Yii::$app->session->getFlash('form-data')['body']); } ?> <div class="alert alert-warning alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Закрыть"> <span aria-hidden="true">×</span> </button> <p>При заполнении формы допущены ошибки</p> <?php if (Yii::$app->session->hasFlash('form-errors')): /* ошибки */ ?> <?php $allErrors = Yii::$app->session->getFlash('form-errors'); ?> <ul> <?php foreach ($allErrors as $errors): ?> <?php foreach ($errors as $error): ?> <li><?= $error; ?></li> <?php endforeach; ?> <?php endforeach; ?> </ul> <?php endif; ?> </div> <?php else: /* форма прошла валидацию */ ?> <div class="alert alert-success alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Закрыть"> <span aria-hidden="true">×</span> </button> <p>Данные формы прошли валидацию.</p> </div> <?php endif; ?> <?php endif; ?> <div class="site-feedback"> <h1><?= Html::encode($this->title) ?></h1> <?php $form = ActiveForm::begin(['id' => 'feedback-form', 'options' => ['novalidate' => '']]); ?> <?= $form->field($model, 'name')->textInput(['value' => $data['name']]); ?> <?= $form->field($model, 'email')->textInput(['value' => $data['email']]); ?> <?= $form->field($model, 'body')->textarea(['rows' => 5, 'value' => $data['body']]); ?> <?= Html::submitButton('Отправить', ['class' => 'btn btn-primary']); ?> <?php ActiveForm::end(); ?> </div>
Что мы делаем в контроллере:
- Если данные формы были отправлены, вызываем метод
validate()
модели - Записываем в сессию результат проверки данных формы с ключом
validate
- Если форма не прошла проверку, записываем в сессию массив сообщений об ошибках
- Если форма не прошла проверку, записываем в сессию массив значений полей формы
- В любом случае, после POST-запроса делаем редирект
Что мы делаем в шаблоне:
- Если все поля формы прошли валидацию, просто показываем пользователю сообщение об этом
- Если поля формы не прошли валидацию, показываем список ошибок, которые были допущены
- Если поля формы не прошли валидацию, заполняем поля формы введенными ранее данными
- Yii2. Валидация формы. Часть 1
- Laravel. Отправка письма из приложения
- Yii2. Метки полей формы
- Yii2. Отправка данных AJAX
- Блог на Laravel 7, часть 13. Загрузка и ресайз изображений для категорий и постов блога
- Блог на Laravel 7, часть 9. Панель управления — создание, публикация, удаление комментариев
- Блог на Laravel 7, часть 8. Панель управления — CRUD для категорий, тегов и пользователей
Поиск: PHP • POST • Web-разработка • Yii2 • Форма • Form • Framework • Фреймворк • Validate • Валидация