symfony集合中的实体主键

时间:2016-03-31 19:04:17

标签: php forms doctrine-orm symfony

我正在学习symfony 3& doctrine和我创建了一个带有实体集合的表单。实体是Post和具有许多关系的标签。主要表单是Post和标签集合。 我想只传递我的集合中标签的ID(主键)。结果我只有一个标签形式的字段:

$builder->add('tagId');

我为它创建了自动完成功能,这就是为什么我只需要主键。 保存表单后,doctrine创建了带有传递ID的新标签实体,但我希望找到这些实体而不是创建新实体。不知道......

我试图让它在我的控制器内工作:

$formTags = $form->get('tag');
foreach ($formTags->getData() as $key => $formTag)
{
    // here i have new entities with id ;/
    if($formTag->getTagId())
    {
    // so i tryied to find them, and replace it
        $formTags->offsetSet($key, 
            array($this->getDoctrine()->getRepository('BlogBundle:Tag')
                          ->find($formTag->getTagId())));
    }
}

但是symfony也会使用setData方法抛出异常。提交表单后无法更改。我希望你们能帮助我!

我正在尝试制作数据转换器。忘了提:)问题是我的变换器将tagId字段更改为标记对象。结果我有标签对象与新实体,而不是tagId值 - 里面有另一个对象,转换。所以不要像我预期的那样工作。我想我应该为收集领域而不是标签id制作变换器,但不知道如何使其工作。我试图在集合中创建“tag”字段并对其进行转换,但是doctrine总是尝试根据字段从实体获取值,因此找不到getTag()方法:)

2 个答案:

答案 0 :(得分:1)

您可以在TagType中使用Symfony DataTransfomer将tagId转换为标记实体。

来自Symfony DataTransformer docs

  

数据转换器用于将字段的数据转换为可以在表单中显示的格式(并在提交时返回)。

     

...

     

假设您具有从Task实体到Issue实体的多对一关系(即每个Task都有一个与其相关问题的可选外键)。添加包含所有可能问题的列表框最终可能会很长并且需要很长时间才能加载。相反,您决定要添加文本框,用户只需输入问题编号即可。

答案 1 :(得分:1)

我做到了。对于数据变换器,我们需要制作变换器用于收集,而不是用于集合内的字段。

所以看起来像那样(有效!)。

我的PostType.php表单需要有实体管理器(如内部文档,关于数据转换器)和数据转换器的集合,所以我补充说:

# PostType.php form
namespace BlogBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use BlogBundle\Form\DataTransformer\TagToIdTransformer;
use Doctrine\Common\Persistence\ObjectManager;
class PostType extends AbstractType
{
private $manager;

public function __construct(ObjectManager $manager)
{
    // needed for transformer :( 
    // and we need to register service inside app config for this. Details below
    $this->manager = $manager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('tag', CollectionType::class, array(
        'entry_type' => TagType::class,
        'by_reference' => false,
        'allow_add'    => true,
    ))
        ->add('save', SubmitType::class, array('label' => 'Save'));
    $builder->get('tag')
        ->addModelTransformer(new TagToIdTransformer($this->manager));
}
}

构造函数将抛出异常,我们需要将ObjectManager传递给它。要制作它,请修改捆绑包中的配置文件:

# src/BlogBundle/Resources/config/services.yml
services:
    blog.form.type.tag:
        class: BlogBundle\Form\PostType
        arguments: ["@doctrine.orm.entity_manager"]
        tags:
            - { name: form.type }

现在让我们为集合制作变换器!之前我做错了,因为我试图在内部文档中做一个字段。对于集合,我们需要转换整个标记数组(其manyToMany集合):

<?php
namespace BlogBundle\Form\DataTransformer;

use BlogBundle\Entity\Tag;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;

class TagToIdTransformer implements DataTransformerInterface
{
    private $manager;

    public function __construct(ObjectManager $manager)
    {
        $this->manager = $manager;
    }

    /**
     * Transforms array of objects (Tag) to an array of string (number).
     *
     * @param  array|null $tags
     * @return string
     */
    public function transform($tags)
    {
        $result = array();

        if (null === $tags) {
            return null;
        }
        foreach ($tags as $tag)
        {
            $result[] = $tag->getTagId();
        }

        return $result;
    }

    /**
     * Transforms an array of strings (numbers) to an array of objects (Tag).
     *
     * @param  string $tagsId
     * @return Tag|null
     * @throws TransformationFailedException if object (Tag) is not found.
     */
    public function reverseTransform($tagsId)
    {
        // no issue number? It's optional, so that's ok
        if (!$tagsId) {
            return;
        }
        $result = array();
        $repository = $this->manager
            ->getRepository('BlogBundle:Tag');
        foreach ($tagsId as $tagId) {
            $tag = $repository->find($tagId);
            if (null === $tag) {
                // causes a validation error
                // this message is not shown to the user
                // see the invalid_message option
                throw new TransformationFailedException(sprintf(
                    'An tag with id "%s" does not exist!',
                    $tagId
                ));
            }
            $result[] = $tag;
        }
        return $result;
    }
}

现在一切正常。我可以使用仅填充标签ID的自动填充功能轻松保存我的实体