Forms Symfony表格与外部实体的隐藏关系
我正在尝试在symfony3中创建一个表单。它有一个隐藏字段,用于表示与另一个实体的关系。它被定义为Forms Symfony表格与外部实体的隐藏关系,forms,symfony,symfony-3.1,Forms,Symfony,Symfony 3.1,我正在尝试在symfony3中创建一个表单。它有一个隐藏字段,用于表示与另一个实体的关系。它被定义为 $builder->add('course', HiddenType::class, array('property_path' => 'course.id')) 当我提交表单时,会出现一个错误,因为id属性不可见,而且显然没有setter Could not determine access type for property "id". 我该怎么办?为id添加setter可能
$builder->add('course', HiddenType::class, array('property_path' => 'course.id'))
当我提交表单时,会出现一个错误,因为id属性不可见,而且显然没有setter
Could not determine access type for property "id".
我该怎么办?为id添加setter可能不是一个好主意。默认情况下没有的原因是存在的。id以外的其他字段不是唯一的,因此我不能使用其中任何字段
我猜其中一个选项可能是自定义类型,它在数据库中查询引用实体。但是对于这个非常标准的用例,有没有更简单的方法呢
编辑
很明显我的问题被误解了。所以我会解释得更好。这与教义无关。我的数据模型很好,字段是正确的关系,而不是其他关系。问题只与Symfony表单组件有关,特别是HiddenField在默认情况下似乎无法处理关系。首先,它会在显示表单时导致一个错误,无法将类型模型序列化为字符串,我可以使用用于显示表单的property_path指令来解决这个问题。但一旦提交,它就无法创建相关实体,因为它无法设置id属性,请查看相关实体的属性路径
一个有效的解决方案是使用DataTransformerInterface类,而不是属性路径之类的东西。但我们必须为每一个需要的实体实施一个。所以我想知道是否有一个更简单的解决方案,因为在我看来这是一个非常标准的用例 以下是我所做的:
我在字段中使用了Symfony\Component\Form\DataTransformerInterface来序列化模型,然后在表单传输时通过doctrine从数据库再次加载它。可能不是每个人在任何情况下都想要的,这也意味着表单需要实体管理器作为选项
在形式上
/**
* 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']));
}
}
这是课程转换器
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\Component\Form\DataTransformerInterface来序列化模型,然后在表单传输时通过doctrine从数据库再次加载它。可能不是每个人在任何情况下都想要的,这也意味着表单需要实体管理器作为选项
在形式上
/**
* 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']));
}
}
这是课程转换器
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类,该类将告诉Symfony在将实体呈现为字符串(例如作为隐藏输入)时如何序列化实体
我就是这样做的:
首先,我在表单文件夹中创建一个文件夹DataTransformer,并在其中创建实体DataTransformer类
类必须实现DataTransformerInterface和两个方法:transform和reverseTransform。您可以在接口类的PHPDoc中阅读有关这些方法的更多信息
这是DataTransformer类的一个工作示例
<?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;
}
}
Symfony 4进近
您需要为您的实体创建DataTransformer类,该类将告诉Symfony在将实体呈现为字符串(例如作为隐藏输入)时如何序列化实体
我就是这样做的:
首先,我在表单文件夹中创建一个文件夹DataTransformer,并在其中创建实体DataTransformer类
类必须实现DataTransformerInterface和两个方法:transform和reverseTransform。您可以在接口类的PHPDoc中阅读有关这些方法的更多信息
这是DataTransformer类的一个工作示例
<?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;
}
}
可能重复使用属性路径的原因?字段“course”应该映射到其他实体-然后隐藏字段中的值将是该外部实体的ID。@AndrzejPiszczek可能这就是我在文档中遗漏的内容。有这样的选择吗?目前我正在使用一个自定义transformerread。这里有关于实体连接的信息。好吧,那么你误解我了。理论联系很好,并且正在发挥作用。我只是不知道表单组件是如何工作的,顺便说一句,但我想知道是否有一个更简单的解决方案可能重复您为什么要使用property_path?字段“course”应该映射到其他实体-然后隐藏字段中的值将是该外部实体的ID。@AndrzejPiszczek可能这就是我在文档中遗漏的内容。有这样的选择吗?目前我正在使用一个自定义transformerread。这里有关于实体连接的信息。好吧,那么你误解我了。理论联系很好,并且正在发挥作用。我只是不知道表单组件是如何工作的,顺便说一句,但我想知道是否有一个更简单的解决方案