在单个字段下映射多个实体
Mapping multiple entities under a single field
有没有办法让实体中的单个字段绑定到多个不同的实体?
我有一个 "Task" 实体,它可以与客户实体或供应商实体相关联(不能同时与两者相关联)。现在这两个字段是分开的。
我需要在我的 TaskType 表单中使用它,以便用户可以 select 将任务与哪个 Customer/Supplier 相关联,最好在单个字段下,因为我计划添加更多它可以关联.
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Customer", inversedBy="tasks")
*/
private $customer;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Supplier", inversedBy="tasks")
*/
private $supplier;
public function getCustomer(): ?Customer
{
return $this->customer;
}
public function setCustomer(?Customer $customer): self
{
$this->customer = $customer;
return $this;
}
public function getSupplier(): ?Supplier
...etc
也许您可以尝试以下方法:
理想情况下,我猜您想在 Customer
和 Supplier
之间共享信息。所以我们可以引入一个新的parent class,例如Person
(我不知道他们有什么样的责任,所以我们就拿最多"generic" class 名称),并使用 Doctrine inheritance mapping :
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="discr", type="string")
* @ORM\DiscriminatorMap({
* "customer" = "Customer",
* "supplier" = "Supplier"
* })
*/
abstract class Person
{
//... Fields, traits, embeddables...
/**
* A common attribute between our child classes
* protected to respect encapsulation
*
* @ORM\Column(type="text")
*/
protected $name;
/**
* Here we define the general link to a task. It will be inherited by child classes
*
* @ORM\OneToMany(targetEntity="App\Entity\Task", mappedBy="assignedTo")
*/
protected $tasks;
// public getters/setters...
}
我认为 Class table inheritance strategy would fit your needs here, as you would like to add more entities later. That way, we can respect the Open-closed principle 以后再添加 child classes 而不是只修改一个逻辑 class.
此外,我将 Person
class 抽象化,因为我们通常要处理 Customer
或 Supplier
实例。但根据您的需要,也许您可以删除 abstract
关键字。在这种情况下,您必须在鉴别器映射中包含 Person
。
当然,现在 Customer
和 Supplier
都要扩展 Person
:
//...
class Customer extends Person
//...
//...
class Supplier extends Person
//...
Don't forget to remove shared fields (like id
, for instance) from the child classes, it will be now inherited from Person
因此,在任务中,您可以定义 ManyToOne
与 Person
的关系:
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Person", inversedBy="tasks")
*/
private $assignedTo;
最后,对于您的任务表单,让我们有一个包含所有人姓名的 select 列表:
<?php
namespace App\Form;
use App\Entity\Person;
use App\Entity\Task;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// other task fields
->add('assignedTo', EntityType::class, [
'class' => Person::class,
'choice_label' => 'name',
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Task::class,
]);
}
}
它会select所有的人,不分类型。
然后您可以稍后使用其他 child classes 扩展它!
我希望这会有所帮助。
有没有办法让实体中的单个字段绑定到多个不同的实体?
我有一个 "Task" 实体,它可以与客户实体或供应商实体相关联(不能同时与两者相关联)。现在这两个字段是分开的。
我需要在我的 TaskType 表单中使用它,以便用户可以 select 将任务与哪个 Customer/Supplier 相关联,最好在单个字段下,因为我计划添加更多它可以关联.
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Customer", inversedBy="tasks")
*/
private $customer;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Supplier", inversedBy="tasks")
*/
private $supplier;
public function getCustomer(): ?Customer
{
return $this->customer;
}
public function setCustomer(?Customer $customer): self
{
$this->customer = $customer;
return $this;
}
public function getSupplier(): ?Supplier
...etc
也许您可以尝试以下方法:
理想情况下,我猜您想在 Customer
和 Supplier
之间共享信息。所以我们可以引入一个新的parent class,例如Person
(我不知道他们有什么样的责任,所以我们就拿最多"generic" class 名称),并使用 Doctrine inheritance mapping :
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="discr", type="string")
* @ORM\DiscriminatorMap({
* "customer" = "Customer",
* "supplier" = "Supplier"
* })
*/
abstract class Person
{
//... Fields, traits, embeddables...
/**
* A common attribute between our child classes
* protected to respect encapsulation
*
* @ORM\Column(type="text")
*/
protected $name;
/**
* Here we define the general link to a task. It will be inherited by child classes
*
* @ORM\OneToMany(targetEntity="App\Entity\Task", mappedBy="assignedTo")
*/
protected $tasks;
// public getters/setters...
}
我认为 Class table inheritance strategy would fit your needs here, as you would like to add more entities later. That way, we can respect the Open-closed principle 以后再添加 child classes 而不是只修改一个逻辑 class.
此外,我将 Person
class 抽象化,因为我们通常要处理 Customer
或 Supplier
实例。但根据您的需要,也许您可以删除 abstract
关键字。在这种情况下,您必须在鉴别器映射中包含 Person
。
当然,现在 Customer
和 Supplier
都要扩展 Person
:
//...
class Customer extends Person
//...
//...
class Supplier extends Person
//...
Don't forget to remove shared fields (like
id
, for instance) from the child classes, it will be now inherited fromPerson
因此,在任务中,您可以定义 ManyToOne
与 Person
的关系:
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Person", inversedBy="tasks")
*/
private $assignedTo;
最后,对于您的任务表单,让我们有一个包含所有人姓名的 select 列表:
<?php
namespace App\Form;
use App\Entity\Person;
use App\Entity\Task;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// other task fields
->add('assignedTo', EntityType::class, [
'class' => Person::class,
'choice_label' => 'name',
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Task::class,
]);
}
}
它会select所有的人,不分类型。 然后您可以稍后使用其他 child classes 扩展它! 我希望这会有所帮助。