Многостраничные формы в Drupal 9 пошаговое руководство

Как сделать многостраничность в drupal 9

Как сделать многостраничность в drupal 9

Многостраничные формы в Drupal 9 применяются там, где необходимо разбить ввод данных на логические шаги: например, при регистрации с расширенными профилями, заполнении заявок или сложных анкет. Такой подход снижает вероятность ошибок пользователей и делает процесс ввода информации более управляемым.

В Drupal 9 создание пошаговой формы обычно реализуется через Form API с использованием механизма form state и сохранения данных между шагами. Для этого важно корректно определить структуру формы, настроить переходы и предусмотреть обработку частично введённой информации. Ошибки на этапе проектирования ведут к потере данных, поэтому необходимо заранее продумать логику сохранения и валидации на каждом шаге.

В этом руководстве будут рассмотрены ключевые моменты: определение классов форм, управление состоянием между шагами, настройка маршрутов и использование сервисов Drupal для обработки промежуточных данных. Такой подход позволит создавать формы, которые масштабируются и легко адаптируются под задачи проекта.

Создание кастомного модуля для многостраничной формы

Создание кастомного модуля для многостраничной формы

Для реализации многостраничной формы в Drupal 9 создаётся отдельный модуль. Структура минимальна: папка модуля, файл .info.yml, файл .routing.yml и класс формы в src/Form.

Пример файла multistep_form.info.yml:

name: 'Multistep Form'
type: module
description: 'Модуль для демонстрации многостраничной формы'
core_version_requirement: ^9
package: Custom

В multistep_form.routing.yml описывается маршрут:

multistep_form.start:
path: '/multistep-form'
defaults:
_form: '\Drupal\multistep_form\Form\MultistepForm'
_title: 'Многостраничная форма'
requirements:
_permission: 'access content'

Класс формы создаётся в src/Form/MultistepForm.php и расширяет FormBase. В нём определяются методы getFormId(), buildForm(), validateForm(), submitForm(). Для перехода между шагами используется сохранение состояния в $form_state:

$step = $form_state->get('step');
if (!$step) {
$form_state->set('step', 1);
$step = 1;
}

Каждый шаг строится условно внутри buildForm(). После сабмита кнопкой «Далее» выполняется $form_state->set(‘step’, $step + 1), при «Назад» – $form_state->set(‘step’, $step — 1). Для предотвращения потери данных используется $form_state->setStorage() и getStorage().

После прохождения последнего шага в submitForm() можно сохранить собранные данные в базу с помощью \Drupal::database() или отправить их через сервис.

Определение маршрутов и подключение контроллеров

Определение маршрутов и подключение контроллеров

Маршруты в Drupal 9 описываются в файле модуль.routing.yml. Каждый маршрут связывает URL с контроллером или формой. Для многостраничной формы важно явно задать уникальные пути для каждого шага и указать соответствующие методы контроллера.

Пример структуры маршрутов для пошаговой формы:

Маршрут Путь Контроллер/Форма Метод
example.form.step1 /example/step1 \Drupal\example\Controller\WizardController stepOne
example.form.step2 /example/step2 \Drupal\example\Controller\WizardController stepTwo
example.form.complete /example/complete \Drupal\example\Controller\WizardController complete

Минимальное определение маршрута в example.routing.yml:

example.form.step1:
path: '/example/step1'
defaults:
_controller: '\Drupal\example\Controller\WizardController::stepOne'
_title: 'Шаг 1'
requirements:
_permission: 'access content'

Контроллер создаётся в src/Controller/WizardController.php. Каждый метод возвращает рендер-массив формы через \Drupal::formBuilder():

namespace Drupal\example\Controller;
use Drupal\Core\Controller\ControllerBase;
class WizardController extends ControllerBase {
public function stepOne() {
return \Drupal::formBuilder()->getForm('Drupal\example\Form\StepOneForm');
}
public function stepTwo() {
return \Drupal::formBuilder()->getForm('Drupal\example\Form\StepTwoForm');
}
public function complete() {
return [
'#markup' => $this->t('Форма завершена'),
];
}
}

