Symfony 2 Entity field type with select and/or add new

后端 未结 2 584
孤独总比滥情好
孤独总比滥情好 2021-02-01 09:48

Context:

Let there be two entities (correctly mapped for Doctrine).

  1. Post with properties {$id (integer, autoinc), $name
2条回答
  •  死守一世寂寞
    2021-02-01 10:23

    My Tag entity has a unique field for the tag name. For add Tags I use a new form type and a transformer.

    The Form Type:

    namespace Sg\RecipeBundle\Form\Type;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Bridge\Doctrine\RegistryInterface;
    use Symfony\Component\Security\Core\SecurityContextInterface;
    use Sg\RecipeBundle\Form\DataTransformer\TagsDataTransformer;
    
    class TagType extends AbstractType
    {
        /**
         * @var RegistryInterface
         */
        private $registry;
    
        /**
         * @var SecurityContextInterface
         */
        private $securityContext;
    
    
        /**
         * Ctor.
         *
         * @param RegistryInterface        $registry        A RegistryInterface instance
         * @param SecurityContextInterface $securityContext A SecurityContextInterface instance
         */
        public function __construct(RegistryInterface $registry, SecurityContextInterface $securityContext)
        {
            $this->registry = $registry;
            $this->securityContext = $securityContext;
        }
    
        /**
         * {@inheritdoc}
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->addViewTransformer(
                new TagsDataTransformer(
                    $this->registry,
                    $this->securityContext
                ),
                true
            );
        }
    
        /**
         * {@inheritdoc}
         */
        public function getParent()
        {
            return 'text';
        }
    
        /**
         * {@inheritdoc}
         */
        public function getName()
        {
            return 'tag';
        }
    }
    

    The Transformer:

    em = $registry->getEntityManager();
            $this->securityContext = $securityContext;
        }
    
        /**
         * Convert string of tags to array.
         *
         * @param string $string
         *
         * @return array
         */
        private function stringToArray($string)
        {
            $tags = explode(',', $string);
    
            // strip whitespaces from beginning and end of a tag text
            foreach ($tags as &$text) {
                $text = trim($text);
            }
    
            // removes duplicates
            return array_unique($tags);
        }
    
        /**
         * Transforms tags entities into string (separated by comma).
         *
         * @param Collection | null $tagCollection A collection of entities or NULL
         *
         * @return string | null An string of tags or NULL
         * @throws UnexpectedTypeException
         */
        public function transform($tagCollection)
        {
            if (null === $tagCollection) {
                return null;
            }
    
            if (!($tagCollection instanceof Collection)) {
                throw new UnexpectedTypeException($tagCollection, 'Doctrine\Common\Collections\Collection');
            }
    
            $tags = array();
    
            /**
             * @var \Sg\RecipeBundle\Entity\Tag $tag
             */
            foreach ($tagCollection as $tag) {
                array_push($tags, $tag->getName());
            }
    
            return implode(', ', $tags);
        }
    
        /**
         * Transforms string into tags entities.
         *
         * @param string | null $data Input string data
         *
         * @return Collection | null
         * @throws UnexpectedTypeException
         * @throws AccessDeniedException
         */
        public function reverseTransform($data)
        {
            if (!$this->securityContext->isGranted('ROLE_AUTHOR')) {
                throw new AccessDeniedException('Für das Speichern von Tags ist die Autorenrolle notwendig.');
            }
    
            $tagCollection = new ArrayCollection();
    
            if ('' === $data || null === $data) {
                return $tagCollection;
            }
    
            if (!is_string($data)) {
                throw new UnexpectedTypeException($data, 'string');
            }
    
            foreach ($this->stringToArray($data) as $name) {
    
                $tag = $this->em->getRepository('SgRecipeBundle:Tag')
                    ->findOneBy(array('name' => $name));
    
                if (null === $tag) {
                    $tag = new Tag();
                    $tag->setName($name);
    
                    $this->em->persist($tag);
                }
    
                $tagCollection->add($tag);
    
            }
    
            return $tagCollection;
        }
    }
    

    The config.yml

    recipe.tags.type:
        class: Sg\RecipeBundle\Form\Type\TagType
        arguments: [@doctrine, @security.context]
        tags:
            - { name: form.type, alias: tag }
    

    use the new Type:

            ->add('tags', 'tag', array(
                'label' => 'Tags',
                'required' => false
                ))
    

    Similarities, like "symfony" and "smfony" can be prevented with an autocomplete function:

    TagController:

    getRequest();
            $isAjax = $request->isXmlHttpRequest();
    
            if ($isAjax) {
                $em = $this->getDoctrine()->getManager();
    
                $search = $request->query->get('term');
    
                /**
                 * @var \Sg\RecipeBundle\Entity\Repositories\TagRepository $repository
                 */
                $repository = $em->getRepository('SgRecipeBundle:Tag');
    
                $qb = $repository->createQueryBuilder('t');
                $qb->select('t.name');
                $qb->add('where', $qb->expr()->like('t.name', ':search'));
                $qb->setMaxResults(5);
                $qb->orderBy('t.name', 'ASC');
                $qb->setParameter('search', '%' . $search . '%');
    
                $results = $qb->getQuery()->getScalarResult();
    
                $json = array();
                foreach ($results as $member) {
                    $json[] = $member['name'];
                };
    
                return new Response(json_encode($json));
            }
    
            return new Response('This is not ajax.', 400);
        }
    }
    

    form.html.twig:

    
    

提交回复
热议问题