具有 OneToOne 关系的动态嵌入表单
Dynamic embedded form with OneToOne relationship
我正在尝试为带有插件(招标)的文章创建表单。
文章与插件是一对一的关系,插件可以被禁用(null)。
如果带有插件的复选框被选中,则需要验证插件,然后与文章一起提交。
我遇到的问题是,我无法在提交前将插件设置为 null,是什么导致了错误 - 表单仍然尝试提交与文章相关的插件,而它的值可以'不能为空。
如何在复选框未选中时禁用插件并仍然将文章提交到数据库,但没有插件?
我曾尝试使用表单事件来修改事件的数据,但事实证明在 PRE_SUBMIT 期间 tender 不是数据的一部分。
如果我尝试在 SUBMIT 期间修改数据,那么我必须更改实体方法中的逻辑,但感觉不对,还会导致一些我不记得且无法解决的问题。
我也尝试过使用 'empty_data' => null,认为它会完全按照我的要求行事,但事实证明它对我的表格根本没有影响。
文章实体:
<?php
namespace App\Entity;
use App\Repository\ContentsRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=ContentsRepository::class)
*/
class Contents
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\OneToOne(targetEntity=ContentsTenders::class, mappedBy="content", cascade={"persist", "remove"})
*/
private $tender;
public function getId(): ?int
{
return $this->id;
}
public function getPosition(): ?int
{
return $this->position;
}
public function getTender(): ?ContentsTenders
{
return $this->tender;
}
public function setTender(ContentsTenders $tender): self
{
$this->tender = $tender;
// set the owning side of the relation if necessary
if ($tender->getContent() !== $this) {
$tender->setContent($this);
}
return $this;
}
}
插件的实体:
<?php
namespace App\Entity;
use App\Repository\ContentsTendersRepository;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=ContentsTendersRepository::class)
*/
class ContentsTenders
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\OneToOne(targetEntity=Contents::class, inversedBy="tender", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=false)
*/
private $content;
public function getId(): ?int
{
return $this->id;
}
public function getContent(): ?Contents
{
return $this->content;
}
public function setContent(Contents $content): self
{
$this->content = $content;
return $this;
}
}
文章形式:
class ContentsType extends AbstractType
{
//public function __construct(EntityManagerInterface $em, UserInterface $user)
//{
// $this->em = $em;
// $this->user = $user;
//}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('isTender', CheckboxType::class, [
'mapped' => false,
'required' => false,
'label' => 'Przetarg',
])
->add('tender', NewTendersType::class, [
'required' => false,
'constraints' => array(new Valid()),
'empty_data' => null
])
->add('save', SubmitType::class, [
'label' => 'Zapisz',
'attr' => ['class' => 'save'],
])
;
$builder->addEventListener(
FormEvents::SUBMIT,
function (FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
if(!$form['isTender']->getData()){
//
}
}
);
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Contents::Class,
'accessible_ids' => [],
]);
}
}
@编辑
我用过:
并添加:
class NullableTenderTransformer implements DataTransformerInterface
{
public function transform($value)
{
return $value;
}
public function reverseTransform($data)
{
if($data->getTender()->getTenContracting() === null
&& $data->getTender()->getTenOrderFor() === null
&& $data->getTender()->getTenNumber() === null) {
$data->resetTender();
}
return $data;
}
}
结合下面的答案和控制器中的$content->setTender(new ContentsTenders());
,+模型中的重置方法,它有效。
不过,这可能不是一个完美的解决方案。
您可以使用验证组
'constraints' => array(new Valid(['groups' => "withTender")
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Contents::Class,
'accessible_ids' => [],
'validation_groups' => function (FormInterface $form): array {
$data = $form->getData();
$groups = ['Default'];
if ($data->isTender) {
$groups[] = 'withTender';
}
return $groups;
}
]);
}
我正在尝试为带有插件(招标)的文章创建表单。
文章与插件是一对一的关系,插件可以被禁用(null)。
如果带有插件的复选框被选中,则需要验证插件,然后与文章一起提交。
我遇到的问题是,我无法在提交前将插件设置为 null,是什么导致了错误 - 表单仍然尝试提交与文章相关的插件,而它的值可以'不能为空。
如何在复选框未选中时禁用插件并仍然将文章提交到数据库,但没有插件?
我曾尝试使用表单事件来修改事件的数据,但事实证明在 PRE_SUBMIT 期间 tender 不是数据的一部分。 如果我尝试在 SUBMIT 期间修改数据,那么我必须更改实体方法中的逻辑,但感觉不对,还会导致一些我不记得且无法解决的问题。 我也尝试过使用 'empty_data' => null,认为它会完全按照我的要求行事,但事实证明它对我的表格根本没有影响。
文章实体:
<?php
namespace App\Entity;
use App\Repository\ContentsRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=ContentsRepository::class)
*/
class Contents
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\OneToOne(targetEntity=ContentsTenders::class, mappedBy="content", cascade={"persist", "remove"})
*/
private $tender;
public function getId(): ?int
{
return $this->id;
}
public function getPosition(): ?int
{
return $this->position;
}
public function getTender(): ?ContentsTenders
{
return $this->tender;
}
public function setTender(ContentsTenders $tender): self
{
$this->tender = $tender;
// set the owning side of the relation if necessary
if ($tender->getContent() !== $this) {
$tender->setContent($this);
}
return $this;
}
}
插件的实体:
<?php
namespace App\Entity;
use App\Repository\ContentsTendersRepository;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=ContentsTendersRepository::class)
*/
class ContentsTenders
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\OneToOne(targetEntity=Contents::class, inversedBy="tender", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=false)
*/
private $content;
public function getId(): ?int
{
return $this->id;
}
public function getContent(): ?Contents
{
return $this->content;
}
public function setContent(Contents $content): self
{
$this->content = $content;
return $this;
}
}
文章形式:
class ContentsType extends AbstractType
{
//public function __construct(EntityManagerInterface $em, UserInterface $user)
//{
// $this->em = $em;
// $this->user = $user;
//}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('isTender', CheckboxType::class, [
'mapped' => false,
'required' => false,
'label' => 'Przetarg',
])
->add('tender', NewTendersType::class, [
'required' => false,
'constraints' => array(new Valid()),
'empty_data' => null
])
->add('save', SubmitType::class, [
'label' => 'Zapisz',
'attr' => ['class' => 'save'],
])
;
$builder->addEventListener(
FormEvents::SUBMIT,
function (FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
if(!$form['isTender']->getData()){
//
}
}
);
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Contents::Class,
'accessible_ids' => [],
]);
}
}
@编辑
我用过:
并添加:
class NullableTenderTransformer implements DataTransformerInterface
{
public function transform($value)
{
return $value;
}
public function reverseTransform($data)
{
if($data->getTender()->getTenContracting() === null
&& $data->getTender()->getTenOrderFor() === null
&& $data->getTender()->getTenNumber() === null) {
$data->resetTender();
}
return $data;
}
}
结合下面的答案和控制器中的$content->setTender(new ContentsTenders());
,+模型中的重置方法,它有效。
不过,这可能不是一个完美的解决方案。
您可以使用验证组
'constraints' => array(new Valid(['groups' => "withTender")
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Contents::Class,
'accessible_ids' => [],
'validation_groups' => function (FormInterface $form): array {
$data = $form->getData();
$groups = ['Default'];
if ($data->isTender) {
$groups[] = 'withTender';
}
return $groups;
}
]);
}