Як визначати відносини з абстрактними класами та інтерфейсами
Дата оновлення перекладу 2023-09-04
Як визначати відносини з абстрактними класами та інтерфейсами
Однією з цілей пакетів є створення розумних пакетів функціональностей, які не мають багато залежностей (або не мають їх взагалі), що дозволяє вам використовувати цю функціональність в інших додатках, не додаючи непотрібні речі.
Doctrine 2.2 містить нову утиліту під назвою ResolveTargetEntityListener
, яка
функціонує шляхом перехоплення деяких викликів всередині Doctrine та перевизнчення
параметру targetEntity
в маршрутизації ваших метаданих під час прогону. Це означає,
що у вашому пакеті ви можете використати інтерфейс або абстрактний клас у ваших
відображеннях, та очікувати правильного відображення конкретної сутності під час прогону.
Ця функціональність дозволяє вам визначати відносини між різними сутностями, не роблячи їх жорсткими залежностями.
Задній план
Уявіть, що у вас є InvoiceBundle, який надає функціональність виставлення інвойсів та CustomerBundle, який містить користувацькі інструменти управління. Вам потрібно тримати їх окремо, так як вони можуть бути використані в інших системах одне без одного, але для вашого додатку ви хочете використати їх разом.
У цьому випадку, у вас є сутність Invoice
з відношенням до неіснуючого обʼєкта
InvoiceSubjectInterface
. Ціллю є змусити ResolveTargetEntityListener
замінювати
будь-яке згадування про інтерфейс реальним обʼєктом, що реалізує цей інтерфейс.
Установка
Ця стаття використовує дві наступні базові сутності (які є неповними для скорочення) для
того, щоб пояснити, як встановити та використовувати ResolveTargetEntityListener
.
Сутність користувача:
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
{
// У цьому прикладі, будь-які методи, визначені в InvoiceSubjectInterface
// вже реализовані в BaseCustomer
}
Сутність інвойсу:
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;
/**
* Представляє інвойс.
*/
#[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;
/**
* Інтерфейс, який має реалізовувати обʼєкт Субʼєкта інвойсу.
* У більшості випадків, лише один обʼєкт має реалізовувати цей
* інтерфейс, так як ResolveTargetEntityListener може змінюватися
* ціль лише для одного обʼєкта.
*/
interface InvoiceSubjectInterface
{
// Вкажіть всі додаткові методи, до яких InvoiceBundle
// знадобиться отримати доступ, щоб ви могли бути впевнені,
// що у вас є доступ до цих методів.
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
, ви можете розʼєднувати ваші пакети,
щоб їх можна було використовувати окремо, але у вас залишається можливість визначати
відносини між різними обʼєктами. Використовуючи цей метод, вашими пакетами буде легше
управляти окремо.