Чат PHP-разработчиков
Формы в Symfony

Формы в Symfony

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

В Symfony каждая форма принадлежит конкретной сущности, что даёт нам удобство её обработки. Формы, как и многое другое во фреймворке, можно создавать через консоль. Название формы должно состоять из названия сущности и слова Type (т.е. PostType, UserType). Форму можно создать с помощью компонента maker следующей командой:

Код доступен только после покупки курса по фреймворку Symfony 4.

Symfony попросит вас ввести имя сущности, с которой связана форма. Введите Post. Дальше у вас сгенерируется папка Form, где вы найдёте класс PostType. Перейдя в него, вы должны увидеть следующий код:

В методе configureOptions() Symfony указывает, какая сущность будет источником данных для нашей формы. На данный момент нас интересует метод buildForm, который, собственно, и строит нашу форму из полей нашей сущности. Мы смело можем удалить поля slug и created_at, поскольку они будут генерироваться автоматически. Кроме того, нам доступны некоторые настройки для нашей формы: так, например, метод в add() мы можем указать, какой тип данных будет принимать то или иное поле - TextType или TextareaType, а также установить label, если он нужен. Вот так будет выглядеть наш метод теперь:

Код доступен только после покупки курса по фреймворку Symfony 4.

Обратите внимание на то, что классы TextType и TextareaType должны быть загружены по следующим неймспейсам:

Код доступен только после покупки курса по фреймворку Symfony 4.

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

Итак, закончив, с созданием формы (да, на этом всё), используем же её для создания первой нашей публикации! Для этого перейдите в класс PostsController.php и создайте метод addPost(). Также не забудьте назначить маршрут нашему методу в аннотации Route и добавить имя.

Для начала нужно понять, где хранятся данные, передаваемые пользователем через форму. Как я уже упоминал в одной из предыдущих статьях, Symfony - HTTP фреймворк, данные он получает из класса Request и отдаёт в виде Response. Поэтому одним из параметров нашего метода будет объект $request, а вторым - знакомый нам класс Slugify. Прежде чем начнём писать наш метод, нам надо зарегистрировать класс Slugify как сервис в файле config/services.yaml. Вот как это будет выглядеть:

Строка autowire: true позволяет переложить на Symfony автоматическую загрузку нашего сервиса.

Кстати говоря, эту запись можно убрать

Код доступен только после покупки курса по фреймворку Symfony 4.

Теперь мы зарегистрировали класс как сервис, а не как аргумент другого класса, в результате чего он стал нам доступен глобально.

Итак, приступим к созданию нашего метода.
Сначала мы создаём объект нашей сущности, которую и будем сохранять.

Код доступен только после покупки курса по фреймворку Symfony 4.

Дальше мы создаём форму с помощью метода createForm, который обязательным параметром принимает наш класс PostType и объект класса Post.

Код доступен только после покупки курса по фреймворку Symfony 4.

Далее мы обрабатываем наш $request с помощью метода handleRequest, который стал нам доступен после создания инстанса формы.

Код доступен только после покупки курса по фреймворку Symfony 4.

Теперь мы проверяем, нажата ли кнопка под формой и является ли она валидной в соответствии с теми правилами валидации, которые мы применили к нашей сущности. Если оба этих условия выполняются, мы устанавливаем slug с помощью уже известного нам метода slugify, куда передаём title статьи. Время для поля created_at берём текущее, которое возвращает нам объект класса DateTime() по умолчанию.

Код доступен только после покупки курса по фреймворку Symfony 4.

Вызываем наш Manager, подготавливаем (persist) и сохраняем пост (flush). После сохранения редиректим пользователя на страницу со всеми постами.

Код доступен только после покупки курса по фреймворку Symfony 4.

А сам метод addPosts() возвращает шаблон, куда в качестве аргумента передаём $form->createView(). Этот метод создаст саму форму в нашей вёрстке.

Код доступен только после покупки курса по фреймворку Symfony 4.

Вот как полностью выглядит наш метод:

Код доступен только после покупки курса по фреймворку Symfony 4.

Теперь создайте шаблон в папке templates/posts под именем new.html.twig. Всё, что он будет делать, это рендерить форму. Вот как будет выглядеть наш шаблон:

Код доступен только после покупки курса по фреймворку Symfony 4.

Twig позволяет по-разному рендерить форму: можно сразу вывести всю форму с помощью такой записи {{ form(form) }}, однако в этом случае будет сложнее управлять каждым полем отдельно - его стилями или названием. Поэтому мы используем теги form_start и form_end, между которыми выводим каждое поле в отдельности. Записи form.title и form.body соответствует реальным полям в нашей таблице и в свойствах нашей сущности. Также мы добавляем rows и cols для form.body (вы же помните, как мы указали, что это TextareaType?), чтобы форма не выглядела маленькой. До тегов form_end вы должны не забыть добавить кнопку. Теперь наша форма и метод-handler, которые её обрабатывает, готовы. Вы можете перейти по указанному адресу и попробовать написать и сохранить первую запись.

Ну что же, на этом уроке мы освоили очередной важный компонент фреймворка - формы. На следующем уроке мы напишем первое CRUD приложение, в результате чего вы научитесь создавать, редактировать и удалять записи.

Курс программирования на PHP
Подготовка до уровня устройства на работу!
Начать бесплатно
Комментарии (10)


valera

"Обратите внимание на то, что классы TextType и TextareaType должны быть загружены по следующим неймспейсам:

use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType; "

а этот неймспейс можно убрать тогда?

use Doctrine\DBAL\Types\TextType;
kafkiansky

Если он нигде не применяется, то да.

valera

Подскажите, пож-ста, почему так получилось, что ext-http отсутствует в composer.json ?

ext-http is missing in composer.json

это Storm ругается на Request

и после добавления ext-http надо php composer update сделать?

а use какой потом добавить? use http\Env\Request; не подойдёт же для Requesta?

kafkiansky

Вы не должны обращать на это внимание. И добавлять в композер не нужно. Это не влияет на работу приложения.

valera

web сервер не стартует, ошибку могу вечером только показать, но там что-то про $request и http\Env\Request;

kafkiansky

Ок, жду ошибку

valera
Cannot determine controller argument for "App\Controller\PostsController::a  
  ddPost()": the $request argument is type-hinted with the non-existent class  
   or interface: "http\Env\Request".
valera

web сервер не стартует

Cannot determine controller argument for "App\Controller\PostsController::a  
  ddPost()": the $request argument is type-hinted with the non-existent class  
   or interface: "http\Env\Request".
kafkiansky

Потому что вы используете не тот Request, надо использовать Request по неймспейсу Symfony\Component\HttpFoundation\Request

valera

так всегда происходит по дефолту? Надо потом вручную namespace менять?

Самый понятный курс PHP
Онлайн-уроки в удобное время!
Начать бесплатно
Популярное за сутки
Онлайн-курсы PHP и MySQL
Обучение с полного нуля до уровня джуниора!
Начать бесплатно
Сейчас читают
Онлайн-курсы PHP и MySQL
Обучение с полного нуля до уровня джуниора!
Начать бесплатно
Новые статьи
Логические задачи с собеседований