在 Symfony5 應用程式中,我們如何利用表單組件來正確設定自參考的多對多關系?
注意:這純粹是關于事物的形式方面,Doctrine 已經很高興了。
假設我們有一個“人”物體,這些人實體承載客人,他們也是人:
#[Entity(repositoryClass: PersonRepository::class)]
class Person
{
#[Id]
#[GeneratedValue]
#[Column(type: Types::INTEGER)]
private int $id;
#[Column(type: Types::STRING, length: 255)]
private string $firstName;
#[Column(type: Types::STRING, length: 255)]
private string $lastName;
/** @var Collection<Person> */
#[ManyToMany(targetEntity: self::class, inversedBy: 'guestsHosted')]
private Collection $hosts;
/** @var Collection<Person> */
#[ManyToMany(targetEntity: self::class, mappedBy: 'hosts')]
private Collection $guestsHosted;
public function __construct()
{
$this->fellowshipHosts = new ArrayCollection();
$this->fellowsHosted = new ArrayCollection();
}
// getters/setters ommitted for brevity
public function addHost(self $host): self
{
}
public function removeHost(self $host): self
{
}
public function addGuestsHosted(self $guestHosted): self
{
}
public function removeGuestsHosted(self $guestsHosted): self
{
}
我想要實作的是一個包含可添加/可移動行集合的表單,然后用戶可以添加一行,選擇現有的其他人作為他們的主持人,添加另一行,選擇另一個人,等等。一個簡單的樣機:
我如何使用 Symfony 的表單組件來實作這一點?由于相同表單型別的遞回,我現在在那里的內容不起作用:
class PersonType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('firstName', null, [])
->add('lastName', null, [])
->add('hosts', CollectionType::class, [
'entry_type' => self::class,
'entry_options' => ['label' => false],
'required' => false,
'allow_delete' => true,
'allow_add' => true,
'by_reference' => false,
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Person::class,
]);
}
}
NB: I've built similar UIs like this in the past and know about the little dance involving form.vars.prototype and hooking up the JS to that. Where I'm lost is how to map this association on the form-level, so that I get a dropdown of all Persons, and map that into the $hosts property of the entity.
Any help is appreciated!
uj5u.com熱心網友回復:
@Bossman 的評論非常正確,但以防萬一您想使用單一表單型別進行操作,我會這樣做:
class PersonType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('firstName', null, [])
->add('lastName', null, []);
if (!$options['is_host']) {
->add('hosts', CollectionType::class, [
'entry_type' => self::class,
'entry_options' => ['label' => false, 'is_host' => true],
'required' => false,
'allow_delete' => true,
'allow_add' => true,
'by_reference' => false,
]);
}
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Person::class,
'is_host' => false,
]);
}
}
基本上,我在這里所做的是通過將“is_host”顯式傳遞給表單選項來防止遞回,這表明這是否是一個子物體,然后我只為根物體構建“主機”表單欄位。
如果要在現有主機中進行選擇,請使用 EntityType:
class PersonType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
// You'll be able to use this later in the 'query_builder' option
$personId = $options['person_id'];
$builder
->add('firstName', null, [])
->add('lastName', null, [])
->add('hosts', CollectionType::class, [
'entry_type' => EntityType::class,
'entry_options' => ['label' => false, 'class' => Person::class],
'required' => false,
'allow_delete' => true,
'allow_add' => true,
'by_reference' => false,
])
}
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Person::class,
]);
$resolver->setAllowedTypes('person_id', ['int', 'null']);
}
}
記住以下幾點很重要:
您必須將當前人員 ID 作為
person_id表單選項傳遞(或為新條目傳遞null)。如果需要,您還可以從 $builder 變數中檢索此值。根據您的需要修改 EntityType 選項中的“query_builder”,例如不要從主機串列中排除當前(root)人員等。
這種方法MIGHT導致多個資料庫查詢(1元每收集專案),但我現在不知道這件事。如果是這樣,您應該自己找到解決此問題的方法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/379183.html
標籤:php symfony many-to-many symfony-forms symfony5