Ключевые моменты:

  • Каждый шаг оформляется отдельным маршрутом и методом контроллера.
  • Названия маршрутов должны быть уникальными и использовать префикс модуля.
  • Разделение маршрутов упрощает навигацию между шагами и обработку состояния формы.

Реализация логики пошаговой навигации

Реализация логики пошаговой навигации

Для организации переходов между шагами используется метод buildForm(), где каждая стадия формы определяется отдельной веткой условий. Текущий шаг фиксируется в состоянии формы с помощью $form_state->get(‘step’). При первом вызове следует инициализировать это значение в 1, чтобы обеспечить корректное начало процесса.

Кнопки навигации создаются с помощью #type => ‘submit’ и должны иметь разные #submit-колбэки. Кнопка «Далее» увеличивает шаг через $form_state->set(‘step’, $step + 1), а кнопка «Назад» – уменьшает. После изменения шага используется $form_state->setRebuild(TRUE) для перерисовки формы с новым набором элементов.

При переходе вперёд важно сохранять введённые данные: для этого применяется $form_state->setTemporaryValue() или $form_state->setStorage(). При возврате на предыдущий экран эти значения подставляются в поля с помощью #default_value, что исключает потерю данных.

Завершающий шаг обрабатывается отдельным submit-методом, где данные объединяются и передаются в бизнес-логику (например, сохранение в сущность или отправка на почту). Проверку корректности лучше выполнять в validateForm(), различая правила по текущему шагу, чтобы исключить валидацию полей, которые ещё не были показаны пользователю.

Таким образом, минимальный набор логики включает: хранение номера шага в FormState, обработчики кнопок для инкрементации/декрементации, обязательный вызов setRebuild() и механизм сохранения временных данных. Эта структура делает процесс предсказуемым и легко расширяемым.

Сохранение и передача данных между шагами

Сохранение и передача данных между шагами

В многостраничных формах Drupal 9 критически важно сохранять состояние между шагами, чтобы пользователь не терял введённые данные при переходах. Для этого удобно использовать сервис \Drupal::service('tempstore.private'). Он хранит данные в сессии и доступен только текущему пользователю.

Пример сохранения данных на первом шаге:


$store = \Drupal::service('tempstore.private')->get('my_form');
$store->set('step1_data', $form_state->getValue('field_name'));

Получение данных на следующем шаге:


$store = \Drupal::service('tempstore.private')->get('my_form');
$step1_data = $store->get('step1_data');

Хранить массив значений предпочтительнее, чем отдельные ключи: это упрощает обработку и снижает количество обращений к хранилищу. Используйте $store->set('form_data', $form_state->getValues()); и при необходимости объединяйте данные каждого шага.

Не рекомендуется использовать $_SESSION напрямую – это усложняет тестирование и противоречит архитектуре Drupal. TempStore очищается автоматически при завершении сессии, что снижает риск накопления «мусора».

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

Добавление проверки и валидации на каждом шаге

В многошаговых формах Drupal 9 каждая страница должна иметь собственную логику проверки, чтобы предотвратить переход к следующему шагу при ошибках. Для этого используется метод validateForm() внутри класса формы, а также возможность определения уникальных валидаторов для каждого шага.

  • В buildForm() храните текущий шаг в $form_state->get('page_num'). Это позволит различать логику валидации.
  • В validateForm() используйте switch или if для проверки конкретных полей текущего шага.
  • Для обязательных полей используйте $form_state->setErrorByName(), передавая имя элемента и сообщение об ошибке.
  • При сложной логике выносите правила в отдельные методы, чтобы код оставался читаемым.

Пример минимальной проверки для второго шага:


public function validateForm(array &$form, FormStateInterface $form_state) {
$step = $form_state->get('page_num');
if ($step === 2) {
$email = $form_state->getValue('user_email');
if (!\Drupal::service('email.validator')->isValid($email)) {
$form_state->setErrorByName('user_email', $this->t('Введите корректный email.'));
}
}
}

