1 | <?php |
||||
2 | /** |
||||
3 | * Copyright (C) 2018 Gerrit Addiks. |
||||
4 | * This package (including this file) was released under the terms of the GPL-3.0. |
||||
5 | * You should have received a copy of the GNU General Public License along with this program. |
||||
6 | * If not, see <http://www.gnu.org/licenses/> or send me a mail so i can send you a copy. |
||||
7 | * @license GPL-3.0 |
||||
8 | * @author Gerrit Addiks <[email protected]> |
||||
9 | */ |
||||
10 | |||||
11 | namespace Addiks\RDMBundle\Doctrine; |
||||
12 | |||||
13 | use Addiks\RDMBundle\Hydration\EntityHydratorInterface; |
||||
14 | use Addiks\RDMBundle\Mapping\Drivers\MappingDriverInterface; |
||||
15 | use Addiks\RDMBundle\Mapping\EntityMappingInterface; |
||||
16 | use Addiks\RDMBundle\DataLoader\DataLoaderInterface; |
||||
17 | use Doctrine\ORM\Event\LifecycleEventArgs; |
||||
18 | use Doctrine\ORM\Mapping\ClassMetadata; |
||||
19 | use Doctrine\ORM\Tools\SchemaTool; |
||||
20 | use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs; |
||||
21 | use Doctrine\ORM\Event\LoadClassMetadataEventArgs; |
||||
22 | use Doctrine\ORM\EntityManagerInterface; |
||||
23 | use Doctrine\ORM\UnitOfWork; |
||||
24 | use Doctrine\DBAL\Schema\Table; |
||||
25 | use Doctrine\ORM\Event\PostFlushEventArgs; |
||||
26 | use Doctrine\ORM\Proxy\Proxy; |
||||
27 | use Doctrine\DBAL\Schema\Column; |
||||
28 | use PDOException; |
||||
29 | use Doctrine\DBAL\Exception\ConnectionException; |
||||
30 | |||||
31 | /** |
||||
32 | * Hooks into the event's of doctrine2-ORM and forwards the entities to other objects. |
||||
33 | */ |
||||
34 | final class EventListener |
||||
35 | { |
||||
36 | |||||
37 | /** |
||||
38 | * @var EntityHydratorInterface |
||||
39 | */ |
||||
40 | private $entityHydrator; |
||||
41 | |||||
42 | /** |
||||
43 | * @var MappingDriverInterface |
||||
44 | */ |
||||
45 | private $mappingDriver; |
||||
46 | |||||
47 | /** |
||||
48 | * @var DataLoaderInterface |
||||
49 | */ |
||||
50 | private $dbalDataLoader; |
||||
51 | |||||
52 | /** |
||||
53 | * @var array<class-string, bool> |
||||
0 ignored issues
–
show
Documentation
Bug
introduced
by
Loading history...
|
|||||
54 | */ |
||||
55 | 10 | private $hasRdmMappingForClass = array(); |
|||
56 | |||||
57 | public function __construct( |
||||
58 | EntityHydratorInterface $entityHydrator, |
||||
59 | MappingDriverInterface $mappingDriver, |
||||
60 | 10 | DataLoaderInterface $dbalDataLoader |
|||
61 | 10 | ) { |
|||
62 | 10 | $this->entityHydrator = $entityHydrator; |
|||
63 | $this->mappingDriver = $mappingDriver; |
||||
64 | $this->dbalDataLoader = $dbalDataLoader; |
||||
65 | 3 | } |
|||
66 | |||||
67 | public function postLoad(LifecycleEventArgs $arguments): void |
||||
68 | 3 | { |
|||
69 | /** @var object $entity */ |
||||
70 | $entity = $arguments->getEntity(); |
||||
0 ignored issues
–
show
The function
Doctrine\ORM\Event\LifecycleEventArgs::getEntity() has been deprecated: 2.13. Use {@see getObject} instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||
71 | 3 | ||||
72 | /** @var EntityManagerInterface $entityManager */ |
||||
73 | 3 | $entityManager = $arguments->getEntityManager(); |
|||
0 ignored issues
–
show
The function
Doctrine\ORM\Event\Lifec...rgs::getEntityManager() has been deprecated: 2.13. Use {@see getObjectManager} instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||
74 | |||||
75 | $this->entityHydrator->hydrateEntity($entity, $entityManager); |
||||
76 | 3 | } |
|||
77 | |||||
78 | public function prePersist(LifecycleEventArgs $arguments): void |
||||
79 | 3 | { |
|||
80 | /** @var object $entity */ |
||||
81 | $entity = $arguments->getEntity(); |
||||
0 ignored issues
–
show
The function
Doctrine\ORM\Event\LifecycleEventArgs::getEntity() has been deprecated: 2.13. Use {@see getObject} instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||
82 | 3 | ||||
83 | /** @var EntityManagerInterface $entityManager */ |
||||
84 | 3 | $entityManager = $arguments->getEntityManager(); |
|||
0 ignored issues
–
show
The function
Doctrine\ORM\Event\Lifec...rgs::getEntityManager() has been deprecated: 2.13. Use {@see getObjectManager} instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||
85 | 3 | ||||
86 | if (!($entity instanceof Proxy)) { |
||||
87 | $this->entityHydrator->assertHydrationOnEntity($entity, $entityManager); |
||||
88 | } |
||||
89 | 5 | } |
|||
90 | |||||
91 | public function postFlush(PostFlushEventArgs $arguments): void |
||||
92 | 5 | { |
|||
93 | /** @var EntityManagerInterface $entityManager */ |
||||
94 | $entityManager = $arguments->getEntityManager(); |
||||
0 ignored issues
–
show
The function
Doctrine\ORM\Event\PostF...rgs::getEntityManager() has been deprecated: 2.13. Use {@see getObjectManager} instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||
95 | 5 | ||||
96 | /** @var UnitOfWork $unitOfWork */ |
||||
97 | $unitOfWork = $entityManager->getUnitOfWork(); |
||||
98 | 5 | ||||
99 | 5 | /** @param class-string $className */ |
|||
100 | 1 | foreach ($unitOfWork->getIdentityMap() as $className => $entities) { |
|||
101 | if (!$this->hasRdmMappingForClass($className)) { |
||||
102 | continue; |
||||
103 | 4 | } |
|||
104 | |||||
105 | foreach ($entities as $entity) { |
||||
106 | 4 | /** @var object $entity */ |
|||
107 | 4 | ||||
108 | if (!$this->isUnitializedProxy($entity)) { |
||||
109 | if ($unitOfWork->isScheduledForDelete($entity)) { |
||||
110 | $this->dbalDataLoader->removeDBALDataForEntity($entity, $entityManager); |
||||
111 | 4 | ||||
112 | } else { |
||||
113 | $this->dbalDataLoader->storeDBALDataForEntity($entity, $entityManager); |
||||
114 | } |
||||
115 | } |
||||
116 | } |
||||
117 | } |
||||
118 | 5 | } |
|||
119 | |||||
120 | public function loadClassMetadata(LoadClassMetadataEventArgs $arguments): void |
||||
121 | 5 | { |
|||
122 | /** @var EntityManagerInterface $entityManager */ |
||||
123 | $entityManager = $arguments->getEntityManager(); |
||||
124 | 5 | ||||
125 | /** @var ClassMetadata $classMetadata */ |
||||
126 | 5 | $classMetadata = $arguments->getClassMetadata(); |
|||
127 | |||||
128 | try { |
||||
129 | $this->dbalDataLoader->prepareOnMetadataLoad($entityManager, $classMetadata); |
||||
130 | |||||
131 | } catch (PDOException | ConnectionException $exception) { |
||||
132 | var_dump($exception->getMessage()); |
||||
133 | if (!str_contains($exception->getMessage(), 'No such file or directory')) { |
||||
134 | throw $exception; |
||||
135 | } |
||||
136 | 2 | } |
|||
137 | } |
||||
138 | |||||
139 | 2 | /** |
|||
140 | * Invoked when doctrine has generated a table-definition in the target-schema. |
||||
141 | * Collects the additional schema-columns from the mapping and add's them to the table. |
||||
142 | 2 | * |
|||
143 | * Dispatched in: |
||||
144 | * @see SchemaTool::getSchemaFromMetadata |
||||
145 | 2 | */ |
|||
146 | public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $arguments): void |
||||
147 | { |
||||
148 | 2 | /** @var Table $table */ |
|||
149 | $table = $arguments->getClassTable(); |
||||
150 | 2 | ||||
151 | /** @var ClassMetadata $classMetadata */ |
||||
152 | 2 | $classMetadata = $arguments->getClassMetadata(); |
|||
153 | |||||
154 | 2 | /** @var class-string $className */ |
|||
155 | $className = $classMetadata->getName(); |
||||
156 | |||||
157 | /** @var ?EntityMappingInterface $entityMapping */ |
||||
158 | 2 | $entityMapping = $this->mappingDriver->loadRDMMetadataForClass($className); |
|||
159 | |||||
160 | 2 | if ($entityMapping instanceof EntityMappingInterface) { |
|||
161 | 2 | /** @var array<Column> $additionalColumns */ |
|||
162 | $additionalColumns = $entityMapping->collectDBALColumns(); |
||||
163 | 2 | ||||
164 | 2 | foreach ($additionalColumns as $column) { |
|||
165 | /** @var Column $column */ |
||||
166 | |||||
167 | /** @var string $columnName */ |
||||
168 | $columnName = $column->getName(); |
||||
169 | |||||
170 | if (!$table->hasColumn($columnName)) { |
||||
171 | |||||
172 | 5 | /** @var array<string, mixed> $columnConfig */ |
|||
173 | $columnConfig = $column->toArray(); |
||||
174 | 5 | unset($columnConfig['name']); |
|||
175 | |||||
176 | 5 | $table->addColumn( |
|||
177 | $columnName, |
||||
178 | $column->getType()->getName(), |
||||
179 | 5 | $columnConfig |
|||
180 | 5 | ); |
|||
181 | } |
||||
182 | } |
||||
183 | 5 | } |
|||
184 | 5 | } |
|||
185 | |||||
186 | /** @param class-string $className */ |
||||
0 ignored issues
–
show
|
|||||
187 | 5 | private function hasRdmMappingForClass(string $className): bool |
|||
188 | { |
||||
189 | if (!isset($this->hasRdmMappingForClass[$className])) { |
||||
190 | /** @var class-string $currentClassName */ |
||||
191 | $currentClassName = $className; |
||||
192 | |||||
193 | 4 | do { |
|||
194 | $this->hasRdmMappingForClass[$className] = is_object( |
||||
195 | $this->mappingDriver->loadRDMMetadataForClass($currentClassName) |
||||
196 | 4 | ); |
|||
197 | |||||
198 | 4 | $currentClassName = current(class_parents($currentClassName)); |
|||
199 | } while (class_exists($currentClassName) && !$this->hasRdmMappingForClass[$className]); |
||||
200 | } |
||||
201 | |||||
202 | 4 | return $this->hasRdmMappingForClass[$className]; |
|||
203 | } |
||||
204 | |||||
205 | /** |
||||
206 | * @param object $entity |
||||
207 | */ |
||||
208 | private function isUnitializedProxy($entity): bool |
||||
209 | { |
||||
210 | /** @var bool $isUnitializedProxy */ |
||||
211 | $isUnitializedProxy = false; |
||||
212 | |||||
213 | if ($entity instanceof Proxy && !$entity->__isInitialized()) { |
||||
214 | $isUnitializedProxy = true; |
||||
215 | } |
||||
216 | |||||
217 | return $isUnitializedProxy; |
||||
218 | } |
||||
219 | |||||
220 | } |
||||
221 |