Symfony 4.1:动态多对多实体类型
Symfony 4.1 : Dynamic ManyToMany EntityType
我有一个带有 ManyToMany 字段的实体,使用 EntityType 呈现并且选择仅限于现有 links :
实体示例:
/**
* @var House[]|ArrayCollection
*
* @ORM\ManyToMany(targetEntity=House::class, fetch="LAZY")
* @ORM\JoinTable(name="city_house")
*/
private $houses;
/**
* constructor.
*/
public function __construct()
{
$this->houses = new ArrayCollection();
}
public function addHouse(House $house)
{
if ($this->houses->contains($house)) {
return $this;
}
$this->houses[] = $house;
return $this;
}
public function removeHouse(House $house): bool
{
if (!$this->houses->contains($house)) {
return true;
}
return $this->houses->removeElement($house);
}
/**
* Get brands.
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getBrands(): ?Collection
{
return $this->brands;
}
还有我的 formBuilder :
$builder
->add('houseTypes', EntityType::class, [
'multiple' => false,
'required' => false,
'mapped' => false,
'class' => HouseType::class,
])
->add('houses', EntityType::class, [
'multiple' => true,
'required' => false,
'class' => House::class,
'by_reference' => false,
'choices' => $builder->getData()->getHouses(),
])
我使用 multiselect js 在房屋 EntityType 中添加过滤房屋(按类型)。
JS 部分运行良好,它向 select 添加选项 link 这个
<option value="6">House (type)</option>
当我从这个列表中删除元素时,symfony 会很好地删除 link。
但是当添加新元素时,formValdator 会报错。
ConstraintViolation {#3985 ▼
root: Form {#2783 …}
path: "children[houses]"
value: [▼
"57"
"3"
"2"
]
}
TransformationFailedException {#2663 ▼
#message: "Unable to reverse value for property path "houses": Could not find all matching choices for the given values"
#code: 0
#file: "/srv/vendor/symfony/form/Form.php"
#line: 1115
trace: {▶}
…1
}
TransformationFailedException {#2678 ▼
#message: "Could not find all matching choices for the given values"
#code: 0
#file: "/srv/vendor/symfony/form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php"
#line: 68
trace: {▶}
}
您知道如何解决这个问题吗?
我知道怎么做了,我们需要使用表单事件。
所以,我添加了监听器:
$builder->addEventListener(FormEvents::PRE_SET_DATA, [$this, 'onPreSetData']);
$builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'onPreSubmit']);
添加回调函数
/**
* @param FormEvent $event
*/
public function onPreSubmit(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
$brandsCollection = null;
if (isset($data['houses'])) {
$housesCollection = $this->em->getRepository(House::class)->findById($data['houses']);
}
$houses = new ArrayCollection($housesCollection ?? []);
$this->addHouse($form, $houses);
}
/**
* @param FormEvent $event
*/
public function onPreSetData(FormEvent $event)
{
$promo = $event->getData();
$form = $event->getForm();
$houses = $promo->getHouses() ? $promo->getHouses() : null;
$this->addHouse($form, $houses);
}
/**
* @param FormInterface $form
* @param Collection|null $houses
*/
protected function addHouse(FormInterface $form, Collection $houses = null)
{
$form->add('houses', EntityType::class, [
'multiple' => true,
'required' => false,
'class' => House::class,
'by_reference' => false,
'choices' => $houses,
]);
}
我有一个带有 ManyToMany 字段的实体,使用 EntityType 呈现并且选择仅限于现有 links :
实体示例:
/**
* @var House[]|ArrayCollection
*
* @ORM\ManyToMany(targetEntity=House::class, fetch="LAZY")
* @ORM\JoinTable(name="city_house")
*/
private $houses;
/**
* constructor.
*/
public function __construct()
{
$this->houses = new ArrayCollection();
}
public function addHouse(House $house)
{
if ($this->houses->contains($house)) {
return $this;
}
$this->houses[] = $house;
return $this;
}
public function removeHouse(House $house): bool
{
if (!$this->houses->contains($house)) {
return true;
}
return $this->houses->removeElement($house);
}
/**
* Get brands.
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getBrands(): ?Collection
{
return $this->brands;
}
还有我的 formBuilder :
$builder
->add('houseTypes', EntityType::class, [
'multiple' => false,
'required' => false,
'mapped' => false,
'class' => HouseType::class,
])
->add('houses', EntityType::class, [
'multiple' => true,
'required' => false,
'class' => House::class,
'by_reference' => false,
'choices' => $builder->getData()->getHouses(),
])
我使用 multiselect js 在房屋 EntityType 中添加过滤房屋(按类型)。
JS 部分运行良好,它向 select 添加选项 link 这个
<option value="6">House (type)</option>
当我从这个列表中删除元素时,symfony 会很好地删除 link。 但是当添加新元素时,formValdator 会报错。
ConstraintViolation {#3985 ▼
root: Form {#2783 …}
path: "children[houses]"
value: [▼
"57"
"3"
"2"
]
}
TransformationFailedException {#2663 ▼
#message: "Unable to reverse value for property path "houses": Could not find all matching choices for the given values"
#code: 0
#file: "/srv/vendor/symfony/form/Form.php"
#line: 1115
trace: {▶}
…1
}
TransformationFailedException {#2678 ▼
#message: "Could not find all matching choices for the given values"
#code: 0
#file: "/srv/vendor/symfony/form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php"
#line: 68
trace: {▶}
}
您知道如何解决这个问题吗?
我知道怎么做了,我们需要使用表单事件。
所以,我添加了监听器:
$builder->addEventListener(FormEvents::PRE_SET_DATA, [$this, 'onPreSetData']);
$builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'onPreSubmit']);
添加回调函数
/**
* @param FormEvent $event
*/
public function onPreSubmit(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
$brandsCollection = null;
if (isset($data['houses'])) {
$housesCollection = $this->em->getRepository(House::class)->findById($data['houses']);
}
$houses = new ArrayCollection($housesCollection ?? []);
$this->addHouse($form, $houses);
}
/**
* @param FormEvent $event
*/
public function onPreSetData(FormEvent $event)
{
$promo = $event->getData();
$form = $event->getForm();
$houses = $promo->getHouses() ? $promo->getHouses() : null;
$this->addHouse($form, $houses);
}
/**
* @param FormInterface $form
* @param Collection|null $houses
*/
protected function addHouse(FormInterface $form, Collection $houses = null)
{
$form->add('houses', EntityType::class, [
'multiple' => true,
'required' => false,
'class' => House::class,
'by_reference' => false,
'choices' => $houses,
]);
}