如何使用抽象类和接口定义关系
Bundle 的目标之一是创建功能离散的 bundle,这些 bundle 没有很多(如果有的话)依赖项,允许您在其他应用程序中使用该功能,而无需包含不必要的项。
Doctrine 2.2 包含一个名为 ResolveTargetEntityListener
的新实用程序,它的功能是通过拦截 Doctrine 内部的某些调用,并在运行时重写元数据映射中的 targetEntity
参数。这意味着在您的 bundle 中,您可以使用接口或抽象类在映射中,并期望在运行时正确映射到具体的实体。
此功能允许您定义不同实体之间的关系,而无需使它们成为硬依赖项。
背景
假设您有一个 InvoiceBundle,它提供发票功能,以及一个 CustomerBundle,它包含客户管理工具。您希望将它们分开,因为它们可以在没有彼此的其他系统中使用,但对于您的应用程序,您希望将它们一起使用。
在这种情况下,您有一个 Invoice
实体,它与一个不存在的对象 InvoiceSubjectInterface
存在关系。目标是让 ResolveTargetEntityListener
将任何提及接口的地方替换为实现该接口的真实对象。
设置
本文使用以下两个基本实体(为简洁起见,这些实体是不完整的)来解释如何设置和使用 ResolveTargetEntityListener
。
Customer 实体
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// src/Entity/Customer.php
namespace App\Entity;
use App\Entity\CustomerInterface as BaseCustomer;
use App\Model\InvoiceSubjectInterface;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ORM\Table(name: 'customer')]
class Customer extends BaseCustomer implements InvoiceSubjectInterface
{
// In this example, any methods defined in the InvoiceSubjectInterface
// are already implemented in the BaseCustomer
}
Invoice 实体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// src/Entity/Invoice.php
namespace App\Entity;
use App\Model\InvoiceSubjectInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* Represents an Invoice.
*/
#[ORM\Entity]
#[ORM\Table(name: 'invoice')]
class Invoice
{
#[ORM\ManyToOne(targetEntity: InvoiceSubjectInterface::class)]
protected InvoiceSubjectInterface $subject;
}
InvoiceSubjectInterface
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// src/Model/InvoiceSubjectInterface.php
namespace App\Model;
/**
* An interface that the invoice Subject object should implement.
* In most circumstances, only a single object should implement
* this interface as the ResolveTargetEntityListener can only
* change the target to a single object.
*/
interface InvoiceSubjectInterface
{
// List any additional methods that your InvoiceBundle
// will need to access on the subject so that you can
// be sure that you have access to those methods.
public function getName(): string;
}
接下来,您需要配置监听器,它会告知 DoctrineBundle 关于替换的信息
1 2 3 4 5 6 7
# config/packages/doctrine.yaml
doctrine:
# ...
orm:
# ...
resolve_target_entities:
App\Model\InvoiceSubjectInterface: App\Entity\Customer
最终想法
使用 ResolveTargetEntityListener
,您可以解耦您的 bundle,保持它们可以独立使用,但仍然能够定义不同对象之间的关系。通过使用这种方法,您的 bundle 最终将更容易独立维护。