Рекомендации:

  1. Не копите ошибки на финальном шаге – проверяйте поля сразу после ввода.
  2. Используйте встроенные валидаторы Drupal, например EmailValidator или UrlHelper.
  3. Для зависимости полей добавляйте условные проверки: например, если выбран определённый тип, проверять связанные поля.
  4. Храните промежуточные результаты в $form_state->set(), чтобы не потерять данные при возврате к предыдущим шагам.

После прохождения всех шагов многостраничной формы необходимо собрать данные из каждого шага в единый массив. Используйте сервис `\Drupal::request()->getSession()` для хранения промежуточных значений, чтобы избежать потери данных при переходе между страницами.

Для окончательной обработки данных создайте метод `submitForm()` в основном классе формы. В этом методе объедините массивы с данными из всех страниц, примените необходимые проверки валидности и очистку, например с помощью `\Drupal\Component\Utility\Xss::filter()` для текстовых полей.

Если требуется экспорт данных, можно интегрировать генерацию CSV или PDF на финальном шаге, используя соответствующие модули, например `drupal/csv_serialization` или `mpdf/mpdf`. Перед генерацией убедитесь, что все обязательные поля заполнены, чтобы избежать ошибок при формировании файла.

Вопрос-ответ:

Как создать многостраничную форму в Drupal 9 без использования сторонних модулей?

В Drupal 9 можно создавать многостраничные формы с помощью стандартного API Form API. Для этого нужно определить форму как класс, реализующий интерфейс FormInterface или наследующийся от FormBase, а затем использовать методы buildForm() для добавления полей и submitForm() для обработки данных. Чтобы разделить форму на несколько страниц, применяют метод #states или создают отдельные формы для каждой страницы и управляют переходом через состояние пользователя с помощью сессий или temporary storage (TempStore). Такой подход позволяет сохранять введённые данные между шагами без сторонних модулей.

Какие подходы к хранению данных между шагами формы рекомендуются в Drupal 9?

Существует несколько способов хранения данных между шагами многостраничной формы. Один из них — использование TempStore API, который предоставляет временное хранилище для текущего пользователя. Другой способ — сессии PHP, однако их стоит использовать аккуратно, чтобы не перегружать сессию лишними данными. Для сложных форм с большим количеством полей можно сохранять промежуточные данные в пользовательских сущностях или в отдельной таблице базы данных, что позволяет более гибко работать с логикой перехода между шагами.

Как добавить проверку данных на каждом шаге формы?

В Form API проверка данных выполняется через метод validateForm(). Для многостраничной формы можно проверять только поля текущего шага, чтобы пользователь получал ошибки только за введённые значения. Если используется TempStore для хранения промежуточных данных, можно также проверять ранее введённые значения и корректировать их по необходимости. Для сложных зависимостей между полями удобно использовать условия #states, чтобы включать или отключать обязательность полей в зависимости от предыдущих ответов.

Как реализовать возврат к предыдущему шагу и корректировку данных?

Для поддержки возврата к предыдущему шагу нужно сохранять все введённые данные в TempStore или другой промежуточной структуре. При переходе назад форма должна заполняться значениями, которые пользователь уже ввёл. В submitForm() необходимо различать действия «далее» и «назад», чтобы обновлять состояние формы корректно. Это позволяет пользователю редактировать введённые значения, не теряя уже заполненные поля, и обеспечивает более гибкое взаимодействие с многостраничной формой.

Можно ли подключать динамические поля на последующих шагах формы?

Да, Drupal 9 поддерживает динамическое добавление полей. На следующих шагах формы можно создавать поля в зависимости от выбора пользователя на предыдущих шагах. Для этого используется логика в buildForm(), где проверяются значения из TempStore или сессии, и на их основе формируются новые элементы формы. Важно также обеспечить правильную проверку и сохранение этих динамических данных, чтобы они корректно передавались между шагами и не терялись при возврате на предыдущие страницы.

Ссылка на основную публикацию