Формы в Symfony


Оглавление (нажмите, чтобы открыть):

symfony4 Form — Форма с вложенной коллекцией форм. Создание, сохранение. Вложенные сущности, «документы», иерархия

Primary tabs

Forums:

В Symfony существует компонент Forms, предназначенный для создания форм, основанных на сущностях (Entity). Если корректно написать класс формы, то можно максимально упростить рендеринг, сохранение и автозаполнение формы. Но чем сложнее поставленная задача, тем более неоднозначно решение.

Здесь, например, можно посмотреть, как сохранять non-mapped поля при автоматическом сохранении формы.

Задача

В данной статье мы рассмотрим, как АВТОМАТИЧЕСКИ (не каждое поле отдельно, а сущность целиком) вывести форму для создания сущности (Entity), а также вложенной в неё коллекции (ArrayCollection), и сохранить её.

Решение

Итак, у нас есть 2 связанные сущности: Product и ProductField. Связаны они Один-ко-Многим.

    Часть сущностей (нас интересуют в основном поля связи). Для синхронного сохранения вложенной сущности, добавим полю productFields сущности Product опцию cascade=<"persist", "remove">:

И для сохранения внешнего ключа в таблице product_field, добавим установку связи с продуктом (обратная связь: ProductField->setProduct) при создании связи Product->addProductField.
Внимание! Это обязательно, иначе ProductField добавится в коллекцию, но не будет установлен внешний ключ в таблице БД!

  • В контроллере будет всего лишь:
  • Формы сущностей. Чтобы Symfony понимал, в какую сущность сохранять данные, добавляем метод configureOptions(). Чтобы поля для вложенной сущности подгружались в форму, добавляем атрибуты CollectionType-поля: by_reference, prototype, allow_add и allow_delete. Взято из оф. документации Симфони:
  • В шаблоне. Выводим вложенные сущности в виде списка, а также добавляем атрибуты для подгрузки неограниченного количества пунктов списка:
  • js-код для подгрузки неограниченного количества вложенных форм (не забудьте подключить его в своём шаблоне):
  • Чтобы сделать из формы создания форму редактирования, просто передайте вторым аргументом в метод createForm() не пустой объект сущности, а тот, который надо изменить.

    Вот и всё) Спасибо всем, кто писал хоть что-то на просторах интернета на эту тему) Без вас было бы слишком тяжело использовать «лёгкий» способ сохранения сущностей в Symfony :))

    Вопросы с тегом ‘symfony-forms’

    Количество результатов: 361

    Привет Я использую Symfony Date-Type с виджетом single_text. Это мой код. use Symfony\Component\Form\Extension\Core\Type\DateType; // . $builder->add(‘date_crea.

    С Symfony 4.2, у меня есть сущность с утверждают: . /** * @var string * * @Assert\NotBlank() * @Assert\Email() */ private $email; . У меня есть форма для л.

    Потребовалось мне так долго, чтобы получить титул право, и я гавань написал вопрос еще: / Поехали: Мое меню загружается из сущностей. Для того, чтобы позволить пользо.

    Я использую KnpLabs/Doctrine2Behaviors переводимого модуль для управления интернационализацией внутри моего Symfony2 проекта. Я также использую JMS/i18n-маршрутизации.

    В моем приложении Symfony 4, у меня есть объект, который включает в себя поле типа Дата. По умолчанию, Symfony представляет это как набор отдельных ящиков за месяц, де.

    Как обрабатывать следующие структуры данных через Symfony формы? Субъект, который проводит сбор субъекта, который имеет отношение к себе: Order /** @var OrderPro.

    Есть некоторый вопрос о передаче пользовательских переменных пользовательской FormType У меня есть пользовательский FormType имени KontoType: Я прохожу некоторые пол.

    Вот моя форма: < $builder ->add(‘price’, ChoiceType::class, [ ‘label’ => false, ‘required’ => false, ‘choices.

    У меня есть форма, которая включает в себя поле типа коллекции, в поле типа коллекции есть еще одна коллекция полого типа. Я должен добавить вложенные поля формы в вет.

    Может кто-то объяснить, почему я получаю эту ошибку? Я использую CollectionType в первый раз. Используемый документация. Вот моя часть, где я пытаюсь использовать Coll.

    У меня есть два связанных сущностей в моем симфони проекте — которые хранятся с использованием доктрины. Один объект является «Рекламодатель», который имеет идентифика.

    Я нашел ответ на аналогичную проблему, чем у меня, но я не понимаю, как это работает, и что я должен изменить в своем коде. Поэтому я прошу вас о помощи, у меня есть с.

    Я использую гибрид Symfony форм только покориться и отменяют кнопки, где любой пользовательский ввод данных, посланных с помощью HTML. Вот мой контроллер код, который.

    Я следую шаги, описанные в этой документации https://symfony.com/doc/current/controller/upload_file.html чтобы файл, который будет загружен. Он прекрасно работает для .

    Я пытаюсь представить массив со значениями в поле формы Symfony 4, но проверка держит неудачу. Я нахожусь в процессе обновления моего приложения из симфони 2.7 до Sym.

    У меня есть Symfony 4 объекта, который включает в себя логическое свойство для «удалено». В моем хранилище, я только возвращение лиц, которые не помечены как удаленные.

    У меня есть форма, которая требует только маркер CSRF. Другие параметры обеспечиваются из самого URL, или значение по умолчанию. /** * @Route(«/projets/projet-

    у меня есть совокупность форм как в приведенном ниже коде, что приводит к форме, которая выглядит следующим образом (с два примера записей): При нажатии представить.

    Я прошел через документацию, но не ясно, что, как мы можем создать следующее поле ввода с помощью Symfony formtype. 0 голосов

    Мне нужна помощь, пожалуйста, с моим приложением в Symfony 4. Я пытаюсь изменить пользователь, но мне не нужно, чтобы изменить пароль. Это мой код: $form = $this.

    начинающий я Вью Js и только начали Vue Js с Symfony 4 и я возникли проблемы с формой визуализации в Vue.js. App.js import Vue from ‘vue’ import App from ‘./Compone.

    Я пытаюсь создать форму, которая будет включать в себя поля из другого. У меня есть объект клиента и адреса лица. Когда администратор создает Клиента он должен быть в .

    Я пытаюсь создать форму, чтобы создавать новые «исследования», каждый из которых состоит из «заголовка» и набор «вариантов», варианты отдельных лиц, а также связаны с .

    Я учусь на Symfony 4, и я хотел бы, чтобы сделать свои категории и мою подлодку-категорию, как дерево с флажками (и подводными лодки — сабвуфер категория) в форме (для.

    Я пытаюсь создать именованный вид (строитель) в моем контроллере, как . $form = $this->createNamedBuilder(‘form1’, $data) ->add(. ) ->getForm(); Но я по.

    Я использую CollectionType рендеринг нескольких экземпляров класса в моей форме. Но после того, как поля ввода визуализируется есть лишняя информация оказаны. Просто .

    Я хотел бы знать, как я могу положить больше чем одну форму в одном контроллере? Я сделал это, видит код ниже, в моем контроллере, который содержит 2 формы; 1 добавить.

    Я работал через несколько форм-учебники на Symfony-страницы (особенно Как встроить Коллекцию форм, Как использовать форму без DATACLASS & CollectionType поле ). Я пыт.

    Я хотел бы запустить фоновое задание на Symfony 4, на основе настройки формы. Это позволило бы избежать, что пользователь должен оставаться в форме, пока задача не буд.

    Я работаю на 4 формы Symfony со встроенными типами для REST API. Форма: class OffertaType extends AbstractType < public function buildForm(FormBuilderInterface $b.

    Я следовал Symfony 4.2 документации, но, кажется, форма не будет представлен. Я провел все свое воскресенье, но мне кажется, секрет, как это работает, в журналах я .

    Я строй сайта, который должен иметь общественные формы, где поля не являются статикой, и на основе результата формы в бэк-офисе. Таким образом, единственная цель формы.

    У меня есть две сущности: продукт и изображение. У сущности Product есть поле featuredImg, связанное с сущностью Image с отношением OneToOne. Я не могу обновить featur.

    У меня вопрос о событиях формы Symfony, у меня есть 2 объекта: Пользователь и Адрес, Пользователь может иметь mainAddress и subAddress, он также может использовать оди.

    Я делаю приложение для библиотеки, вы можете установить образ книги, и моя форма будет выглядеть так: Изображение желтого разногласия является действительным изобра.

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

    Я получаю это сообщение об ошибке: Ожидаемый аргумент типа «App \ Entity \ Artist or null», «строка», заданный в пути свойства «artist». Это код моей формы в Symfony .

    Я работаю над проектом, чтобы пользователи могли найти музыкальные концерты, основанные на дате начала, дате окончания, артисте и городе. Когда я отправляю форму поис.

    Я получаю это сообщение об ошибке: Ожидаемый аргумент типа «App \ Entity \ Artist or null», «строка», заданный в пути свойства «artist». Это код моей формы в Symfony .

    У меня странные ошибки. Я реализовал компонент формы в моей системе. Там я создал FormType, где я использую EntityType для поля. Каждый раз, когда я хочу создать форму.

    Если я получаю данные JSON в запросе (например типа интерфейс API), в чем Symfony рекомендуемого способом заполнения объекта. Мне кажется, варианты: Используйте комп.

    Я работаю в форме Symfony с загрузкой файлов. Однако, когда я загрузить файл меньшего размера он работает правильно, но с большим файлом сказать, файл 8Мб дает следующ.

    Коллекция форм Symfony


    В Symfony у меня есть две сущности: Вопрос и Ответ. Они имеют отношение один ко многим, где один вопрос может иметь много ответов. Используя эти объекты, я пытаюсь создать форму с текстовыми полями, где пользователь может редактировать данные из этих объектов. Читая документацию поваренной книги Symfony, я понимаю, что мне нужно использовать набор форм для отображения нескольких ответов на вопрос. Для того, что я понимаю, форма вопроса будет генерировать данные вопроса, и это также будет включать форму ответа, которая будет иметь все ответы. На данный момент я застрял с этой ошибкой:

    Не удалось загрузить тип «QuizBundle \ Entity \ Answer

    Может кто-нибудь помочь мне решить это и построить форму с вопросом и ответами? Спасибо

    Вот мой объект ответа:

    пытаясь получить вопрос из БД и ответы

    Решение

    У вас есть ошибка в вашем классе формы здесь:

    Это тип поля за каждый предмет в этой коллекции (например TextType, ChoiceType и т. Д.). (…)

    Вы указали имя класса объекта ( Answer::class ) пока должно быть какое-то FormType имя класса (например, AnswerType. class ).

    symfony-forms Как работать с параметрами формы

    пример

    В этом примере я создал форму, которая используется для регистрации нового пользователя. В параметрах, переданных форме, я предоставляю разные роли, которые пользователь может иметь.

    Создание класса повторного использования для моей формы с настроенным классом данных и дополнительной опцией, которая заполняет поле выбора, чтобы выбрать userrole:

    Как вы можете видеть, в форму с именем «roleChoises» добавлена ​​опция по умолчанию. Эта опция создается и передается в методе для создания объекта формы. См. Следующий код.

    Много форм с Symfony3

    Пишу приложение в котором есть таблица. Нужно ее редактировать при помощи ajax. В каждом ряде таблицы находятся формы, чтобы можно было их отправлять на сервер. С помощью html форм все получается, но наверно лучше было бы использовать именно формы Symfony. Пытался реализовать формы симфони, но так и не понял как передать туда переменные. Так вот, как реализовать вывод многих симфони форм с разными параметрами? Таблица сейчас выводится вот так:

    1 ответ 1

    Вам необходимо использовать коллекции форм, почитать о них можно в документации.

    Реализовать можно примерно так:

    • создаём класс-контейнер для коллекции классов Garden:
    • создаём форму для Garden:
    • создаём форму для Gardens:

    Передача пользовательских параметров в форму symfony2

    в symfony 1.4 можно было параметризовать определение класса формы с помощью параметров формы. Есть ли способ передать пользовательские параметры в мой пользовательский тип формы. я попытался использовать параметр options buildForm метод, но я не очень уверен, что это за массив, и, по-видимому, это не то, что я хочу. Спасибо!

    6 ответов

    решение простое, если вы хотите, чтобы ваш пользовательский параметр был доступен также в шаблоне Twig, вы должны использовать $builder->setAttribute() на buildForm способ и $view->set() метод buildView() метод, слишком.

    шаблон для пользовательского типа форма (файл . Acme / DemoBundle / ресурсы/представления/форма / поля.формат html.веточка):

    зарегистрируйте шаблон для пользовательских типов форм в app/config / config.в формате YML

    использование: предварительный просмотр изображения пользователя при редактировании его профиль:

    2014-08-18: обновлено для Symfony 2.1 или выше

    обновление: обратите внимание, что это решение работает только в Symfony 2.0.x, который устарел, используйте setDefaultOptions вместо getDefaultOptions .

    справедливо, типы форм Symfony 2 принимают параметры, которые вы можете использовать для всего, что хотите внутри типа формы. Вам нужно переопределить getDefaultOptions метод для указания параметров типа.

    например, у меня есть типа MyCustomType принимают my_option этот параметр имеет значение по умолчанию false реализация MyCustomType может быть что-то вроде этого.

    позже вам нужно будет указать опцию при создании формы в контроллере, используя третий параметр buildForm :

    если вы не указать , оно принимает значение по умолчанию ( false ).

    используя symfony 2.8, мне удалось использовать предлагаемое решение, расширяющее configureOptions() метод.

    мне нужно использовать ElementType , как собрание и врезанная форма. Я понял, что пройти мимо my_custom_option_parameter до CollectionType , потому что я не подгоняйте configureOptions() of CollectionType , но моей ElementType . Если вам нужно передать my_custom_option_parameter через CollectionType , вы можете добиться успеха, определив my_custom_option_parameter на entry_options (см. документацию CollectionType Поле) для проживания CollectionType .

    пример прохождения my_custom_option_parameter через CollectionType :

    Я пробовал использовать эти параметры array без успеха, поскольку казалось, что он может нести только небольшое предопределенное подмножество ключей. Для меня это было неприемлемо.

    тем не менее, вы можете передать все параметры через формы __construct метод и сохраните его в свойствах класса для последующего использования. Затем из buildForm вы можете получить доступ к нему с помощью $this->»propertyName» .

    это до вас, чтобы решить, хотите ли вы пройти один array или только несколько переменных для __construct .

    это просто примерный пример:

    используя Symfony 3, я смог передать пользовательские параметры в форму, установив параметр по умолчанию в OptionsResolver, введенный в метод configureOptions моего класса типа формы:

    таким образом, похоже, вы можете определить контракт с вашей формой и поставщиком данных для установки произвольных данных в форме.

    Я только что успешно осуществили эту процедуру. Обратите внимание, что на обратный путь, так как вы установили ‘mapped’ => false, в formBuilder, $form->getData() не вернуться. Чтобы получить выбранное значение:

    в ваш контроллер. Почему это за меня . . .

    на основе ответа @pulzarraider я создал код с изменениями для Symfony 3.

    вам нужно изменить

    OptionsResolverInterface на OptionsResolver

    Космонавт в лодке

    Личный блог Олега Абражаева о программировании, технологиях и о жизни

    Рубрики

    • HTML и CSS (7)
    • Java (2)
    • JavaScript (5)
    • Linux (45)
      • Debian (4)
      • Ubuntu (24)
    • MySQL (10)
    • PHP (49)
      • Doctrine (7)
      • Kohana Framework (7)
      • Symfony Framework 2 (3)
      • WordPress CMS (4)
      • Zend Framework 2 (8)

    • Ruby (2)
      • Redmine (2)
    • seo шмео (6)
    • Просто мысли (110)

    Облако меток

    Свежие комментарии

    • PHP: include или все в один файл? — include php быстродействие — Вопросы и ответы по программированию к записи Сравнение производительности автозагрузки и объединения классов в один файл
    • Новичёк к записи Satis: создание вашего собственного Composer репозитория
    • Самарка к записи Что делать с ошибкой W: Possible missing firmware /lib/firmware/rtl_nic/rtl8105e-1.fw for module r8169
    • Saskozp к записи Фикс Bootstrap 3 Navigation dropdown submenu и реализация в Zend Framework 2 и Smarty
    • seoonly.ru к записи Список полезных команд для Linux (Ubuntu, Debian) – ОБНОВЛЯЕМЫЙ

    livelib.ru

    Подписаться на обновления!

    Избегание сущностей в формах Symfony и переосмысление разработки форм Symfony

    Будучи активным в IRC, почти каждый день автор этой статьи видит поступающие вопросы про использование форм Symfony и сущностей в них. Это не только создает проблемы, но так же рискованно. Вы же не хотите сохранить сущность в невалидном состоянии!

    Как и в прошлый раз, мне просто захотелось перевести еще пару статей в вольном стиле. И так как тут вторая статья является продолжением первой, я решил уместить их в один пост. Вот ссылка на оригинал первой: https://stovepipe.systems/post/avoiding-entities-in-forms

    Избегание сущностей в формах Symfony

    “Но испрользовать сущности в моих формах просто!”. Да, это просто. Вам не нужно писать никакого дополнительно кода, чтобы соединить ваши правила валидации и маппинга данных, не говоря уже о том, что вам нужно только выполнить flush() и готово. Применять этот метод особенно легко при реализации CRUD и можно выполнять разработку приложений быстрее, удовлетворяя RAD подход.

    В чем же тогда проблема?

    С чего же мне начать?

    • Сущности всегда должны быть в валидном состоянии
    • Сущностям нужна дополнительная угадывающая логика при заполнении значениями по умолчанию
    • Сущности ограничивают структуру данных и переиспользование ваших типов форм

    Что имеется в виду под валидным состоянием?

    Это означает, что в тот момент, когда форма создана – она должна соблюдать вашу бизнес логику. Если для аутентификации требуется логин пользователя, он всегда должен присутствовать и это значит, что вам надо добавить параметр в конструктор. Это обычно не единственное правило, другое правило может быть, что логин пользователя должен быть как минимум 5 символов в длину.

    Делая так, вы предотвращаете невалидное состояние формы авторизации, но компонент форм в Symfony “не любит” это. Внутренне компонент форм пытается вызвать setUsername() на указанном маппинге в форме.

    Теперь юзер хочет изменить свое имя и пишет Foo и это вызовет исключение в момент, когда будет попытка вызвать setUsername(‘Foo’). Это ясно означает, что вы не можете быть уверенны в валидном состоянии сущности, т.к. вам придется удалить код с Exception чтобы использовать объект Authentication как объект данных.
    Если же вы уберете исключение и позволите сущности быть в невалидном состоянии, любой вызов flush() сохранит эту сущность в БД в таком виде.

    Что имеется в виду под дополнительной угадывающей логикой?

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

    Что имеется в виду под ограничением структуры данных и переиспользования?

    Когда ваша сущность является так же объектом данных, вы ограничены структурой вашей сущности при маппинге типа формы. Это значит, что если вы хотите выделить часть, которая совместно используется между формами, вы не можете просто переиспользовать подтипы, т.к. это будет требовать изменения структуры данных. Другим решением будет добавление временных свойств в сущность, которые будут использоваться только в форме. И это нарушит принцип Single Responsibility (прим. одна ответственность, S в SOLID).

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

    Как можно добавить newUsername в вашу сущность? Если нету такого свойства, то вот так

    Архитектура форм в Symfony2

    В Symfony 2 появился совершенно новый компонент для работы с формами, который, насколько я знаю, легко заменит большинство подобных библиотек для PHP и по функционалу, и по возможности в расширении оного (конечно, если не брать в расчет небольшие недостатки при работе с JavaScript). Разработка этого компонента заняла более двух лет, хотя думать над ним я начал еще где-то в 2009-ом году или даже раньше. С каждой новой версией этот компонент становится все более и более стабильным, а полностью стабильная версия ожидается с выходом Symfony 2.2.

    Данный пост приурочен к выходу Zend Framework 2 Form RFC, так как мне кажется, что его разработчики, по сути, сделали много того, что уже было сделано нами. Конечно же всем ясно, что Zend Framework 2 должен обладать прослойкой для работы с формами, который полностью учитывает особенности компонентов, поставляемых с фреймворком. Целью данного поста является попытка показать, что Symfony2 Forms прекрасно подходит под эти требования. Функционал, присущий Symfony2, может быть легко убран: код для обработки форм и все уровни абстракций полностью независимы. Привязать же поддержку особенностей компонентов Zend-а так же не составит труда.

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

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

    В этом посте вы не найдете примеров использования «киллер-фич» данного компонента, для этого есть документация. Так же вы не найдете тут и информации по использованию его, так скажем, вне контекста, независимо от фреймворка. Подобная информация должна быть описана, к примеру, в Gist.

    Влияние

    На компонент форм повлияло множество фреймворков, написанных на разных языках, включая symfony 1, Zend Framework 1, Django, Ruby on Rails, Struts и JSF. Кроме того, в нем можно найти сходства с Formlets, WUI и iData, библиотеками для работы с формами, написанными для функциональных языков программирования, таких как Links, Curry и Clean.

    Ключевые аспекты

    Ключевыми аспектами при проектировании компонента для работы с формами являются:

    • Повышенный уровень абстракции
    • Расширяемость
    • Композиционность
    • Разделение задач
    • Привязка моделей
    • Динамические поведения

    Коротко пройдемся по каждому из этих аспектов, прежде чем обсуждать, каким образом реализованная архитектура их покрывает.

    Повышенный уровень абстракции

    Повышение уровня абстракции позволяет взять любую часть формы — даже форму целиком — и поместить ее в структуру данных, которую затем вы сможете использовать вновь. Рассмотрим форму для выбора даты, в которой имеются три выпадающих списка для выбора по дню, месяцу и году. Для начала вам нужен код, который сформирует HTML со всеми опциями выпадающих списков. Затем, вам понадобится код, который преобразует данные из формата вашего приложения (к примеру объект DateTime, если мы говорим о PHP) в формат, подходящий для нашего представления (для того что бы отметить выбранное значение у списков). Конечно понадобится и обратная процедура. А теперь представим ситуацию, когда вам придется добавить еще один выпадающий список для каких-то дополнительных данных. В этом случае вам придется продублировать весь код для этого списка и адаптировать его под новые требования.

    Введение абстракции решает эту проблему, предоставляя подходящие структуры для описания и повторного использования вашего кода.

    Расширяемость

    Расширяемость основывается на двух концепциях, относящихся к абстракции:

    1. Специализация, это логическая последовательность абстракций. Если есть возможность абстрагировать функционал в обобщенные структуры данных, то их можно так же и расширить в более специализированные структуры. Например, мы можем расширить приведенный выше пример с выбором даты, добавив поля для выбора времени. Если бы возможности расширить функционал существующего поля для выбора даты не было, то нам пришлось бы переписывать существенную часть функционала.
    2. Примеси являются противоположностью специализации. К примеру вы захотели изменить все существующие поле так, что бы в их описаниях была звездочка («*»), которая бы показывала то, что эти поля обязательны к заполнению. Использовать для этого подход со специализацией несколько непрактично, так как вам придется расширить все имеющиеся поля, реализуя тот же функционал. Примеси же позволяют подключать функционал к существующим объектам без необходимости переопределять их. К тому же, добавленный таким способом функционал будет наследоваться для всех дочерних объектов в древе наследования.

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

    Компоновщик

    Если мы проанализируем последний пример, мы можем заметить, что особой разницы между полями (составными полями, такими как в рассмотренном примере, или примитивными, такими как текстовое поле ввода) и формами нету. И поля и формы

    1. Принимают значения по умолчанию из моделей (из массивов, из дат, из строк. )
    2. Преобразуют значения, что бы его можно было использовать в представлении
    3. Формируют HTML
    4. Принимают значения, введенные пользователем
    5. Преобразуют значение обратно в формат модели
    6. Могут проводить валидацию данных

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

    1. передавать значения по умолчанию (массив или объект) его потомкам
    2. передавать введенные значения каждого дочернего элемента обратно в массив или объект
    Разделение задач

    Мы можем разделить задачи, описанные выше, на несколько определенных групп:

    • Преобразование данных
    • Формирование HTML (представление)
    • Валидация
    • Привязка данных

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

    Привязка моделей

    В большинстве случаев, формы напрямую привязаны к структурам, так или иначе, описанным в модели области определения. Рассмотрим на примере отправки информации профиля пользователя. Предположим, что вся информация о пользователе хранится в отдельной таблице в вашей базе данных. Таблица хранит информацию о свойствах, которые содержит профиль, о том, какой тип данных используется для каждого из свойств, их значения по умолчанию и ограничения по вводу данных. В идеале, ваше приложение так же должно содержать класс Profile со всеми необходимыми свойствами, с привязкой к таблице в базе данных, например, посредством Doctrine2 ORM. Этот класс может содержать больше информации о профиле, нежели хранится в таблице, например если в профиле указывается какой-то набор предметов, интересующих пользователя. Список этих предметов, для простоты, будем брать из файла конфигураций.


    Обычно, информация описывающая объект (назовем ее метаданными) должна быть продублирована в прослойке форм. Разработчику приходится следить за тем, не изменились ли поля, какие из них можно редактировать, следить за тем, что бы форма отображала соответствующие полям HTML виджеты, следить за тем, что бы некоторые из полей не могли оставаться пустыми ну и т.д. Именно из-за этих вещей создание форм становится довольно неблагодарным делом.

    Привязка моделей призвана изменить ситуацию. Она основывается на двух идеях:

    1. Использование существующих метаданных во время создании формы, дабы уменьшить количество дублируемого кода и/или настроек.

    Значения по умолчанию должны получаться из модели области определения (в нашем случае это будет экземпляр класса Profile) и запись введенных данных так же должна осуществляться в нашу модель.

    Динамические поведения

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

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

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

    Высокоуровневая архитектура

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

    • Расширения уровня ядра предоставляют описания структуры полей (назовем это типами форм (FormType)), реализованных во фреймворке.
    • Расширение валидации необходимо для проверки введенных пользователем данных внутри форм.
    • Расширение DI позволяет использовать контейнер зависимостей.
    • Расширение CSRF, как можно понять из названия, добавляет CSRF защиту для формы.
    • Расширения Doctrine2 (поставляемые с Doctrine Bridge) добавляют специфичные для Doctrine выпадающие списки и компоненты, позволяющие получить метаданные объекта для использования их в формах.

    Верхний уровень содержит компоненты, реализующие формирование HTML-я. По умолчанию в Symfony2 есть два таких компонента: один для рендринга форм через Twig (поставляется в Twig bridge) и другой для рендринга через старый добрый PHP (поставляется с FrameworkBundle).

    Наверное самое интересной особенностью данной архитектуры является то, что любой из компонентов можно заменить. Можно написать расширение для того, что бы формы использовали компонент валидации из Zend-а. Так же вы можете написать компонент представления реализующий рендринг через Smarty или любой другой шаблонизатор. Вы даже можете удалить расширение уровня ядра и написать свои основные типы форм для простых полей. Даже лежащий в основе диспетчек событий может быть заменен на ваш компонент, реализующий интерфейс EventDispatcherInterface. Это дает неплохое преимущество в гибкости, несмотря на некоторые неудобства.

    Низкоуровневая архитектура

    В данном разделе речь пойдет о внутренней архитектуре компонента форм. Как уже было упомянуто выше, форма и все ее части представлены в виде одной и той же структуры данных, которая реализует шаблон проектирования «Компоновщик». В компоненте Form данная структура описана интерфейсом FormInterface. Основным классом, реализующим этот интерфейс, является класс Form, который использует три компонента, при помощи которых и работает все это дело:

    • Мэппер данных распределяет данные формы по ее дочерним элементам. Кроме того, в обязанности этого компонента входит сбор данных от дочерних элементов обратно к данным формы.
    • Две цепочки преобразователей данных, как понятно из названия, преобразуют значения для разных их представлений. Преобразователи данных гарантируют то, что ваше приложение получит значение в строго определенном формате, вне зависимости от формата, который используется для его представления.
    • Диспетчер событий позволяет запускать специфичный код на заранее определенных этапах обработки формы. Такой подход позволяет адаптировать структуру формы под входящие данные, или же отфильтровать эти самые входящие данные, произвести валидацию или изменить их.

    Все эти компоненты передаются в конструктор объекта Form и не могут быть изменены после создания формы, так как это может привести к нежелательным изменениям состояния формы. Так как интерфейс конструктора объекта Form достаточно сложный, был реализован конструктор форм (FormBuilder), который упрощает создание экземпляров этих объектов.

    Представление формы это структура данных, описывающая представление. То-есть вместо того, что бы в шаблонах вызывать непосредственно класс Form, вы будете работать с экземпляром класса FormView. Этот объект хранит в себе дополнительную, специфичную только для представления информацию, такую как атрибуты name для элементов HTML форм, их ID и т.д.

    Приведенная ниже UML диаграмма отображает суть архитектуры.

    Как видно из этой диаграммы, жизненный цикл формы состоит из трех разных представлений:

    • При создании, форма представлена в виде иерархии объектов FormBuilder
    • В контроллере, форма представлена иерархией объектов Form
    • На уровне представления, она представлена иерархией объектов FormView

    Поскольку настройка конструкторов форм их представление дело довольно нудное, в Symfony2 реализованы основные типы форм, которые уже реализуют основные настройки. Типы форм поддерживают динамическое наследование. Это значит, что вы можете расширять различные базовые типы, основываясь на опциях, передаваемых в конструктор формы. Следующая диаграмма отображает все типы, поставляемые с Symfony2 (типы, отмеченные зеленым цветом, поставляются с ядром, когда как желтые — с дополнительными бандлами):

    Примеси, о которых мы раньше упоминали, реализуются в SYmfony2 как, так называемые, расширения типов. Эти расширения могут быть подключены к существующим типам форм и добавляют к ним какое-либо поведение. В Symfony2, например, существуют расширения для добавления CSRF защиты, применительно к типу «form» (и как следствие, всем типам, которые наследуют этот тип).

    Фабрика форм получает иерархию типов из загруженных расширений, и использует ее для настройки объектов FormBuilder и FormView. Важно отметить, что этот этап можно контролировать. Например, тип «choice» позволяет указывать в настройках атрибут «choices«, который содержит в себе все значения для опций, которые должны быть отображены.

    Есть еще одна достаточно важная концепция компонента Form — предсказатели типов. Эти «предсказатели» пытаются предугадать тип и опции поля формы, основываясь на метаданных, взятых из объекта области определения, за которой закреплена форма (если, конечно, она закреплена). К примеру, если какое-либо из свойств нашего объекта содержит связь «один ко многим» между объектом Tag, предсказатели типов автоматически настроят это поле формы для этого свойства так, что бы оно было полем выбора, с возможностью выбрать несколько значений, а так же будет использовать все экземпляры объектов Tag в качестве опций для этого поля. Похожая концепция используется в ModelForms во фреймворке Django. Правда есть одно достаточно большое отличие: предсказатели типов используют метаданные предоставляемые не только ORM-ом, но и все метаданные объекта. Symfony2 поставляется с тремя предсказателями типов: один использует метаданные, предоставляемые Doctrine2, другой — предоставляемые Propel и еще один использует правила валидации.

    Описанные выше концепции можно описать следующей UML диаграммой.

    Заключение

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

    Эта архитектура решает проблемы недостаточного уровня абстракций, специализации и примесей, предоставляя динамическое древо наследования типов форм и их расширений. Она решает проблему композиционности, распределяя задачи по обработке формы на все ее элементы. Так же она обеспечивает четкое разделение задач между компонентами, благодаря чему вы можете заменить их на свои. Используя метаданные объектов области определения при создании формы, описанная архитектура реализует привязку данных к этим моделям, что позволяет производить чтение и запись данных напрямую. Так же мы не обошли вниманием и динамические поведения, предоставляя возможность отслеживать определенные события, возникающие в процессе обработки формы, используя свои обработчики, например для валидации или фильтрации данных.

    Заинтересовались? Изучайте код. Экспериментируйте с ним. И помогите нам интегрировать его в ваш любимый фреймворк.

    От переводчика: переводы данной статьи существуют, но мне они показались не слишком качественными. Да и думаю не помешает. В переводе возможны неточности, посему буду благодарен, если вы укажите на них в ЛС. Спасибо за внимание.

    Формы¶

    Работа с формами — одна из наиболее типичных и проблемных задач для web-разработчика. Symfony2 включает компонент для работы с Формами, который облегчает работу с ними. В этой главе вы узнаете, как создавать сложные формы с нуля, познакомитесь с наиболее важными особенностями библиотеки форм.

    Компонент для работы с формами — это независимая библиотека, которая может быть использована вне проектов Symfony2. Подробности ищите по ссылке Symfony2 Form Component на ГитХабе.

    Создание простой формы¶

    Предположим, вы работаете над простым приложением — списком ToDo, которое будет отображать некоторые “задачи”. Поскольку вашим пользователям будет необходимо создавать и редактировать задачи, вам потребуется создать форму. Но, прежде чем начать, давайте создадим базовый класс Task , который представляет и хранит данные для одной задачи:

    Если вы будете брать код примеров один в один, вам, прежде всего необходимо создать пакет AcmeTaskBundle , выполнив следующую команду (и принимая все опции интерактивного генератора по умолчанию):

    Этот класс представляет собой обычный PHP-объект и не имеет ничего общего с Symfony или какой-либо другой библиотекой. Это PHP-объект, который выполняет задачу непосредственно внутри вашего приложение (т.е. является представлением задачи в вашем приложении). Конечно же, к концу этой главы вы будете иметь возможность отправлять данные для экземпляра Task (посредством HTML-формы), валидировать её данные и сохранять в базу данных.

    Создание формы¶

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

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

    Создание формы требует совсем немного кода, так как объекты форм в Symfony2 создаются при помощи конструктора форм — “form builder”. Цель конструктора форм — облегчить насколько это возможно создание форм, выполняя всю тяжёлую работу.

    В этом примере вы добавили два поля в вашу форму — task и dueDate , соответствующие полям task и dueDate класса Task . Вы также указали каждому полю их типы (например text , date ), которые в числе прочих параметров, определяют — какой HTML таг будет отображен для этого поля в форме.

    Symfony2 включает много встроенных типов, которые будут обсуждаться совсем скоро (см. Встроенные типы полей ).

    Отображение формы¶

    Теперь, когда форма создана, следующим шагом будет её отображение. Отобразить форму можно, передав специальный объект “form view” в ваш шаблон (обратите внимание на конструкцию $form->createView() в контроллере выше) и использовать ряд функций-помощников в шаблоне:

    В этом примере предполагается, что вы создали маршрут task_new , который указывает на контроллер AcmeTaskBundle:Default:new , который был создан ранее.

    Вот и всё! Напечатав form_widget(form) , каждое поле формы будет отображено, так же как метки полей и ошибки (если они есть). Это очень просто, но не очень гибко (пока что). На практике вам, скорее всего, захочется отобразить каждое поле формы отдельно, чтобы иметь полный контроль над тем как форма выглядит. Вы узнаете, как сделать это в секции “ Отображение формы в шаблоне ”.

    Прежде чем двигаться дальше, обратите внимание на то, как было отображено поле task , содержащее значение поля task объекта $task (“Write a blog post”). Это — первая задача форм: получить данные от объекта и перевести их в формат, подходящий для их последующего отображения в HTML форме.

    Система форм достаточно умна, чтобы получить доступ к значению защищённого (protected) поля task через методы getTask() и setTask() класса Task . Так как поле не публичное (public), оно должно иметь “геттер” и “сеттер” методы для того, чтобы компонент форм мог получить данные из этого поля и изменить их. Для булевых полей вы также можете использовать “is*” метод (например isPublished() ) вместо getPublished() .

    Обработка отправки форм¶

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

    Теперь, при отправке формы контроллер привязывает отправленные данные к форме, которая присваивает эти данные полям task и dueDate объекта $task . Эта задача выполняется методом bindRequest() .

    Как только вызывается метод bindRequest() , отправленные данные тут же присваиваются соответствующему объекту формы. Это происходит вне зависимости от того, валидны ли эти данные или нет.

    Этот контроллер следует типичному сценарию по обработке форм и имеет три возможных пути:

    1. При первичной загрузке страницы в браузер метод запроса будет GET , форма лишь создаётся и отображается;
    2. Когда пользователь отправляет форму (т.е. метод будет уже POST ) с неверными данными (вопросы валидации будут рассмотрены ниже, а пока просто предположим что данные не валидны), форма будет привязана к данным и отображена вместе со всеми ошибками валидации;
    3. Когда пользователь отправляет форму с валидными данными, форма будет привязана к данным и у вас есть возможность для выполнения некоторых действий, используя объект $task (например сохранить его в базе данных) перед тем как перенаправить пользователя на другую страницу (например, “thank you” или “success”).

    Перенаправление пользователя после успешной отправки формы предотвращает повторную отправку этих же данных, если пользователь обновит страницу.

    Валидация форм¶

    В предыдущей секции вы узнали, что форма может быть отправлена с валидными или не валидными данными. В Symfony2 валидация применяется к объекту, лежащему в основе формы (например, Task ). Другими словами, вопрос не в том, валидна ли форма, а валиден ли объект $task , после того как форма передала ему отправленные данные. Выполнив метод $form->isValid() , можно узнать валидны ли данные объекта $task или же нет.

    Валидация выполняется посредством добавление набора правил (называемых ограничениями) к классу. Для того, чтобы увидеть валидацию в действии, добавьте ограничения для валидации того, что поле task не может быть пусто, а поле dueDate не может быть пусто и должно содержать объект \DateTime .

    Это всё! Если вы отправите форму с ошибочными значениями — вы увидите что соответствующие ошибки будут отображены в форме.

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


    Генерированные формы полностью поддерживают эту возможность, добавляя соответствующие HTML-атрибуты, которые активируют HTML5 клиентскую валидацию. Тем не менее, валидация на стороне клиента может быть отключена путём добавления атрибута novalidate к тагу form или formnovalidate к тагу submit . Это бывает необходимо, когда вам нужно протестировать ваши серверные ограничения, но, к примеру, браузер не даёт отправить форму с пустыми полями.

    Валидация — это важная функция в составе Symfony2, она описывается в отдельной главе .

    Валидационные группы¶

    Если вы не используете валидационные группы , вы можете пропустить эту секцию.

    Если ваш объект использует возможности валидационных групп , вам нужно указать, какие группы вы хотите использовать:

    Если вы создаёте классы форм (хорошая практика), тогда вам нужно указать следующий код в метод getDefaultOptions() :

    В обоих этих примерах, для валидации объекта, для которого создана форма, будет использована лишь группа registration .

    Groups based on Submitted Data¶

    New in version 2.1: The ability to specify a callback or Closure in validation_groups is new to version 2.1

    Если вам требуется дополнительная логика для определения валидационных групп, например, на совновании данных, отправленных пользователем, вы можете установить значением опции val > Closure ).

    Этот код вызовет статический метод determineValidationGroups() класса Client с текущей формой в качестве аргумента, после того как данные будут привязаны (bind) к форме, но перед запуском процесса валидации. Вы также можете определить логику в замыкании Closure , например:

    Встроенные типы полей¶

    В состав Symfony входит большое число типов полей, которые покрывают все типичные поля и типы данных, с которыми вы столкнётесь:

    Вы также можете создавать свои собственные типы полей. Эта возможность подробно описывается в статье книги рецептов “ /cookbook/form/create_custom_field_type ”.

    Опции полей форм¶

    Каждый тип поля имеет некоторое число опций, которые можно использовать для их настройки. Например, поле dueDate сейчас отображает 3 селектбокса. Тем не менее, поле date можно настроить таким образом, чтобы отображался один текстбокс (где пользователь сможет ввести дату в виде строки):

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

    Наиболее типичной опцией является опция required , которая может быть указана для любого поля. По умолчанию, опция required установлена в true , что даёт возможность браузерам с поддержкой HTML5 использовать встроенную в них клиентскую валидацию, если поле остаётся пустым. Если вам этого не требуется, или же установите опцию required в false или же отключите валидацию HTML5 .

    Отметим также, что установка опции required в true не влияет на серверную валидацию. Другими словами, если пользователь отправляет пустое значение для этого поля (при помощи старого браузера или веб-сервиса) оно будет считаться валидным, если вы не используете ограничения NotBlank или NotNull .

    Таким образом, опция required — хороша, но серверную валидацию использовать необходимо всегда.

    Автоматическое определение типов полей¶

    Теперь, когда вы добавили данные для валидации в класс Task , Symfony теперь много знает о ваших полях. Если вы позволите, Symfony может определять (“угадывать”) тип вашего поля и устанавливать его автоматически. В этом примере, Symfony может определить по правилам валидации, что task является полем типа text и dueDate — полем типа date :

    Автоматическое определение активируется, когда вы опускаете второй аргумент в методе add() (или если вы указываете null для него). Если вы передаёте массив опций в качестве третьего аргумента (как в случае dueDate выше), эти опции применяются к “угаданному” полю.

    Если ваша форма использует особую группу валидации, определитель типов полей будет учитывать все ограничения при определении типов полей (включая ограничения, которые не являются частью используемых валидационных групп).

    Автоматическое определение опций для полей¶

    В дополнение к определению “типа” поля, Symfony также может попытаться определить значения опций для поля.

    Когда эти опции будут установлены, поле будет отображено с использованием особых HTML атрибутов, которые позволяют выполнять HTML5 валидацию на стороне клиента (например Assert\MaxLength ). И, поскольку вам нужно будет вручную добавлять правила валидации на стороне сервера, эти опции могут быть угаданы исходя из ограничений, которые вы будете использовать для неё.

    • required : Опция required может быть определена исходя из правил валидации (т.е. если поле NotBlank или NotNull ) или же на основании метаданных Doctrine (т.е. если поле nullable ). Это может быть очень удобно, так как правила клиентской валидации автоматически соответствуют правилам серверной валидации.
    • min_length : Если поле является одним из видов текстовых полей, опция min_length может быть угадана исходя из правил валидации ( если используются ограничения MinLength или Min ) или же из метаданных Doctrine (основываясь на длине поля).
    • max_length : Аналогично min_length с той лишь разницей, что определяет максимальное значение длины поля.

    Эти опции могут быть определены автоматически, только если вы используете автоопределение полей (не указываете или передаёте null в качестве второго аргумента в метод add() ).

    Если вы хотите изменить значения, определённые автоматически, вы можете перезаписать их, передавая требуемые опции в массив опций:

    Отображение формы в шаблоне¶

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

    Давайте более подробно рассмотрим каждую часть:

    • form_enctype(form) — если хоть одно поле формы является полем для загрузки файла, эта функция отобразит необходимый атрибут enctype=»multipart/form-data» ;
    • form_errors(form) — Отображает глобальные по отношению к форме целиком ошибки валидации (ошибки для полей отображаются после них);
    • form_row(form.dueDate) — Отображает текстовую метку, ошибки и HTML-виджет для заданного поля (например для dueDate ) внутри div элемента (по умолчанию);
    • form_rest(form) — Отображает все остальные поля, которые ещё не были отображены. Как правило хорошая идея расположить вызов этого хелпера внизу каждой формы (на случай если вы забыли вывести какое-либо поле или же не хотите вручную отображать скрытые поля). Этот хелпер также удобен для активации автоматической защиты от CSRF атак .

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

    Вы можете получить доступ к данным вашей формы при помощи form.vars.value :

    Отображение каждого поля вручную¶

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

    Если автоматически созданная метка для поля вам не нравится, вы можете указать её явно:

    Наконец, некоторые типы полей имеют дополнительные опции отображения, которые можно указывать виджету. Эти опции документированы для каждого такого типа, но общей для всех опцией является attr , которая позволяет вам модифицировать атрибуты элемента формы. Следующий пример добавит текстовому полю CSS класс task_field :

    Справочник по функциям Twig¶

    Если вы используете Twig, полная справочная информация о функциях, используемых для отображения форм, доступна в справочнике . Ознакомьтесь с этой информацией, для того чтобы узнать больше о доступных хелперах и опциях, которые для них доступны.

    Создание классов форм¶

    Как вы уже видели ранее, форма может быть создана и использована непосредственно в контроллере. Тем не менее, лучшей практикой является создание формы в отдельном PHP-классе, который может быть использован повторно в любом месте вашего приложения. Создайте новый класс, который будет содержать логику создания формы task :

    Этот новый класс содержит все необходимые указания для создания формы задачи (обратите внимание, что метод getName() должен возвращать уникальный идентификатор для данной формы). Теперь, вы можете использовать этот класс для быстрого создания объекта формы в контроллере:

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

    Настройка data_class для формы

    Каждая форма должна знать имя класса, который будет содержать данные для неё (например, Acme\TaskBundle\Entity\Task ). Как правило, эти данные определяются автоматически по объекту, который передаётся вторым параметром в метод createForm (т.е. $task ). Позднее, когда вы займётесь встраиванием форм, полагаться на автоопреление уже будет нельзя. Таким образом, хоть и не всегда необходимо, но всё же желательно явно указывать опцию data_class , добавив следующие строки в класс формы:

    Формы и Doctrine¶

    Цель любой формы — преобразование данных из объекта (в нашем случае Task ) в HTML форму и наоборот — преобразование данных, отправленных пользователем, обратно в объект. По существу, тема по сохранению объекта Task в базе данных совершенно не относится теме, обсуждаемой в главе “Формы”. Тем не менее, если вы сконфигурировали класс Task для работы с Doctrine (т.е. вы добавили метаданные для отображения (mapping metadata) для него), его сохранение после отправки формы можно выполнить в случае, если форма валидна:

    Если, по каким-то причинам у вас нет изначального объекта $task , вы можете получить его из формы:

    Больше информации по работе с базами данных вы можете получить в главе Doctrine ORM .

    Самое главное, что требуется уяснить, когда форма и данные связываются, данные тут же передаются в объект, лежащий в основе формы. Если вы хотите сохранить эти данные, вам нужно просто сохранить объект (который уже содержит отправленные данные).

    Встроенные формы¶

    Зачастую, когда вы хотите создать форму, вам требуется добавлять в неё поля из различных объектов. Например, форма регистрации может содержать данные, относящиеся к объекту User и к нескольким объектам Address . К счастью, с использованием компонента форм сделать это легко и естественно.

    Встраивание одного объекта¶

    Предположим, что каждая задача Task соответствует некоторому объекту Category . Начнём конечно же с создания класса Category :

    Затем создадим свойство category в классе Task :

    Теперь ваше приложение нужно подправить с учётом новых требований. Создайте класс формы для изменения объекта Category :


    Конечно целью же является изменение Category для Task непосредственно из задачи. Для того чтобы выполнить это, добавьте поле category в форму TaskType , которое будет представлено экземпляром нового класса CategoryType :

    Поля формы CategoryType теперь могут быть отображены прямо в форме TaskType . Отобразите поля Category тем же способом как и поля Task :

    Когда пользователь отправляет форму, данные для полей Category будут использованы для создания экземпляра Category , который будет присвоен полю category объекта Task .

    Объект Category доступен через метод $task->getCategory() и может быть сохранён в базу данных или использован где требуется.

    Встраивание коллекций форм¶

    Вы также можете встроить в вашу форму целую коллекцию форм (например форма Category с множеством саб-форм Product ). Этого можно достичь при использовании поля collection .

    Подробнее этот тип поля описан в книге рецептов “ /cookbook/form/form_collections ” и справочнике: collection .

    Дизайн форм¶

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

    Symfony использует шаблоны для отображения всех частей форм, таких как метки, таги, input таги, сообщения об ошибках и многое другое.

    В Twig каждый такой фрагмент представлен блоком Twig. Для настройки любой части отображения формы вам просто надо заменить нужный блок.

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

    Для того чтобы понять, как это работает, давайте настроим отображение фрагмента form_row и добавим атрибут > div , который содержит каждую строку. Для того чтобы выполнить это, создайте новый файл шаблона, который будет содержать новую разметку:

    Фрагмент field_row используется при отображении большинства полей при помощи функции form_row . Для того, чтобы сообщить компоненту форм, чтобы он использовал новый фрагмент field_row , определённый выше, добавьте следующую строку в начале шаблона, отображающего форму:

    Таг form_theme (в Twig) как бы “импортирует” фрагменты, определённые в указанном шаблоне и использует их при отображении формы. Другими словами, когда вызывается функция form_row ниже в этом шаблоне, она будет использовать блок field_row из вашей темы (вместо блока field_row по умолчанию используемого в Symfony).

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

    Дополнительную информацию о кастомизации форм ищите в книге рецептов: /cookbook/form/form_customization .

    Именование фрагментов форм¶

    В Symfony, каждая отображаемая часть формы — HTML элементы форм, ошибки, метки и т.д. — определены в базовой теме, которая представляет из себя набор блоков в Twig и набор шаблонов в PHP.

    В Twig все блоки определены в одном файле (form_div_layout.html.twig), который располагается внутри Twig Bridge. В этом файле вы можете увидеть любой из блоков, необходимых для отображения любого стандартного поля.

    В PHP каждый фрагмент расположен в отдельном файле. По умолчанию, они располагаются в директории Resources/views/Form в составе пакета framework (см. на GitHub).

    Наименование каждого фрагмента следует одному базовому правилу и разбито на две части, разделённых подчерком ( _ ). Несколько примеров:

    • field_row — используется функцией form_row для отображения большинства полей;
    • textarea_widget — используется функцией form_widget для отображения полей типа textarea ;
    • field_errors — используется функцией form_errors для отображения ошибок.

    Каждый фрагмент подчиняется простому правилу: type_part . Часть type соответствует типу поля, которое будет отображено (например, textarea , checkbox , date и т.д.), часть part соответствует же тому, что именно будет отображаться ( label , widget , errors , и т.д.). По умолчанию есть четыре возможных типов parts, которые отображаются:

    label ( field_label ) отображает метку для поля
    widget ( field_widget ) отображает HTML-представление для поля
    errors ( field_errors ) отображает ошибки для поля
    row ( field_row ) отображает цельную строку для поля (label, widget & errors)

    Есть также ещё три типа parts — rows , rest , и enctype — но заменять их вам вряд ли потребуется, так что и заботиться этом не стоит.

    Зная тип поля (например textarea ), а также какую часть вы хотите изменить (например, widget ), вы можете составить имя фрагмента, который должен быть переопределён (например, textarea_widget ).

    Наследование фрагментов шаблона форм¶

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

    Ответ на этот вопрос такой: отображаются они при помощи фрагмента field_errors . Когда Symfony отображает ошибки для textarea, он ищет фрагмент textarea_errors , прежде чем использовать стандартный фрагмент field_errors . Любой тип поля имеет родительский тип (для textarea это field ) и Symfony использует фрагмент от родительского типа, если базовый фрагмент не существует.

    Таким образом, чтобы переопределить фрагмент ошибок только для полей textarea , скопируйте фрагмент field_errors , переименуйте его в textarea_errors и измените его как вам требуется. Для того, чтобы изменить отображение ошибок для всех полей, скопируйте и измените сам фрагмент field_errors .

    Родительские типы для всех типов полей можно узнать из справочника: типы полей .

    Глобальная тема для форм¶

    В примере выше вы использовали хелпер form_theme (для Twig), чтобы “импортировать” изменённые фрагменты форм только в одну форму. Вы также можете указать Symfony тему форм для всего проекта в целом.

    Для того, чтобы автоматически подключить переопределённые блоки из ранее созданного шаблона fields.html.twig , измените ваш файл конфигурации следующим образом:

    Любой блок внутри шаблона fields.html.twig будет использован глобально в рамках проекта для определения формата отображения форм.

    Настройка отображения форм в файле формы при использовании Twig

    При использовании Twig, вы также можете изменить блок формы непосредственно внутри шаблона, где требуется изменение стиля отображения:

    Таг <% form_theme form _self %>позволяет изменять блоки формы непосредственно внутри того шаблона, который требует изменений. Используйте этот метод для быстрой настройки отображения формы, если данное изменение нигде больше не потребуется.

    Для того, чтобы автоматически подключить изменённые шаблоны из директории Acme/TaskBundle/Resources/views/Form , созданной ранее, для всех шаблонов, измените конфигурацию вашего приложения следующим образом:

    Все фрагменты, определённые в директории Acme/TaskBundle/Resources/views/Form теперь будут использованы во всём приложении для изменения стиля отображения форм.

    Защита от CSRF атак¶

    CSRF — или же Подделка межсайтовых запросов это вид атак, позволяющий злоумышленнику выполнять запросы от имени пользователей вашего приложения, которые они делать не собирались (например перевод средств на счёт хакера). К счастью, такие атаки можно предотвратить, используя CSRF токен в ваших формах.

    Хорошие новости! Заключаются они в том, что Symfony по умолчанию добавляет и валидирует CSRF токен для вас. Это означает, что вы получаете защиту от CSRF атак не прилагая к этому никаких усилий. Фактически, все формы в этой главе были защищены от подобных атак.

    Защита от CSRF атак работает за счёт добавления в формы скрытого поля, называемого по умолчанию _token , которое содержит значение, которое знаете только вы и пользователь вашего приложения. Это гарантирует, что пользователь — и никто более — отправил данные, которые пришли к вам. Symfony автоматически валидирует наличие и правильность этого токена.

    Поле _token — это скрытое поле и оно автоматически отображается, если вы используете функцию form_rest() в вашем шаблоне, которая отображает все поля, которые ещё не были отображены в форме.

    CSRF токен можно настроить уровне формы. Например:

    Для того, чтобы отключить CSRF защиту, установите опцию csrf_protection в false . Настройки также можно выполнить на уровне всего проекта. Дополнительную информацию можно найти в справочнике по настройке форм .

    Опция intention ( намерение ) не обязательна, но значительно увеличивает безопасность сгенерированного токена, делая его различным для всех форм.

    Использование форм без класса¶

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

    Тем не менее, вам возможно потребуется использовать форму без соответствующего класса и получать массив отправленных данных, а не объект. Этого просто достичь:

    По умолчанию, форма полагает, что вы хотите работать с массивами данных, а не с объектами. Есть два способа изменить это поведение и связать форму с объектом:

    1. Передать объект при создании формы (первый аргумент createFormBuilder ) или второй аргумент createForm );
    2. Определить опцию data_class для вашей формы.

    Если вы этого не сделали, тогда форма будет возвращать данные в виде массива. В этом примере, так как $defaultData не является объектом (и не установлена опция data_class ), $form->getData() в конечном итоге вернёт массив.

    Вы также можете получить доступ к значениям POST (в данном случае “name”) напрямую через объект запроса, например так:

    Тем не менее, в большинстве случаев рекомендуется использовать метод getData(), так как он возвращает данные (как правило объект) после того как он был преобразован фреймворком форм.

    Добавление валидации¶

    А как же быть с валидацией? Обычно, когда вы используете вызов $form->isValid() , объект валидировался на основании ограничений, которые вы добавили в этот класс. Но когда класса нет, как добавить ограничения для данных из формы?

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

    Теперь, когда вы вызываете $form->isValid() , ограничения, указанные выше, выполняются для данных формы. Если вы используете класс формы, переопределите метод getDefaultOptions :

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

    Заключение¶

    Теперь вы знаете всё необходимое для создания сложных форм для вашего приложения. При создании форм, не забывайте что первой целью формы является транслирование данных из объекта ( Task ) в HTML форму, чтобы пользователь мог модифицировать эти данные. Второй целью формы является получение отправленных пользователем данных и передача их обратно в объект.

    Есть ещё много вещей, которые стоит узнать о прекрасном мире форм, таких как загрузка файлов при помощи Doctrine , или же как создание формы с динамически меняемым числом вложенных форм ( например, список todo, где вы можете добавлять новые поля при помощи Javascript перед отправкой). Ищите ответы в книге рецептов. Также изучите справочник по типам полей , который включает примеры использования полей и их опций.

    Передача пользовательских параметров в форму symfony2

    в symfony 1.4 можно было параметризовать определение класса формы с помощью опций формы. Есть ли способ передать пользовательские параметры в свой собственный тип формы. Я попытался использовать параметр options метода buildForm , но я не очень уверен, что это за массив, и, видимо, это не то, что я хочу. Спасибо!

    Решение прост, если вы хотите, чтобы ваша пользовательская опция была доступна также в шаблоне Twig, вы должны использовать $builder->setAttribute() в buildForm а также $view->set() в методе buildView() .

    Шаблон для настраиваемого типа формы (файл. Acme/DemoBundle/Resources/views/Form/fields.html.twig):

    Зарегистрируйте свой шаблон для пользовательских типов форм в app/config/config.yml

    Использование: просмотр предварительного просмотра изображения пользователя при редактировании его профиля:

    2014-08-18: Обновлено для Symfony 2.1 или выше

    ОБНОВЛЕНИЕ: Обратите внимание, что это решение работает только в Symfony 2.0.x, который устарел, используйте setDefaultOptions вместо getDefaultOptions .

    Справедливо, типы форм Symfony 2 принимают параметры, которые вы можете использовать для всего, что вы хотите, внутри типа формы. Вам необходимо переопределить метод getDefaultOptions , чтобы указать параметры вашего типа.

    Например, у меня есть тип MyCustomType , который принимает my_option , этот параметр имеет значение по умолчанию false , реализация MyCustomType может быть примерно такой.

    Позже вам нужно будет указать параметр при создании формы в контроллере, используя третий параметр buildForm :

    Если вы не указали опцию my_option , она принимает значение по умолчанию ( false ).

    Мастер Йода рекомендует:  Ошибочные представления программистов о телефонных номерах
    Добавить комментарий