Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Формы

Форму в Drupal описывают массивом, а не разметкой. По этому описанию система сама выводит поля, проверяет обязательные значения, защищает от подделки запроса и вызывает ваши методы проверки и обработки. Сделаем форму подписки на новые статьи блога.

Где лежит форма

Каждая форма — отдельный класс в папке src/Form модуля. Создайте папку и файл вручную.

Класс формы

// web/modules/custom/blog/src/Form/SubscribeForm.php
namespace Drupal\blog\Form;
 
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
 
class SubscribeForm extends FormBase
{
    public function getFormId(): string
    {
        return 'blog_subscribe_form';
    }
 
    public function buildForm(array $form, FormStateInterface $form_state): array
    {
        $form['email'] = [
            '#type' => 'email',
            '#title' => $this->t('Почта'),
            '#required' => TRUE,
        ];
 
        $form['actions']['submit'] = [
            '#type' => 'submit',
            '#value' => $this->t('Подписаться'),
        ];
 
        return $form;
    }
 
    public function submitForm(array &$form, FormStateInterface $form_state): void
    {
        $email = $form_state->getValue('email');
 
        $this->messenger()->addStatus($this->t('Адрес @email подписан.', ['@email' => $email]));
    }
}
МетодЧто делает
getFormId()Возвращает уникальное имя формы
buildForm()Описывает поля и кнопки
submitForm()Выполняется после успешной отправки

Поля — те же массивы вывода со свойством #type. Значения отправленной формы хранит объект $form_state.

Маршрут формы

Форме не нужен контроллер: в маршруте вместо _controller указывают _form:

# web/modules/custom/blog/blog.routing.yml
blog.subscribe:
  path: '/blog/subscribe'
  defaults:
    _form: '\Drupal\blog\Form\SubscribeForm'
    _title: 'Подписка'
  requirements:
    _permission: 'access content'

После drush cr откройте /blog/subscribe: появится поле и кнопка. Пустую форму браузер не отправит, а после отправки с адресом вверху страницы появится зелёное сообщение.

Проверка

Свои правила проверки пишут в методе validateForm():

// web/modules/custom/blog/src/Form/SubscribeForm.php
public function validateForm(array &$form, FormStateInterface $form_state): void
{
    if (str_ends_with($form_state->getValue('email'), '@example.com')) {
        $form_state->setErrorByName('email', $this->t('Укажите настоящий адрес.'));
    }
}

setErrorByName() отмечает поле с ошибкой: форма вернётся к посетителю с красным сообщением, а submitForm() не выполнится. Формат адреса и обязательность Drupal проверил сам — по #type и #required.

Элементы формы

ТипПоле
textfieldСтрока
textareaМногострочный текст
email, tel, url, numberПоля с проверкой формата
selectСписок: варианты в #options
checkbox, checkboxes, radiosФлажки и переключатели
dateДата
submitКнопка отправки

Общие свойства: #title, #description, #default_value, #required.

После отправки

// web/modules/custom/blog/src/Form/SubscribeForm.php
$this->messenger()->addStatus($this->t('Готово.'));
$this->messenger()->addError($this->t('Не удалось сохранить.'));
 
$form_state->setRedirect('blog.list');

Сообщение показывается один раз — на следующей странице. setRedirect() отправляет посетителя на маршрут по имени; без него он останется на странице формы. Сохранять адрес в базу форма начнёт в уроке о базе данных.

Форма внутри страницы

Форму можно вывести как часть массива вывода в контроллере:

// web/modules/custom/blog/src/Controller/BlogController.php
$build['subscribe'] = $this->formBuilder()->getForm(\Drupal\blog\Form\SubscribeForm::class);

Частая ошибка

Данные нельзя читать из $_POST: там значения до проверки и без защиты от подделки. Используйте $form_state->getValue('email') — в нём только поля, описанные в форме и прошедшие проверку. И не выводите форму обычными тегами HTML: без Form API у неё не будет токена защиты.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.