总是这样吗?我已经在网上搜索并阅读了文档,但不是更明智的。我确实读过,当 inherit_data 为真时,不能应用DataTransformers,这似乎也是一种耻辱。 (可能是什么原因?)
我有一个FormType ' PermissionType' ,用于映射'权限' 。 权限和其他一些实体一样,还有 creation / lastModification DateTime 。阅读How to Reduce Code Duplication with "inherit_data"后,我自然而然地继续实施新发现的好建议并创建了 TimeTrackedType 。
此子窗体到PermissionType显示两个DateTimeType字段,inherit_data
设置为true
。它们被正确呈现给浏览器,但它们仍然是空的,但我尝试将数据输入它们。我开始时添加了一个DataMapper,但没有调用TimeTrackedType。然而,它的父PermissionType的DataMapper本身就是一个子表单,而且这似乎是我可以更改TimeTrackedType的DateTimeType字段值的唯一地方。
我希望我在这里做错了,因为在子表单中创建输入但在父类中必须映射到它们似乎是错误的。任何人都可以详细说明这个吗?任何指针都非常感谢。
以下是实体,第一位用户:
/**
* @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
*/
class User implements AdvancedUserInterface, \Serializable {
use HasSingleId, TimeTrackedEntityTrait, EntityCreatorTrait;
// ^^^ This trait has two DateTime fields and that's it.
// (...)
/**
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Permission", mappedBy="user")
* @Assert\Valid()
*/
private $permissions;
// (...)
}
然后许可:
/**
* @ORM\Entity(repositoryClass="AppBundle\Repository\PermissionRepository")
*/
class Permission {
use TimeTrackedEntityTrait, EntityCreatorTrait;
/**
* @var User
* @ORM\Id
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="permissions")
*/
private $user;
/**
* @var array
* @ORM\Id
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Role", inversedBy="permissions")
*/
private $role;
// (...getters and setters...)
}
最后一级角色:
/**
* @ORM\Entity(repositoryClass="AppBundle\Repository\RoleRepository")
*/
class Role implements RoleInterface {
use HasSingleId, TimeTrackedEntityTrait, EntityCreatorTrait;
/**
* @var type string
* @ORM\Column(type="string", nullable=false, unique=true);
*/
private $name;
/**
* @var type ArrayCollection
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Permission", mappedBy="role")
* @Assert\Valid()
*/
private $permissions;
}
现在FormTypes:
class UserType extends AbstractType {
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('username', TextType::class, [ 'attr' => [ 'size' => 10 ] ] )
->add('password', RepeatedType::class, [
'type' => PasswordType::class,
'attr' => ['size' => 10 ],
'first_options' => [ 'label' => 'Password' ],
'second_options' => [ 'label' => 'Confirm' ] ]);
$entity = $builder->getData();
$admin = $entity->hasRole('ROLE_ADMIN');
if($admin) {
$builder->add('id', TextType::class, [ 'attr' => [ 'size' => 4 ] ]);
$builder->add('isEnabled', CheckboxType::class, [ 'required' => false ]);
}
$builder->add('permissions', CollectionType::class, [
'data_class' => 'Doctrine\ORM\PersistentCollection',
'mapped'=>true,
'prototype'=>true,
'allow_add'=>true,
'allow_delete'=>true,
'entry_type' => PermissionType::class]);
$builder->add('email', EmailType::class);
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'required' => true,
'mapped' => true,
'data_class' => 'AppBundle\Entity\User'
]);
}
}
...和...
class PermissionType extends AbstractType implements DataMapperInterface {
public function mapDataToForms($permission, $forms) {
$forms = iterator_to_array($forms);
if($permission instanceof Permission && $permission) {
$forms['role']->setData($permission->getRole()->getName());
// These two statements get the job done, but not as was intended.
$forms['created']->setData($permission->getCreated());
$forms['lastModified']->setData($permission->getLastModified());
}
}
public function mapFormsToData($forms, &$permission) {
$forms = iterator_to_array($forms);
if($permission instanceof Permission) {
$permission->setCreated($forms['created']->getData());
$permission->setLastModified($forms['lastModified']->getData());
}
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->setDataMapper($this);
$builder->add('role', TextType::class, [ 'mapped' => true ]);
$builder->add('timing', TimeTrackedEntityType::class, [
'data_class' => 'AppBundle\Entity\Permission',
'inherit_data' => true, 'mapped'=>true ]);
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Permission',
'mapped'=>true,
'compound'=>true,
));
}
public function getParent() {
return FormType::class;
}
public function getName() { return 'PermissionType'; }
}
......最后:
class TimeTrackedEntityType extends AbstractType implements DataMapperInterface {
// This is the method that doesn't get called
public function mapDataToForms($permission, $forms) {
$forms = iterator_to_array($forms);
$forms['created']->setData($permission->getCreated()->format("d/m/Y H:i:s"));
$forms['lastModified']->setData($permission->getLastModified()->format("d/m/Y H:i:s"));
}
public function mapFormsToData($forms, &$data) {
$forms = iterator_to_array($forms);
$data->setCreated($forms['created']->getData());
$data->setLastModified($forms['lastModified']->getData());
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->setDataMapper($this);
$builder->add('created', DateTimeType::class, [
'format' => 'd/M/Y H:i:s',
'input' => 'datetime',
'widget' => 'single_text',
'attr'=>['size'=>14, 'class'=>'right'],
'mapped' => true ]);
$builder->add('lastModified', DateTimeType::class, [
'format' => 'd/M/Y H:i:s',
'input' => 'datetime',
'widget' => 'single_text',
'attr'=>['size'=>14, 'class'=>'right'],
'mapped' => true ]);
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'mapped'=>true,
'compound'=>true,
'inherit_data' => true,
));
}
public function getName() { return 'TimeTrackedEntityType'; }
}
答案 0 :(得分:0)
该文章根本不使用DataMapper
。
使用特征意味着属性是正常的PermissionEntity
对象的一部分,因此它们不是像对应的PermissionType
形式中的其他字段那样保存这些属性,而是嵌套在子表单类型中TimeTrackedEntityType
。
然后,您只需要将inherit_data
设置为true
和右data_class
选项,如果您需要此子表单,其他地方,以及您已经在{ {1}},因为子表单获取其父表单的数据,因此不需要TimeTrackedEntityType
。
如果你想使用一个,它应该只有父表单而不是它的子表单,它会被按预期忽略。