У меня есть 2 объекта – пользователь и группа. Они имеют отношения «многие ко многим», а «Группа» используется для хранения ролей пользователей.
Я пытаюсь сделать форму редактирования пользователя, добавив коллекцию, я хочу добавить новую роль, выбрав ее из раскрывающегося списка (ограниченного тем, что уже находится в БД)
UserType.php:
class UserType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('username') ->add('email') ->add('forename') ->add('surname') ->add('isActive') ->add('joinDate', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy')) ->add('lastActive', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy')) ->add('groups', 'collection', array( 'type' => new GroupType(), 'allow_add' => true, )) ; } public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'data_class' => 'Sfox\CoreBundle\Entity\User' )); } }
и GroupType.php:
class GroupType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name') ->add('role'); } public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( "data_class" => 'Sfox\CoreBundle\Entity\Group' )); } }
Это отображает роли в форме в основных текстовых полях, но если я добавлю запись в форму, она будет каскадировать, сохраняя новую запись в группах, и если бы я должен был редактировать запись, это изменило бы базовые данные Группы.
Я попытался сделать GroupSelectType.php:
class GroupSelectType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('role', 'entity', array('class'=>'SfoxCoreBundle:Group', 'property'=>'name')); } public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( "data_class" => 'Sfox\CoreBundle\Entity\Group' )); } }
Добавляя поле как тип «сущность», оно отображает правильный флажок выбора (но со значениями по умолчанию). Я не могу привязать его к форме UserType!
Все, что я хочу, чтобы форма делала, – это изменить базовые группы ArrayCollection в группе User.
Кто-нибудь знает, как я могу это достичь?
Ну, я разработал решение для всех, кто борется с подобными проблемами …
Мне пришлось создать пользовательский тип формы и объявить его как службу, чтобы я мог пройти в диспетчере сущностей. Затем мне нужно было сделать dataTransformer для изменения объектов группы в целое число для формы
Custom GroupSelectType:
class GroupSelectType extends AbstractType { /** * @var ObjectManager */ private $om; private $choices; /** * @param ObjectManager $om */ public function __construct(ObjectManager $om) { $this->om = $om; // Build our choices array from the database $groups = $om->getRepository('SfoxCoreBundle:Group')->findAll(); foreach ($groups as $group) { // choices[key] = label $this->choices[$group->getId()] = $group->getName() . " [". $group->getRole() ."]"; } } public function buildForm(FormBuilderInterface $builder, array $options) { $transformer = new GroupToNumberTransformer($this->om); $builder->addModelTransformer($transformer); } public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( "choices" => $this->choices, )); } public function getParent() { return 'choice'; } public function getName() { return 'group_select'; } }
В конструкторе я получаю все доступные группы и помещаю их в массив «выборы», который передается в поле выбора в качестве опции.
Вы также заметите, что я использую настраиваемый преобразователь данных, это изменение группыId (которая используется при рендеринге формы) для объекта Group. Я также сделал службу GroupSelectType и передал в [@ doctrine.orm.entity_manager]
services.yml (config bundle):
services: sfox_core.type.group_select: class: Sfox\CoreBundle\Form\Type\GroupSelectType arguments: [@doctrine.orm.entity_manager] tags: - { name: form.type, alias: group_select }
GroupToNumberTranformer.php
class GroupToNumberTransformer implements DataTransformerInterface { /** * @var ObjectManager */ private $om; /** * @param ObjectManager $om */ public function __construct(ObjectManager $om) { $this->om = $om; } /** * Transforms an object (group) to a string (number). * * @param Group|null $group * @return string */ public function transform($group) { if (null === $group) { return ""; } return $group->getId(); } /** * Transforms a string (number) to an object (group). * * @param string $number * @return Group|null * @throws TransformationFailedException if object (group) is not found. */ public function reverseTransform($number) { if (!$number) { return null; } $group = $this->om ->getRepository('SfoxCoreBundle:Group') ->findOneBy(array('id' => $number)) ; if (null === $group) { throw new TransformationFailedException(sprintf( 'Group with ID "%s" does not exist!', $number )); } return $group; } }
И мой измененный UserType.php – Заметьте, что я использую свой собственный тип формы «group_select» сейчас, поскольку он работает как служба:
class UserType extends AbstractType { private $entityManager; public function __construct($entityManager) { $this->entityManager = $entityManager; } public function buildForm(FormBuilderInterface $builder, array $options) { $transformer = new GroupToNumberTransformer($this->entityManager); $builder ->add('username') ->add('email') ->add('forename') ->add('surname') ->add('isActive') ->add('joinDate', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy')) ->add('lastActive', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy')); $builder ->add( $builder->create('groups', 'collection', array( 'type' => 'group_select', 'allow_add' => true, 'options' => array( 'multiple' => false, 'expanded' => false, ) )) ); } public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'data_class' => 'Sfox\CoreBundle\Entity\User' )); } public function getName() { return 'sfox_corebundle_usertype'; } }