1 | <?php |
||
17 | class UnitOfWork implements PropertyChangedListener |
||
18 | { |
||
19 | /** |
||
20 | * An entity is in MANAGED state when its persistence is managed by an EntityManager. |
||
21 | */ |
||
22 | const STATE_MANAGED = 1; |
||
23 | /** |
||
24 | * An entity is new if it has just been instantiated (i.e. using the "new" operator) |
||
25 | * and is not (yet) managed by an EntityManager. |
||
26 | */ |
||
27 | const STATE_NEW = 2; |
||
28 | /** |
||
29 | * A detached entity is an instance with persistent state and identity that is not |
||
30 | * (or no longer) associated with an EntityManager (and a UnitOfWork). |
||
31 | */ |
||
32 | const STATE_DETACHED = 3; |
||
33 | /** |
||
34 | * A removed entity instance is an instance with a persistent identity, |
||
35 | * associated with an EntityManager, whose persistent state will be deleted |
||
36 | * on commit. |
||
37 | */ |
||
38 | const STATE_REMOVED = 4; |
||
39 | |||
40 | |||
41 | /** |
||
42 | * The (cached) states of any known entities. |
||
43 | * Keys are object ids (spl_object_hash). |
||
44 | * |
||
45 | * @var array |
||
46 | */ |
||
47 | private $entityStates = []; |
||
48 | |||
49 | |||
50 | /** @var EntityManager */ |
||
51 | private $manager; |
||
52 | /** @var EntityPersister[] */ |
||
53 | private $persisters = []; |
||
54 | /** @var array */ |
||
55 | private $entityIdentifiers; |
||
56 | /** @var object[][] */ |
||
57 | private $identityMap; |
||
58 | /** @var IdentifierFlattener */ |
||
59 | private $identifierFlattener; |
||
60 | /** @var array */ |
||
61 | private $originalEntityData; |
||
62 | |||
63 | /** |
||
64 | * UnitOfWork constructor. |
||
65 | * |
||
66 | * @param EntityManager $manager |
||
67 | */ |
||
68 | 14 | public function __construct(EntityManager $manager) |
|
73 | |||
74 | /** |
||
75 | * @param $className |
||
76 | * |
||
77 | * @return EntityPersister |
||
78 | */ |
||
79 | 13 | public function getEntityPersister($className) |
|
89 | |||
90 | /** |
||
91 | * Checks whether an entity is registered in the identity map of this UnitOfWork. |
||
92 | * |
||
93 | * @param object $entity |
||
94 | * |
||
95 | * @return boolean |
||
96 | */ |
||
97 | public function isInIdentityMap($entity) |
||
115 | |||
116 | /** |
||
117 | * Gets the identifier of an entity. |
||
118 | * The returned value is always an array of identifier values. If the entity |
||
119 | * has a composite identifier then the identifier values are in the same |
||
120 | * order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames(). |
||
121 | * |
||
122 | * @param object $entity |
||
123 | * |
||
124 | * @return array The identifier values. |
||
125 | */ |
||
126 | public function getEntityIdentifier($entity) |
||
130 | |||
131 | /** |
||
132 | * @param $className |
||
133 | * @param \stdClass $data |
||
134 | * @param object|null $unmanagedProxy |
||
135 | * |
||
136 | * @return ObjectManagerAware|object |
||
137 | * @throws MappingException |
||
138 | */ |
||
139 | 12 | public function getOrCreateEntity($className, \stdClass $data, $unmanagedProxy = null) |
|
140 | { |
||
141 | /** @var EntityMetadata $class */ |
||
142 | 12 | $class = $this->manager->getClassMetadata($className); |
|
143 | 12 | $hydrator = new EntityHydrator($this->manager, $class); |
|
144 | |||
145 | 12 | $tmpEntity = $hydrator->hydarate($data); |
|
146 | |||
147 | 12 | $id = $this->identifierFlattener->flattenIdentifier($class, $class->getIdentifierValues($tmpEntity)); |
|
148 | 12 | $idHash = implode(' ', $id); |
|
149 | |||
150 | 12 | $overrideLocalValues = false; |
|
151 | 12 | if (isset($this->identityMap[$class->rootEntityName][$idHash])) { |
|
152 | 2 | $entity = $this->identityMap[$class->rootEntityName][$idHash]; |
|
153 | 2 | $oid = spl_object_hash($entity); |
|
154 | |||
155 | 2 | if ($entity instanceof Proxy && !$entity->__isInitialized()) { |
|
156 | 2 | $entity->__setInitialized(true); |
|
157 | |||
158 | 2 | $overrideLocalValues = true; |
|
159 | 2 | $this->originalEntityData[$oid] = $data; |
|
160 | |||
161 | 2 | if ($entity instanceof NotifyPropertyChanged) { |
|
162 | $entity->addPropertyChangedListener($this); |
||
163 | } |
||
164 | 2 | } |
|
165 | 2 | } else { |
|
166 | 11 | $entity = $unmanagedProxy; |
|
167 | 11 | if (null === $entity) { |
|
168 | 11 | $entity = $this->newInstance($class); |
|
169 | 11 | } |
|
170 | 11 | $this->registerManaged($entity, $id, $data); |
|
171 | 11 | $overrideLocalValues = true; |
|
172 | } |
||
173 | |||
174 | 12 | if (!$overrideLocalValues) { |
|
175 | return $entity; |
||
176 | } |
||
177 | |||
178 | 12 | $entity = $hydrator->hydarate($data, $entity); |
|
179 | |||
180 | 12 | return $entity; |
|
181 | } |
||
182 | |||
183 | |||
184 | /** |
||
185 | * @param ApiMetadata $class |
||
186 | * |
||
187 | * @return \Doctrine\Common\Persistence\ObjectManagerAware|object |
||
188 | */ |
||
189 | 11 | private function newInstance(ApiMetadata $class) |
|
199 | |||
200 | /** |
||
201 | * INTERNAL: |
||
202 | * Registers an entity as managed. |
||
203 | * |
||
204 | * @param object $entity The entity. |
||
205 | * @param array $id The identifier values. |
||
206 | * @param \stdClass|null $data The original entity data. |
||
207 | * |
||
208 | * @return void |
||
209 | */ |
||
210 | 12 | public function registerManaged($entity, array $id, \stdClass $data = null) |
|
224 | |||
225 | /** |
||
226 | * INTERNAL: |
||
227 | * Registers an entity in the identity map. |
||
228 | * Note that entities in a hierarchy are registered with the class name of |
||
229 | * the root entity. |
||
230 | * |
||
231 | * @ignore |
||
232 | * |
||
233 | * @param object $entity The entity to register. |
||
234 | * |
||
235 | * @return boolean TRUE if the registration was successful, FALSE if the identity of |
||
236 | * the entity in question is already managed. |
||
237 | * |
||
238 | */ |
||
239 | 12 | public function addToIdentityMap($entity) |
|
259 | |||
260 | /** |
||
261 | * Gets the identity map of the UnitOfWork. |
||
262 | * |
||
263 | * @return array |
||
264 | */ |
||
265 | public function getIdentityMap() |
||
269 | |||
270 | /** |
||
271 | * Gets the original data of an entity. The original data is the data that was |
||
272 | * present at the time the entity was reconstituted from the database. |
||
273 | * |
||
274 | * @param object $entity |
||
275 | * |
||
276 | * @return array |
||
277 | */ |
||
278 | public function getOriginalEntityData($entity) |
||
288 | |||
289 | /** |
||
290 | * INTERNAL: |
||
291 | * Checks whether an identifier hash exists in the identity map. |
||
292 | * |
||
293 | * @ignore |
||
294 | * |
||
295 | * @param string $idHash |
||
296 | * @param string $rootClassName |
||
297 | * |
||
298 | * @return boolean |
||
299 | */ |
||
300 | public function containsIdHash($idHash, $rootClassName) |
||
304 | |||
305 | /** |
||
306 | * INTERNAL: |
||
307 | * Gets an entity in the identity map by its identifier hash. |
||
308 | * |
||
309 | * @ignore |
||
310 | * |
||
311 | * @param string $idHash |
||
312 | * @param string $rootClassName |
||
313 | * |
||
314 | * @return object |
||
315 | */ |
||
316 | public function getByIdHash($idHash, $rootClassName) |
||
320 | |||
321 | /** |
||
322 | * INTERNAL: |
||
323 | * Tries to get an entity by its identifier hash. If no entity is found for |
||
324 | * the given hash, FALSE is returned. |
||
325 | * |
||
326 | * @ignore |
||
327 | * |
||
328 | * @param mixed $idHash (must be possible to cast it to string) |
||
329 | * @param string $rootClassName |
||
330 | * |
||
331 | * @return object|bool The found entity or FALSE. |
||
332 | */ |
||
333 | public function tryGetByIdHash($idHash, $rootClassName) |
||
343 | |||
344 | /** |
||
345 | * Gets the state of an entity with regard to the current unit of work. |
||
346 | * |
||
347 | * @param object $entity |
||
348 | * @param int|null $assume The state to assume if the state is not yet known (not MANAGED or REMOVED). |
||
349 | * This parameter can be set to improve performance of entity state detection |
||
350 | * by potentially avoiding a database lookup if the distinction between NEW and DETACHED |
||
351 | * is either known or does not matter for the caller of the method. |
||
352 | * |
||
353 | * @return int The entity state. |
||
354 | */ |
||
355 | public function getEntityState($entity, $assume = null) |
||
376 | |||
377 | /** |
||
378 | * Tries to find an entity with the given identifier in the identity map of |
||
379 | * this UnitOfWork. |
||
380 | * |
||
381 | * @param mixed $id The entity identifier to look for. |
||
382 | * @param string $rootClassName The name of the root class of the mapped entity hierarchy. |
||
383 | * |
||
384 | * @return object|bool Returns the entity with the specified identifier if it exists in |
||
385 | * this UnitOfWork, FALSE otherwise. |
||
386 | */ |
||
387 | 11 | public function tryGetById($id, $rootClassName) |
|
399 | |||
400 | /** |
||
401 | * Notifies the listener of a property change. |
||
402 | * |
||
403 | * @param object $sender The object on which the property changed. |
||
404 | * @param string $propertyName The name of the property that changed. |
||
405 | * @param mixed $oldValue The old value of the property that changed. |
||
406 | * @param mixed $newValue The new value of the property that changed. |
||
407 | * |
||
408 | * @return void |
||
409 | */ |
||
410 | public function propertyChanged($sender, $propertyName, $oldValue, $newValue) |
||
413 | } |
||
414 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.