长话短说,在Symfony 2.8中,我Movie
实体actors
字段,它是实体Actor
(ManyToMany
)的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 调用值,因此它不再将其识别为对象,而是文本值。
例子:
- Symfony2 - DTO的使用
- 具有 jQuery 自动完成功能的表单
正确的方法不是数据转换器,而是表单事件,请看这里:http://symfony.com/doc/current/form/dynamic_form_modification.html#form-events-submitted-data
在示例中,您有野外运动(一个实体,如您的Movie
)和野外位置(另一个实体,如actors
)。诀窍是使用 ajax 来完全重新加载表单并使用 PRE_SET_DATA
和POST_SUBMIT
.
我正在使用Symfony 3.x,但我认为它与2.8.x相同
当您添加数据转换器并且似乎没有任何变化时,听起来数据永远不会通过您的数据转换器。在调用新的数据转换器之前,转换可能会失败。尝试在代码中添加几行:
$builder->get('actors')->resetViewTransformers();
$builder->get('actors')->resetModelTransformers();
// and then add your own