1
1
Referencing Entities with Abstract Classes and Interfaces
2
2
=========================================================
3
3
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 .
7
7
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.
13
13
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 >`.
16
17
17
- .. tip ::
18
+ .. versionadded :: 7.3
18
19
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
21
22
22
23
Background
23
24
----------
24
25
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.
29
30
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 .
34
35
35
36
Set up
36
37
------
37
38
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 ``.
40
41
41
- A Customer entity::
42
+ A `` Customer `` entity::
42
43
43
44
// src/Entity/Customer.php
44
45
namespace App\Entity;
@@ -55,17 +56,14 @@ A Customer entity::
55
56
// are already implemented in the BaseCustomer
56
57
}
57
58
58
- An Invoice entity::
59
+ An `` Invoice `` entity::
59
60
60
61
// src/Entity/Invoice.php
61
62
namespace App\Entity;
62
63
63
64
use App\Model\InvoiceSubjectInterface;
64
65
use Doctrine\ORM\Mapping as ORM;
65
66
66
- /**
67
- * Represents an Invoice.
68
- */
69
67
#[ORM\Entity]
70
68
#[ORM\Table(name: 'invoice')]
71
69
class Invoice
@@ -74,7 +72,7 @@ An Invoice entity::
74
72
protected InvoiceSubjectInterface $subject;
75
73
}
76
74
77
- An InvoiceSubjectInterface ::
75
+ The interface representing the subject used in the invoice ::
78
76
79
77
// src/Model/InvoiceSubjectInterface.php
80
78
namespace App\Model;
@@ -94,8 +92,8 @@ An InvoiceSubjectInterface::
94
92
public function getName(): string;
95
93
}
96
94
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 :
99
97
100
98
.. configuration-block ::
101
99
@@ -145,7 +143,6 @@ about the replacement:
145
143
Final Thoughts
146
144
--------------
147
145
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