“无法反转属性路径的值”,用于 Select2 上的 Symfony2 表单 ChoiceType 字段


"Unable to reverse value for property path" for Symfony2 form ChoiceType field on Select2

长话短说,在Symfony 2.8中,我Movie实体actors字段,它是实体ActorManyToMany)的ArrayCollection,我希望该字段是ajax加载的Select2。当我不使用 Ajax 时,形式是:

->add('actors', EntityType::class, array(
        'class' => Actor::class,
        'label' => "Actors of the work",
        'multiple' => true,
        'attr' => array(
          'class' => "select2-select",
         ),
       ))

它有效

我试图在那里放一个空的选择字段:

->add('actors', ChoiceType::class, array(
    'mapped' => false,
    'multiple' => true,
    'attr'=>array(
        'class' => "select2-ajax",
        'data-entity'=>"actor"
    )
))

Select2 Ajax 工作,DOM 中的所有内容看起来都与前面的示例相同,但在表单提交时,我在分析器中收到错误: This value is not valid.

Symfony'Component'Validator'ConstraintViolation
Object(Symfony'Component'Form'Form).children[actors] = [0 => 20, 1 => 21]
Caused by:
Symfony'Component'Form'Exception'TransformationFailedException
Unable to reverse value for property path "actors": Could not find all matching choices for the given values
Caused by:
Symfony'Component'Form'Exception'TransformationFailedException
Could not find all matching choices for the given values

有趣的是,收到的数据与EntityType时相同:[0 => 20, 1 => 21]

我将字段标记为未映射,我什至将字段名称更改为电影实体的字段名称以外的字段名称。我尝试添加空choices,我试图将其保留为EntityType但使用自定义query_builder,返回空集合。现在我没主意了。

我应该怎么做?

在雷蒙德的回答之后编辑

我添加了DataTransformer:

use Doctrine'Common'Persistence'ObjectManager;
use CompanyName'Common'CommonBundle'Entity'Actor;
use Symfony'Component'Form'DataTransformerInterface;
use Symfony'Component'Form'Exception'TransformationFailedException;
class ActorToNumberTransformer implements DataTransformerInterface
{
    private $manager;
    public function __construct(ObjectManager $objectManager)
    {
        $this->manager = $objectManager;
    }
    public function transform($actors)
    {
        if(null === $actors)
            return array();
        $actorIds = array();
        foreach($actors as $actor)
            $actorIds[] = $actor->getId();
        return $actorIds;
    }
    public function reverseTransform($actorIds)
    {
        if($actorIds === null)
            return array();
        foreach($actorIds as $actorId)
        {
            $actor = $this->manager->getRepository('CommonBundle:Actor')->find($actorId);
            if(null === $actor)
                throw new TransformationFailedException(sprintf('An actor with id "%s" does not exist!', $actorId));
            $actors[] = $actor;
        }
        return $actors;
    }
}

MovieType buildForm()末尾添加了它:

$builder->get('actors')
    ->addModelTransformer(new ActorToNumberTransformer($this->manager));
$builder->get('actors')
    ->addViewTransformer(new ActorToNumberTransformer($this->manager));

并增加服务:

common.form.type.work:
    class: CompanyName'Common'CommonBundle'Form'Type'MovieType
    arguments: ["@doctrine.orm.entity_manager"]
    tags:
        - { name: form.type }

什么都没有改变。在表单提交时,reverseTransform()获取正确的数据,但探查器显示相同的错误。现在对我来说是一个很大的迷雾...

您需要添加一个 DTO(数据转换器)来转换从表单接收的值并返回相应的对象。由于您从 Ajax 调用值,因此它不再将其识别为对象,而是文本值。

例子:

  1. Symfony2 - DTO的使用
  2. 具有 jQuery 自动完成功能的表单

正确的方法不是数据转换器,而是表单事件,请看这里:http://symfony.com/doc/current/form/dynamic_form_modification.html#form-events-submitted-data

在示例中,您有野外运动(一个实体,如您的Movie)和野外位置(另一个实体,如actors)。诀窍是使用 ajax 来完全重新加载表单并使用 PRE_SET_DATAPOST_SUBMIT .

我正在使用Symfony 3.x,但我认为它与2.8.x相同

当您添加数据转换器并且似乎没有任何变化时,听起来数据永远不会通过您的数据转换器。在调用新的数据转换器之前,转换可能会失败。尝试在代码中添加几行:

$builder->get('actors')->resetViewTransformers();
$builder->get('actors')->resetModelTransformers();
// and then add your own