Symfony 形成与外国实体的隐藏关系
Symfony form hidden relation to foreign entity
我正在尝试在 symfony 3 中创建一个表单。它有一个隐藏字段用于与另一个实体的关系。它被定义为
$builder->add('course', HiddenType::class, array('property_path' => 'course.id'))
当我提交表单时这样做,我得到一个错误,因为 id 属性 不可见并且显然没有 setter。
Could not determine access type for property "id".
我该怎么办?为 id 添加 setter 可能不是一个好主意。默认情况下 none 是有原因的。除 id 之外的其他字段不是唯一的,因此我不能使用其中任何一个。
我想一个选项可能是自定义类型,它在数据库中查询引用实体。但是对于这个相当标准的用例有更简单的方法吗?
编辑
好吧,显然我的问题被误解了。所以我会解释得更好。这与教义无关。我的数据模型很好,该字段是一个适当的关系,而不是别的东西。问题仅与 Symfony Form 组件有关,特别是 HiddenField
似乎默认无法处理关系。首先,它会在显示表单 Cannot serialize type Model to string
时导致错误,我可以使用用于显示表单的 property_path
指令来解决。但是一旦提交,它就无法创建相关实体,因为它无法设置相关学说实体的 id 属性(参见 property_path
)。
一个有效的解决方案是使用 DataTransformerInterface
class 而不是 属性 路径。但是必须为每个需要的实体实施一个。所以我想知道是否有更简单的解决方案,因为在我看来它是一个非常标准的用例。
这是我所做的:
我在现场使用了 Symfony\Component\Form\DataTransformerInterface
来序列化模型,然后在表单传输时通过学说从数据库中再次加载它。可能不是每个人在任何情况下都想要的,也意味着表单需要实体管理器作为一个选项。
形式
/**
* Some form
*/
class SomeType extends AbstractType
{
// Configure
public function configureOptions(OptionsResolver $resolver) {
[...]
$resolver->setRequired('entity_manager');
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('course', HiddenType::class);
[...]
$builder->get('course')
->addModelTransformer(new CourseTransformer($options['entity_manager']));
}
}
这是 CourseTransformer
class CourseTransformer implements DataTransformerInterface
{
// The object manager
private $manager;
//Constructor
public function __construct(ObjectManager $manager) {
$this->manager = $manager;
}
/**
* Transforms an object (course) to a string (id).
*/
public function transform($course)
{
if (null === $course) return '';
return $course->getId();
}
/**
* Transforms a string (id) to an object (course).
*/
public function reverseTransform($courseId)
{
// no course id? It's optional, so that's ok
if (!$courseId) {
return;
}
$course = $this->manager
->getRepository('MyBundle:Course')
// query for the issue with this id
->find($courseId)
;
if (null === $course) {
// causes a validation error
// this message is not shown to the user
throw new TransformationFailedException(sprintf(
'An course with id "%s" does not exist!',
$courseId
));
}
return $course;
}
}
Symfony 4 方法
您需要为您的实体创建一个 DataTransformer class,此 class 将告诉 Symfony 在将实体呈现为字符串(例如作为隐藏输入)时如何序列化您的实体。
我是这样做的:
首先,我在 "Form" 文件夹中创建了一个文件夹 "DataTransformer",并在其中创建了我的实体 DataTransformer class。
您的 class 必须实现 DataTransformerInterface 和两个方法:transform 和 reverseTransform。您可以在接口 class.
的 PHPDoc 中阅读有关这些方法的更多信息
这是 DataTransformer 的工作示例 class。
<?php
namespace App\Form\DataTransformer;
use App\Repository\CompetitionRepository;
use Symfony\Component\Form\DataTransformerInterface;
class CompetitionTransformer implements DataTransformerInterface
{
private $repository;
public function __construct(CompetitionRepository $repository) {
$this->repository = $repository;
}
/**
* {@inheritdoc}
*/
public function transform($competition): ?int
{
return ( $competition !== null ) ? $competition->getId() : null;
}
/**
* {@inheritdoc}
*/
public function reverseTransform($competitionId)
{
if ('' === $competitionId || null === $competitionId) {
return '';
}
$competition = $this->repository->find( $competitionId );
return $competition;
}
}
您将在表单中使用 DataTransformer class。
class EventType extends AbstractType
{
[...]
private $competitionRepository;
public function __construct(CompetitionRepository $competitionRepository)
{
$this->competitionRepository = $competitionRepository;
}
[...]
public function buildForm(FormBuilderInterface $builder, array $options)
{
[...]
// This is how you use your DataTransformer class
$builder->add('competition', HiddenType::class);
$builder->get('competition')->addModelTransformer(new CompetitionTransformer( $this->competitionRepository ));
}
[...]
}
我正在尝试在 symfony 3 中创建一个表单。它有一个隐藏字段用于与另一个实体的关系。它被定义为
$builder->add('course', HiddenType::class, array('property_path' => 'course.id'))
当我提交表单时这样做,我得到一个错误,因为 id 属性 不可见并且显然没有 setter。
Could not determine access type for property "id".
我该怎么办?为 id 添加 setter 可能不是一个好主意。默认情况下 none 是有原因的。除 id 之外的其他字段不是唯一的,因此我不能使用其中任何一个。
我想一个选项可能是自定义类型,它在数据库中查询引用实体。但是对于这个相当标准的用例有更简单的方法吗?
编辑
好吧,显然我的问题被误解了。所以我会解释得更好。这与教义无关。我的数据模型很好,该字段是一个适当的关系,而不是别的东西。问题仅与 Symfony Form 组件有关,特别是 HiddenField
似乎默认无法处理关系。首先,它会在显示表单 Cannot serialize type Model to string
时导致错误,我可以使用用于显示表单的 property_path
指令来解决。但是一旦提交,它就无法创建相关实体,因为它无法设置相关学说实体的 id 属性(参见 property_path
)。
一个有效的解决方案是使用 DataTransformerInterface
class 而不是 属性 路径。但是必须为每个需要的实体实施一个。所以我想知道是否有更简单的解决方案,因为在我看来它是一个非常标准的用例。
这是我所做的:
我在现场使用了 Symfony\Component\Form\DataTransformerInterface
来序列化模型,然后在表单传输时通过学说从数据库中再次加载它。可能不是每个人在任何情况下都想要的,也意味着表单需要实体管理器作为一个选项。
形式
/**
* Some form
*/
class SomeType extends AbstractType
{
// Configure
public function configureOptions(OptionsResolver $resolver) {
[...]
$resolver->setRequired('entity_manager');
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('course', HiddenType::class);
[...]
$builder->get('course')
->addModelTransformer(new CourseTransformer($options['entity_manager']));
}
}
这是 CourseTransformer
class CourseTransformer implements DataTransformerInterface
{
// The object manager
private $manager;
//Constructor
public function __construct(ObjectManager $manager) {
$this->manager = $manager;
}
/**
* Transforms an object (course) to a string (id).
*/
public function transform($course)
{
if (null === $course) return '';
return $course->getId();
}
/**
* Transforms a string (id) to an object (course).
*/
public function reverseTransform($courseId)
{
// no course id? It's optional, so that's ok
if (!$courseId) {
return;
}
$course = $this->manager
->getRepository('MyBundle:Course')
// query for the issue with this id
->find($courseId)
;
if (null === $course) {
// causes a validation error
// this message is not shown to the user
throw new TransformationFailedException(sprintf(
'An course with id "%s" does not exist!',
$courseId
));
}
return $course;
}
}
Symfony 4 方法
您需要为您的实体创建一个 DataTransformer class,此 class 将告诉 Symfony 在将实体呈现为字符串(例如作为隐藏输入)时如何序列化您的实体。
我是这样做的:
首先,我在 "Form" 文件夹中创建了一个文件夹 "DataTransformer",并在其中创建了我的实体 DataTransformer class。
您的 class 必须实现 DataTransformerInterface 和两个方法:transform 和 reverseTransform。您可以在接口 class.
的 PHPDoc 中阅读有关这些方法的更多信息这是 DataTransformer 的工作示例 class。
<?php
namespace App\Form\DataTransformer;
use App\Repository\CompetitionRepository;
use Symfony\Component\Form\DataTransformerInterface;
class CompetitionTransformer implements DataTransformerInterface
{
private $repository;
public function __construct(CompetitionRepository $repository) {
$this->repository = $repository;
}
/**
* {@inheritdoc}
*/
public function transform($competition): ?int
{
return ( $competition !== null ) ? $competition->getId() : null;
}
/**
* {@inheritdoc}
*/
public function reverseTransform($competitionId)
{
if ('' === $competitionId || null === $competitionId) {
return '';
}
$competition = $this->repository->find( $competitionId );
return $competition;
}
}
您将在表单中使用 DataTransformer class。
class EventType extends AbstractType
{
[...]
private $competitionRepository;
public function __construct(CompetitionRepository $competitionRepository)
{
$this->competitionRepository = $competitionRepository;
}
[...]
public function buildForm(FormBuilderInterface $builder, array $options)
{
[...]
// This is how you use your DataTransformer class
$builder->add('competition', HiddenType::class);
$builder->get('competition')->addModelTransformer(new CompetitionTransformer( $this->competitionRepository ));
}
[...]
}