11Referencing Entities with Abstract Classes and Interfaces
22=========================================================
33
4- In applications where functionality is segregated with minimal concrete dependencies
5- between the various layers , such as monoliths which are split into multiple modules,
6- it might be hard to prevent hard dependencies on entities between modules .
4+ In applications where functionality is organized in layers or modules with
5+ minimal concrete dependencies , such as monoliths split into multiple modules,
6+ it can be challenging to avoid tight coupling between entities .
77
8- Doctrine 2.2 includes a new utility called the ``ResolveTargetEntityListener ``,
9- that functions by intercepting certain calls inside Doctrine and rewriting
10- ``targetEntity `` parameters in your metadata mapping at runtime. It means that
11- you are able to use an interface or abstract class in your mappings and expect
12- correct mapping to a concrete entity at runtime.
8+ Doctrine provides a utility called the ``ResolveTargetEntityListener `` to solve
9+ this issue. It works by intercepting certain calls within Doctrine and rewriting
10+ ``targetEntity `` parameters in your metadata mapping at runtime. This allows you
11+ to reference an interface or abstract class in your mappings and have it resolved
12+ to a concrete entity at runtime.
1313
14- This functionality allows you to define relationships between different entities
15- without making them hard dependencies.
14+ This makes it possible to define relationships between entities without
15+ creating hard dependencies. This feature also works with the ``EntityValueResolver ``
16+ :ref: `as explained in the main Doctrine article <doctrine-entity-value-resolver-resolve-target-entities >`.
1617
17- .. tip ::
18+ .. versionadded :: 7.3
1819
19- Starting with Symfony 7.3, this functionality also works with the ``EntityValueResolver ``.
20- See :ref: ` doctrine-entity-value-resolver-resolve-target-entities ` for more details.
20+ Support for target entity resolution in the ``EntityValueResolver `` was
21+ introduced Symfony 7.3
2122
2223Background
2324----------
2425
25- Suppose you have an application which provides two modules; an Invoice module which
26- provides invoicing functionality, and a Customer module that contains customer management
27- tools . You want to keep dependencies between these modules separated, because they should
28- not be aware of the other module 's implementation details.
26+ Suppose you have an application with two modules: an Invoice module that
27+ provides invoicing functionality, and a Customer module that handles customer
28+ management . You want to keep these modules decoupled, so that neither is aware
29+ of the other's implementation details.
2930
30- In this case, you have an ``Invoice `` entity with a relationship to the interface
31- ``InvoiceSubjectInterface ``. This is not recognized as a valid entity by Doctrine.
32- The goal is to get the ``ResolveTargetEntityListener `` to replace any mention of the interface
33- with a real object that implements that interface .
31+ In this case, your ``Invoice `` entity has a relationship to the interface
32+ ``InvoiceSubjectInterface ``. Since interfaces are not valid Doctrine entities,
33+ the goal is to use the ``ResolveTargetEntityListener `` to replace all
34+ references to this interface with a concrete class that implements it .
3435
3536Set up
3637------
3738
38- This article uses the following two basic entities (which are incomplete for
39- brevity) to explain how to set up and use the ``ResolveTargetEntityListener ``.
39+ This article uses two basic (incomplete) entities to demonstrate how to set up
40+ and use the ``ResolveTargetEntityListener ``.
4041
41- A Customer entity::
42+ A `` Customer `` entity::
4243
4344 // src/Entity/Customer.php
4445 namespace App\Entity;
@@ -55,17 +56,14 @@ A Customer entity::
5556 // are already implemented in the BaseCustomer
5657 }
5758
58- An Invoice entity::
59+ An `` Invoice `` entity::
5960
6061 // src/Entity/Invoice.php
6162 namespace App\Entity;
6263
6364 use App\Model\InvoiceSubjectInterface;
6465 use Doctrine\ORM\Mapping as ORM;
6566
66- /**
67- * Represents an Invoice.
68- */
6967 #[ORM\Entity]
7068 #[ORM\Table(name: 'invoice')]
7169 class Invoice
@@ -74,7 +72,7 @@ An Invoice entity::
7472 protected InvoiceSubjectInterface $subject;
7573 }
7674
77- An InvoiceSubjectInterface ::
75+ The interface representing the subject used in the invoice ::
7876
7977 // src/Model/InvoiceSubjectInterface.php
8078 namespace App\Model;
@@ -94,8 +92,8 @@ An InvoiceSubjectInterface::
9492 public function getName(): string;
9593 }
9694
97- Next, you need to configure the ``resolve_target_entities `` option, which tells the DoctrineBundle
98- about the replacement :
95+ Now configure the ``resolve_target_entities `` option to tell Doctrine
96+ how to replace the interface with the concrete class :
9997
10098.. configuration-block ::
10199
@@ -145,7 +143,6 @@ about the replacement:
145143 Final Thoughts
146144--------------
147145
148- With the ``ResolveTargetEntityListener ``, you are able to decouple your
149- modules, keeping them usable by themselves, but still being able to
150- define relationships between different objects. By using this method,
151- your modules will end up being easier to maintain independently.
146+ Using ``ResolveTargetEntityListener `` allows you to decouple your modules
147+ while still defining relationships between their entities. This makes your
148+ codebase more modular and easier to maintain over time.
0 commit comments