Symfony2 Data Transformer on hidden field

后端 未结 2 1570
死守一世寂寞
死守一世寂寞 2021-02-02 04:34

I\'ve searched and not found anyone with this problem.

I\'ve created my own Data Transformer as set out in the Cookbook and it all seems right but i get the error:

相关标签:
2条回答
  • 2021-02-02 05:07

    This is the way I handle entities with hidden inputs:

    DataTransformer

    <?php
    
    namespace Comakai\CQZBundle\Form\DataTransformer;
    
    use Symfony\Component\Form\DataTransformerInterface;
    use Symfony\Component\Form\Exception\TransformationFailedException;
    use Doctrine\Common\Persistence\ObjectManager;
    
    class EntityToIdTransformer implements DataTransformerInterface
    {
        /**
         * @var ObjectManager
         */
        private $om;
        private $entityClass;
    
        /**
         * @param ObjectManager $om
         */
        public function __construct(ObjectManager $om, $entityClass)
        {
            $this->om = $om;
            $this->entityClass = $entityClass;
        }
    
        /**
         * Transforms an object to a string (id).
         *
         * @param  Object|null $entity
         * @return string
         */
        public function transform($entity)
        {
            if (null === $entity) {
                return "";
            }
    
            return $entity->getId();
        }
    
        /**
         * Transforms a string (id) to an object.
         *
         * @param  string $id
         * @return Object|null
         * @throws TransformationFailedException if object is not found.
         */
        public function reverseTransform($id)
        {
            if (!$id) {
                return null;
            }
    
            $entity = $this->om->getRepository($this->entityClass)->findOneById($id);
    
            if (null === $entity) {
    
                throw new TransformationFailedException(sprintf(
                        'An entity of class ' . $this->entityClass . ' with id "%s" does not exist!', $id
                ));
            }
    
            return $entity;
        }
    
    }
    

    FormType

    <?php
    
    namespace Comakai\CQZBundle\Form\Type;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Doctrine\Common\Persistence\ManagerRegistry;
    use Doctrine\Common\Persistence\ObjectManager;
    use Comakai\CQZBundle\Form\DataTransformer\EntityToIdTransformer;
    
    class EntityHiddenType extends AbstractType
    {
        /**
         * @var ManagerRegistry
         */
        private $registry;
    
        /**
         * @var ObjectManager
         */
        private $om;
        private $cache;
    
        /**
         * @param ObjectManager $om
         */
        public function __construct(ManagerRegistry $registry)
        {
            $this->registry = $registry;
            $this->om = $registry->getManager();
            $this->cache = [];
        }
    
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $class = (empty($options['data_class'])) ? $this->getClassFromMetadata($builder->getName(), $builder->getParent()->getDataClass()) : $options['data_class'];
    
            $transformer = new EntityToIdTransformer($this->om, $class);
            $builder->addViewTransformer($transformer);
    
            $builder->setAttribute('data_class', $class);
        }
    
        public function getParent()
        {
            return 'hidden';
        }
    
        public function getName()
        {
            return 'entity_hidden';
        }
    
        protected function getClassFromMetadata($name, $parentClass)
        {
            /* @var $md \Doctrine\ORM\Mapping\ClassMetadata */
            $md = $this->getMetadata($parentClass)[0];
            $a = $md->getAssociationMapping($name);
            $class = $a['targetEntity'];
    
            return $class;
        }
    
        protected function getMetadata($class)
        {
            if (array_key_exists($class, $this->cache)) {
                return $this->cache[$class];
            }
    
            $this->cache[$class] = null;
            foreach ($this->registry->getManagers() as $name => $em) {
                try {
                    return $this->cache[$class] = array($em->getClassMetadata($class), $name);
                } catch (MappingException $e) {
                    // not an entity or mapped super class
                } catch (LegacyMappingException $e) {
                    // not an entity or mapped super class, using Doctrine ORM 2.2
                }
            }
        }
    
    }
    

    Config (services.yml)

    services:
        cqz.form.type.entity_hidden:
            class: Comakai\CQZBundle\Form\Type\EntityHiddenType
            arguments: ["@doctrine"]
            tags:
                    -  { name: form.type, alias: entity_hidden }
    

    JobType

    $builder->add('company', 'entity_hidden');
    

    Then in your controller

    $job = new \Niche\JobBundle\Entity\Job();
    $type = new \Niche\JobBundle\Form\JobType();
    
    $job->setCompany($businessUser);
    
    $form = $this->createForm($type, $job);
    

    This way you'll have a reusable entity_hidden type.

    UPDATE FOR 2.3

    Since there is no $builder->getParent() anymore (https://github.com/symfony/symfony/blob/master/UPGRADE-2.2.md) and because I don't want to set the class of the field's data, I came up with this (btw, now I'm using the form.type_guesser.doctrine service to get the class):

    Config

    cqz.form.type.suggest:
            class: Comakai\CQZBundle\Form\Type\SuggestType
            arguments: ["@doctrine.orm.entity_manager", "@form.type_guesser.doctrine"]
    

    DataTransformer

    <?php
    
    namespace Comakai\CQZBundle\Form\DataTransformer;
    
    use Symfony\Component\Form\DataTransformerInterface;
    use Symfony\Component\Form\Exception\TransformationFailedException;
    use Doctrine\Common\Persistence\ObjectManager;
    
    class ObjectToIdTransformer implements DataTransformerInterface
    {
         /**
         * @var ObjectManager
         */
        private $om;
        private $objectClass;
    
        /**
         * @param ObjectManager $om
         */
        public function __construct(ObjectManager $om, $objectClass = null)
        {
            $this->om = $om;
            $this->objectClass = $objectClass;
        }
    
        /**
         * Transforms an object to an id.
         *
         * @param  Object|null $object
         * @return mixed
         */
        public function transform($object)
        {
            if (null === $object) {
    
                return '';
            }
    
            return $object->getId();
        }
    
        /**
         * Transforms an id to an object.
         *
         * @param  mixed $id
         *
         * @return Object|null
         *
         * @throws TransformationFailedException if object is not found.
         */
        public function reverseTransform($id)
        {
            if (!$id) {
    
                return null;
            }
    
            $object = $this->om
                ->getRepository($this->objectClass)
                ->find($id)
            ;
    
            if (null === $object) {
    
                throw new TransformationFailedException(sprintf(
                    'An instance of "%s" with id "%s" does not exist!',
                    $this->objectClass,
                    $id
                ));
            }
    
            return $object;
        }
    
        public function getObjectClass()
        {
            return $this->objectClass;
        }
    
        public function setObjectClass($class)
        {
            $this->objectClass = $class;
        }
    }
    

    Type

    <?php
    
    namespace Comakai\CQZBundle\Form\Type;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Doctrine\Common\Persistence\ObjectManager;
    use Symfony\Bridge\Doctrine\Form\DoctrineOrmTypeGuesser;
    use Symfony\Component\OptionsResolver\OptionsResolverInterface;
    use Comakai\CQZBundle\Form\DataTransformer\ObjectToIdTransformer;
    
    use Symfony\Component\Form\FormView;
    use Symfony\Component\Form\FormInterface;
    
    use Symfony\Component\Form\FormEvents;
    use Symfony\Component\Form\FormEvent;
    
    class SuggestType extends AbstractType
    {
        /**
         * @var ObjectManager
         */
        private $om;
        private $guesser;
    
        /**
         * @param ObjectManager $om
         */
        public function __construct(ObjectManager $om, DoctrineOrmTypeGuesser $guesser)
        {
            $this->om = $om;
            $this->guesser = $guesser;
        }
    
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $transformer = new ObjectToIdTransformer($this->om);
            $builder->addModelTransformer($transformer);
    
            if($options['class'] === null) {
    
                $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) use ($transformer, $builder) {
    
                    /* @var $form \Symfony\Component\Form\Form */
                    $form = $event->getForm();
                    $class = $form->getParent()->getConfig()->getDataClass();
                    $property = $form->getName();
                    $guessedType = $this->guesser->guessType($class, $property);
                    $options = $guessedType->getOptions();
    
                    $transformer->setObjectClass($options['class']);
    
                });
    
            } else {
    
                $transformer->setObjectClass($options['class']);
    
            }
        }
        ...
    

    I feel that using a PRE_SET_DATA to set the data class on the transformer is nasty, what do you think?

    0 讨论(0)
  • 2021-02-02 05:20

    I just created an input type hidden:

    $builder->add('child_id', 'hidden', array('mapped' => false))
    

    In the newAction I did fill with the parent id:

    $childForm->get('parent_id')->setData($parentEntity->getId());
    

    And finally in createAction I did put:

    $child->setParent($em->getReference('MyBundle:Parent', $form["child_id"]->getData()))
    

    PS: I understand that you wanted to create your Data Transformer, but if your problem is persist object with parent id, it will help you.

    0 讨论(0)
提交回复
热议问题