Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like UnitOfWork often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use UnitOfWork, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
28 | class UnitOfWork implements PropertyChangedListener |
||
29 | { |
||
30 | /** |
||
31 | * An entity is in MANAGED state when its persistence is managed by an EntityManager. |
||
32 | */ |
||
33 | const STATE_MANAGED = 1; |
||
34 | /** |
||
35 | * An entity is new if it has just been instantiated (i.e. using the "new" operator) |
||
36 | * and is not (yet) managed by an EntityManager. |
||
37 | */ |
||
38 | const STATE_NEW = 2; |
||
39 | /** |
||
40 | * A detached entity is an instance with persistent state and identity that is not |
||
41 | * (or no longer) associated with an EntityManager (and a UnitOfWork). |
||
42 | */ |
||
43 | const STATE_DETACHED = 3; |
||
44 | /** |
||
45 | * A removed entity instance is an instance with a persistent identity, |
||
46 | * associated with an EntityManager, whose persistent state will be deleted |
||
47 | * on commit. |
||
48 | */ |
||
49 | const STATE_REMOVED = 4; |
||
50 | |||
51 | /** |
||
52 | * The (cached) states of any known entities. |
||
53 | * Keys are object ids (spl_object_hash). |
||
54 | * |
||
55 | * @var array |
||
56 | */ |
||
57 | private $entityStates = []; |
||
58 | |||
59 | /** @var EntityManager */ |
||
60 | private $manager; |
||
61 | /** @var EntityPersister[] */ |
||
62 | private $persisters = []; |
||
63 | /** @var CollectionPersister[] */ |
||
64 | private $collectionPersisters = []; |
||
65 | /** @var array */ |
||
66 | private $entityIdentifiers = []; |
||
67 | /** @var object[][] */ |
||
68 | private $identityMap = []; |
||
69 | /** @var IdentifierFlattener */ |
||
70 | private $identifierFlattener; |
||
71 | /** @var array */ |
||
72 | private $originalEntityData = []; |
||
73 | /** @var array */ |
||
74 | private $entityDeletions = []; |
||
75 | /** @var array */ |
||
76 | private $entityChangeSets = []; |
||
77 | /** @var array */ |
||
78 | private $entityInsertions = []; |
||
79 | /** @var array */ |
||
80 | private $entityUpdates = []; |
||
81 | /** @var array */ |
||
82 | private $readOnlyObjects = []; |
||
83 | /** @var array */ |
||
84 | private $scheduledForSynchronization = []; |
||
85 | /** @var array */ |
||
86 | private $orphanRemovals = []; |
||
87 | /** @var ApiCollection[] */ |
||
88 | private $collectionDeletions = []; |
||
89 | /** @var array */ |
||
90 | private $extraUpdates = []; |
||
91 | /** @var ApiCollection[] */ |
||
92 | private $collectionUpdates = []; |
||
93 | /** @var ApiCollection[] */ |
||
94 | private $visitedCollections = []; |
||
95 | /** @var ReflectionPropertiesGetter */ |
||
96 | private $reflectionPropertiesGetter; |
||
97 | |||
98 | /** |
||
99 | * UnitOfWork constructor. |
||
100 | * |
||
101 | * @param EntityManager $manager |
||
102 | */ |
||
103 | 20 | public function __construct(EntityManager $manager) |
|
109 | |||
110 | /** |
||
111 | * @param $className |
||
112 | * |
||
113 | * @return EntityPersister |
||
114 | */ |
||
115 | 19 | public function getEntityPersister($className) |
|
132 | |||
133 | /** |
||
134 | * Checks whether an entity is registered in the identity map of this UnitOfWork. |
||
135 | * |
||
136 | * @param object $entity |
||
137 | * |
||
138 | * @return boolean |
||
139 | */ |
||
140 | public function isInIdentityMap($entity) |
||
158 | |||
159 | /** |
||
160 | * Gets the identifier of an entity. |
||
161 | * The returned value is always an array of identifier values. If the entity |
||
162 | * has a composite identifier then the identifier values are in the same |
||
163 | * order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames(). |
||
164 | * |
||
165 | * @param object $entity |
||
166 | * |
||
167 | * @return array The identifier values. |
||
168 | */ |
||
169 | 1 | public function getEntityIdentifier($entity) |
|
173 | |||
174 | /** |
||
175 | * @param $className |
||
176 | * @param \stdClass $data |
||
177 | * |
||
178 | * @return ObjectManagerAware|object |
||
179 | * @throws MappingException |
||
180 | */ |
||
181 | 13 | public function getOrCreateEntity($className, \stdClass $data) |
|
228 | |||
229 | /** |
||
230 | * INTERNAL: |
||
231 | * Registers an entity as managed. |
||
232 | * |
||
233 | * @param object $entity The entity. |
||
234 | * @param array $id The identifier values. |
||
235 | * @param \stdClass|null $data The original entity data. |
||
236 | * |
||
237 | * @return void |
||
238 | */ |
||
239 | 4 | public function registerManaged($entity, array $id, \stdClass $data = null) |
|
253 | |||
254 | /** |
||
255 | * INTERNAL: |
||
256 | * Registers an entity in the identity map. |
||
257 | * Note that entities in a hierarchy are registered with the class name of |
||
258 | * the root entity. |
||
259 | * |
||
260 | * @ignore |
||
261 | * |
||
262 | * @param object $entity The entity to register. |
||
263 | * |
||
264 | * @return boolean TRUE if the registration was successful, FALSE if the identity of |
||
265 | * the entity in question is already managed. |
||
266 | * |
||
267 | */ |
||
268 | 9 | public function addToIdentityMap($entity) |
|
288 | |||
289 | /** |
||
290 | * Gets the identity map of the UnitOfWork. |
||
291 | * |
||
292 | * @return array |
||
293 | */ |
||
294 | public function getIdentityMap() |
||
298 | |||
299 | /** |
||
300 | * Gets the original data of an entity. The original data is the data that was |
||
301 | * present at the time the entity was reconstituted from the database. |
||
302 | * |
||
303 | * @param object $entity |
||
304 | * |
||
305 | * @return array |
||
306 | */ |
||
307 | public function getOriginalEntityData($entity) |
||
317 | |||
318 | /** |
||
319 | * INTERNAL: |
||
320 | * Checks whether an identifier hash exists in the identity map. |
||
321 | * |
||
322 | * @ignore |
||
323 | * |
||
324 | * @param string $idHash |
||
325 | * @param string $rootClassName |
||
326 | * |
||
327 | * @return boolean |
||
328 | */ |
||
329 | public function containsIdHash($idHash, $rootClassName) |
||
333 | |||
334 | /** |
||
335 | * INTERNAL: |
||
336 | * Gets an entity in the identity map by its identifier hash. |
||
337 | * |
||
338 | * @ignore |
||
339 | * |
||
340 | * @param string $idHash |
||
341 | * @param string $rootClassName |
||
342 | * |
||
343 | * @return object |
||
344 | */ |
||
345 | public function getByIdHash($idHash, $rootClassName) |
||
349 | |||
350 | /** |
||
351 | * INTERNAL: |
||
352 | * Tries to get an entity by its identifier hash. If no entity is found for |
||
353 | * the given hash, FALSE is returned. |
||
354 | * |
||
355 | * @ignore |
||
356 | * |
||
357 | * @param mixed $idHash (must be possible to cast it to string) |
||
358 | * @param string $rootClassName |
||
359 | * |
||
360 | * @return object|bool The found entity or FALSE. |
||
361 | */ |
||
362 | public function tryGetByIdHash($idHash, $rootClassName) |
||
372 | |||
373 | /** |
||
374 | * Gets the state of an entity with regard to the current unit of work. |
||
375 | * |
||
376 | * @param object $entity |
||
377 | * @param int|null $assume The state to assume if the state is not yet known (not MANAGED or REMOVED). |
||
378 | * This parameter can be set to improve performance of entity state detection |
||
379 | * by potentially avoiding a database lookup if the distinction between NEW and DETACHED |
||
380 | * is either known or does not matter for the caller of the method. |
||
381 | * |
||
382 | * @return int The entity state. |
||
383 | */ |
||
384 | 5 | public function getEntityState($entity, $assume = null) |
|
405 | |||
406 | /** |
||
407 | * Tries to find an entity with the given identifier in the identity map of |
||
408 | * this UnitOfWork. |
||
409 | * |
||
410 | * @param mixed $id The entity identifier to look for. |
||
411 | * @param string $rootClassName The name of the root class of the mapped entity hierarchy. |
||
412 | * |
||
413 | * @return object|bool Returns the entity with the specified identifier if it exists in |
||
414 | * this UnitOfWork, FALSE otherwise. |
||
415 | */ |
||
416 | 12 | public function tryGetById($id, $rootClassName) |
|
428 | |||
429 | /** |
||
430 | * Notifies this UnitOfWork of a property change in an entity. |
||
431 | * |
||
432 | * @param object $entity The entity that owns the property. |
||
433 | * @param string $propertyName The name of the property that changed. |
||
434 | * @param mixed $oldValue The old value of the property. |
||
435 | * @param mixed $newValue The new value of the property. |
||
436 | * |
||
437 | * @return void |
||
438 | */ |
||
439 | public function propertyChanged($entity, $propertyName, $oldValue, $newValue) |
||
453 | |||
454 | /** |
||
455 | * Persists an entity as part of the current unit of work. |
||
456 | * |
||
457 | * @param object $entity The entity to persist. |
||
458 | * |
||
459 | * @return void |
||
460 | */ |
||
461 | 5 | public function persist($entity) |
|
466 | |||
467 | /** |
||
468 | * @param ApiMetadata $class |
||
469 | * @param $entity |
||
470 | * |
||
471 | * @throws \InvalidArgumentException |
||
472 | * @throws \RuntimeException |
||
473 | */ |
||
474 | 1 | public function recomputeSingleEntityChangeSet(ApiMetadata $class, $entity) |
|
512 | |||
513 | /** |
||
514 | * Schedules an entity for insertion into the database. |
||
515 | * If the entity already has an identifier, it will be added to the identity map. |
||
516 | * |
||
517 | * @param object $entity The entity to schedule for insertion. |
||
518 | * |
||
519 | * @return void |
||
520 | * |
||
521 | * @throws \InvalidArgumentException |
||
522 | */ |
||
523 | 5 | public function scheduleForInsert($entity) |
|
546 | |||
547 | /** |
||
548 | * Checks whether an entity is scheduled for insertion. |
||
549 | * |
||
550 | * @param object $entity |
||
551 | * |
||
552 | * @return boolean |
||
553 | */ |
||
554 | 1 | public function isScheduledForInsert($entity) |
|
558 | |||
559 | /** |
||
560 | * Schedules an entity for being updated. |
||
561 | * |
||
562 | * @param object $entity The entity to schedule for being updated. |
||
563 | * |
||
564 | * @return void |
||
565 | * |
||
566 | * @throws \InvalidArgumentException |
||
567 | */ |
||
568 | public function scheduleForUpdate($entity) |
||
581 | |||
582 | /** |
||
583 | * Checks whether an entity is registered as dirty in the unit of work. |
||
584 | * Note: Is not very useful currently as dirty entities are only registered |
||
585 | * at commit time. |
||
586 | * |
||
587 | * @param object $entity |
||
588 | * |
||
589 | * @return boolean |
||
590 | */ |
||
591 | public function isScheduledForUpdate($entity) |
||
595 | |||
596 | /** |
||
597 | * Checks whether an entity is registered to be checked in the unit of work. |
||
598 | * |
||
599 | * @param object $entity |
||
600 | * |
||
601 | * @return boolean |
||
602 | */ |
||
603 | public function isScheduledForDirtyCheck($entity) |
||
609 | |||
610 | /** |
||
611 | * INTERNAL: |
||
612 | * Schedules an entity for deletion. |
||
613 | * |
||
614 | * @param object $entity |
||
615 | * |
||
616 | * @return void |
||
617 | */ |
||
618 | public function scheduleForDelete($entity) |
||
639 | |||
640 | /** |
||
641 | * Checks whether an entity is registered as removed/deleted with the unit |
||
642 | * of work. |
||
643 | * |
||
644 | * @param object $entity |
||
645 | * |
||
646 | * @return boolean |
||
647 | */ |
||
648 | public function isScheduledForDelete($entity) |
||
652 | |||
653 | /** |
||
654 | * Checks whether an entity is scheduled for insertion, update or deletion. |
||
655 | * |
||
656 | * @param object $entity |
||
657 | * |
||
658 | * @return boolean |
||
659 | */ |
||
660 | public function isEntityScheduled($entity) |
||
668 | |||
669 | /** |
||
670 | * INTERNAL: |
||
671 | * Removes an entity from the identity map. This effectively detaches the |
||
672 | * entity from the persistence management of Doctrine. |
||
673 | * |
||
674 | * @ignore |
||
675 | * |
||
676 | * @param object $entity |
||
677 | * |
||
678 | * @return boolean |
||
679 | * |
||
680 | * @throws \InvalidArgumentException |
||
681 | */ |
||
682 | public function removeFromIdentityMap($entity) |
||
701 | |||
702 | /** |
||
703 | * Commits the UnitOfWork, executing all operations that have been postponed |
||
704 | * up to this point. The state of all managed entities will be synchronized with |
||
705 | * the database. |
||
706 | * |
||
707 | * The operations are executed in the following order: |
||
708 | * |
||
709 | * 1) All entity insertions |
||
710 | * 2) All entity updates |
||
711 | * 3) All collection deletions |
||
712 | * 4) All collection updates |
||
713 | * 5) All entity deletions |
||
714 | * |
||
715 | * @param null|object|array $entity |
||
716 | * |
||
717 | * @return void |
||
718 | * |
||
719 | * @throws \Exception |
||
720 | */ |
||
721 | 5 | public function commit($entity = null) |
|
798 | |||
799 | /** |
||
800 | * Gets the changeset for an entity. |
||
801 | * |
||
802 | * @param object $entity |
||
803 | * |
||
804 | * @return array |
||
805 | */ |
||
806 | 1 | public function & getEntityChangeSet($entity) |
|
816 | |||
817 | /** |
||
818 | * Computes the changes that happened to a single entity. |
||
819 | * |
||
820 | * Modifies/populates the following properties: |
||
821 | * |
||
822 | * {@link _originalEntityData} |
||
823 | * If the entity is NEW or MANAGED but not yet fully persisted (only has an id) |
||
824 | * then it was not fetched from the database and therefore we have no original |
||
825 | * entity data yet. All of the current entity data is stored as the original entity data. |
||
826 | * |
||
827 | * {@link _entityChangeSets} |
||
828 | * The changes detected on all properties of the entity are stored there. |
||
829 | * A change is a tuple array where the first entry is the old value and the second |
||
830 | * entry is the new value of the property. Changesets are used by persisters |
||
831 | * to INSERT/UPDATE the persistent entity state. |
||
832 | * |
||
833 | * {@link _entityUpdates} |
||
834 | * If the entity is already fully MANAGED (has been fetched from the database before) |
||
835 | * and any changes to its properties are detected, then a reference to the entity is stored |
||
836 | * there to mark it for an update. |
||
837 | * |
||
838 | * {@link _collectionDeletions} |
||
839 | * If a PersistentCollection has been de-referenced in a fully MANAGED entity, |
||
840 | * then this collection is marked for deletion. |
||
841 | * |
||
842 | * @ignore |
||
843 | * |
||
844 | * @internal Don't call from the outside. |
||
845 | * |
||
846 | * @param ApiMetadata $class The class descriptor of the entity. |
||
847 | * @param object $entity The entity for which to compute the changes. |
||
848 | * |
||
849 | * @return void |
||
850 | */ |
||
851 | 5 | public function computeChangeSet(ApiMetadata $class, $entity) |
|
852 | { |
||
853 | 5 | $oid = spl_object_hash($entity); |
|
854 | 5 | if (isset($this->readOnlyObjects[$oid])) { |
|
855 | return; |
||
856 | } |
||
857 | |||
858 | 5 | $actualData = []; |
|
859 | 5 | foreach ($class->getReflectionProperties() as $name => $refProp) { |
|
860 | 5 | $value = $refProp->getValue($entity); |
|
861 | 5 | if ($class->isCollectionValuedAssociation($name) && $value !== null) { |
|
862 | 2 | if ($value instanceof ApiCollection) { |
|
863 | 1 | if ($value->getOwner() === $entity) { |
|
864 | 1 | continue; |
|
865 | } |
||
866 | $value = new ArrayCollection($value->getValues()); |
||
867 | } |
||
868 | // If $value is not a Collection then use an ArrayCollection. |
||
869 | 2 | if (!$value instanceof Collection) { |
|
870 | $value = new ArrayCollection($value); |
||
871 | } |
||
872 | 2 | $assoc = $class->getAssociationMapping($name); |
|
873 | // Inject PersistentCollection |
||
874 | 2 | $value = new ApiCollection( |
|
875 | 2 | $this->manager, |
|
876 | 2 | $this->manager->getClassMetadata($assoc['target']), |
|
877 | $value |
||
878 | 2 | ); |
|
879 | 2 | $value->setOwner($entity, $assoc); |
|
880 | 2 | $value->setDirty(!$value->isEmpty()); |
|
881 | 2 | $class->getReflectionProperty($name)->setValue($entity, $value); |
|
882 | 2 | $actualData[$name] = $value; |
|
883 | 2 | continue; |
|
884 | } |
||
885 | 5 | if (!$class->isIdentifier($name)) { |
|
886 | 5 | $actualData[$name] = $value; |
|
887 | 5 | } |
|
888 | 5 | } |
|
889 | 5 | if (!isset($this->originalEntityData[$oid])) { |
|
890 | // Entity is either NEW or MANAGED but not yet fully persisted (only has an id). |
||
891 | // These result in an INSERT. |
||
892 | 5 | $this->originalEntityData[$oid] = $actualData; |
|
893 | 5 | $changeSet = []; |
|
894 | 5 | foreach ($actualData as $propName => $actualValue) { |
|
895 | 5 | View Code Duplication | if (!$class->hasAssociation($propName)) { |
896 | 5 | $changeSet[$propName] = [null, $actualValue]; |
|
897 | 5 | continue; |
|
898 | } |
||
899 | 5 | $assoc = $class->getAssociationMapping($propName); |
|
900 | 5 | if ($assoc['isOwningSide'] && $assoc['type'] & ApiMetadata::TO_ONE) { |
|
901 | 5 | $changeSet[$propName] = [null, $actualValue]; |
|
902 | 5 | } |
|
903 | 5 | } |
|
904 | 5 | $this->entityChangeSets[$oid] = $changeSet; |
|
905 | 5 | } else { |
|
906 | // Entity is "fully" MANAGED: it was already fully persisted before |
||
907 | // and we have a copy of the original data |
||
908 | 2 | $originalData = $this->originalEntityData[$oid]; |
|
909 | 2 | $isChangeTrackingNotify = false; |
|
910 | 2 | $changeSet = ($isChangeTrackingNotify && isset($this->entityChangeSets[$oid])) |
|
911 | 2 | ? $this->entityChangeSets[$oid] |
|
912 | 2 | : []; |
|
913 | 2 | foreach ($actualData as $propName => $actualValue) { |
|
914 | |||
915 | // skip field, its a partially omitted one! |
||
916 | 2 | if (!isset($originalData->$propName)) { |
|
917 | continue; |
||
918 | } |
||
919 | 2 | $orgValue = $originalData->$propName; |
|
920 | // skip if value haven't changed |
||
921 | 2 | if ($orgValue === $actualValue) { |
|
922 | |||
923 | 2 | continue; |
|
924 | } |
||
925 | // if regular field |
||
926 | 1 | View Code Duplication | if (!$class->hasAssociation($propName)) { |
927 | if ($isChangeTrackingNotify) { |
||
928 | continue; |
||
929 | } |
||
930 | $changeSet[$propName] = [$orgValue, $actualValue]; |
||
931 | continue; |
||
932 | } |
||
933 | |||
934 | 1 | $assoc = $class->getAssociationMapping($propName); |
|
935 | // Persistent collection was exchanged with the "originally" |
||
936 | // created one. This can only mean it was cloned and replaced |
||
937 | // on another entity. |
||
938 | 1 | if ($actualValue instanceof ApiCollection) { |
|
939 | $owner = $actualValue->getOwner(); |
||
940 | if ($owner === null) { // cloned |
||
941 | $actualValue->setOwner($entity, $assoc); |
||
942 | } else { |
||
943 | if ($owner !== $entity) { // no clone, we have to fix |
||
944 | if (!$actualValue->isInitialized()) { |
||
945 | $actualValue->initialize(); // we have to do this otherwise the cols share state |
||
946 | } |
||
947 | $newValue = clone $actualValue; |
||
948 | $newValue->setOwner($entity, $assoc); |
||
949 | $class->getReflectionProperty($propName)->setValue($entity, $newValue); |
||
950 | } |
||
951 | } |
||
952 | } |
||
953 | 1 | if ($orgValue instanceof ApiCollection) { |
|
954 | // A PersistentCollection was de-referenced, so delete it. |
||
955 | $coid = spl_object_hash($orgValue); |
||
956 | if (isset($this->collectionDeletions[$coid])) { |
||
957 | continue; |
||
958 | } |
||
959 | $this->collectionDeletions[$coid] = $orgValue; |
||
960 | $changeSet[$propName] = $orgValue; // Signal changeset, to-many assocs will be ignored. |
||
961 | continue; |
||
962 | } |
||
963 | 1 | if ($assoc['type'] & ApiMetadata::TO_ONE) { |
|
964 | 1 | if ($assoc['isOwningSide']) { |
|
965 | 1 | $changeSet[$propName] = [$orgValue, $actualValue]; |
|
966 | 1 | } |
|
967 | 1 | if ($orgValue !== null && $assoc['orphanRemoval']) { |
|
968 | $this->scheduleOrphanRemoval($orgValue); |
||
969 | } |
||
970 | 1 | } |
|
971 | 2 | } |
|
972 | 2 | if ($changeSet) { |
|
973 | 1 | $this->entityChangeSets[$oid] = $changeSet; |
|
974 | 1 | $this->originalEntityData[$oid] = $actualData; |
|
975 | 1 | $this->entityUpdates[$oid] = $entity; |
|
976 | 1 | } |
|
977 | } |
||
978 | // Look for changes in associations of the entity |
||
979 | 5 | foreach ($class->getAssociationMappings() as $field => $assoc) { |
|
980 | 5 | if (($val = $class->getReflectionProperty($field)->getValue($entity)) === null) { |
|
981 | 5 | continue; |
|
982 | } |
||
983 | 2 | $this->computeAssociationChanges($assoc, $val); |
|
984 | 2 | if (!isset($this->entityChangeSets[$oid]) && |
|
985 | 2 | $assoc['isOwningSide'] && |
|
986 | 2 | $assoc['type'] == ApiMetadata::MANY_TO_MANY && |
|
987 | 2 | $val instanceof ApiCollection && |
|
988 | $val->isDirty() |
||
989 | 2 | ) { |
|
990 | $this->entityChangeSets[$oid] = []; |
||
991 | $this->originalEntityData[$oid] = $actualData; |
||
992 | $this->entityUpdates[$oid] = $entity; |
||
993 | } |
||
994 | 5 | } |
|
995 | 5 | } |
|
996 | |||
997 | /** |
||
998 | * Computes all the changes that have been done to entities and collections |
||
999 | * since the last commit and stores these changes in the _entityChangeSet map |
||
1000 | * temporarily for access by the persisters, until the UoW commit is finished. |
||
1001 | * |
||
1002 | * @return void |
||
1003 | */ |
||
1004 | 5 | public function computeChangeSets() |
|
1043 | |||
1044 | /** |
||
1045 | * INTERNAL: |
||
1046 | * Schedules an orphaned entity for removal. The remove() operation will be |
||
1047 | * invoked on that entity at the beginning of the next commit of this |
||
1048 | * UnitOfWork. |
||
1049 | * |
||
1050 | * @ignore |
||
1051 | * |
||
1052 | * @param object $entity |
||
1053 | * |
||
1054 | * @return void |
||
1055 | */ |
||
1056 | public function scheduleOrphanRemoval($entity) |
||
1060 | |||
1061 | 2 | public function loadCollection(ApiCollection $collection) |
|
1072 | |||
1073 | public function getCollectionPersister($association) |
||
1085 | |||
1086 | public function scheduleCollectionDeletion(Collection $collection) |
||
1089 | |||
1090 | 2 | public function cancelOrphanRemoval($value) |
|
1093 | |||
1094 | /** |
||
1095 | * INTERNAL: |
||
1096 | * Sets a property value of the original data array of an entity. |
||
1097 | * |
||
1098 | * @ignore |
||
1099 | * |
||
1100 | * @param string $oid |
||
1101 | * @param string $property |
||
1102 | * @param mixed $value |
||
1103 | * |
||
1104 | * @return void |
||
1105 | */ |
||
1106 | 10 | public function setOriginalEntityProperty($oid, $property, $value) |
|
1114 | |||
1115 | public function scheduleExtraUpdate($entity, $changeset) |
||
1125 | |||
1126 | /** |
||
1127 | * Refreshes the state of the given entity from the database, overwriting |
||
1128 | * any local, unpersisted changes. |
||
1129 | * |
||
1130 | * @param object $entity The entity to refresh. |
||
1131 | * |
||
1132 | * @return void |
||
1133 | * |
||
1134 | * @throws InvalidArgumentException If the entity is not MANAGED. |
||
1135 | */ |
||
1136 | public function refresh($entity) |
||
1141 | |||
1142 | /** |
||
1143 | * Clears the UnitOfWork. |
||
1144 | * |
||
1145 | * @param string|null $entityName if given, only entities of this type will get detached. |
||
1146 | * |
||
1147 | * @return void |
||
1148 | */ |
||
1149 | public function clear($entityName = null) |
||
1172 | |||
1173 | /** |
||
1174 | * @param PersistentCollection $coll |
||
1175 | * |
||
1176 | * @return bool |
||
1177 | */ |
||
1178 | public function isCollectionScheduledForDeletion(PersistentCollection $coll) |
||
1182 | |||
1183 | /** |
||
1184 | * Schedules an entity for dirty-checking at commit-time. |
||
1185 | * |
||
1186 | * @param object $entity The entity to schedule for dirty-checking. |
||
1187 | * |
||
1188 | * @return void |
||
1189 | * |
||
1190 | * @todo Rename: scheduleForSynchronization |
||
1191 | */ |
||
1192 | public function scheduleForDirtyCheck($entity) |
||
1198 | |||
1199 | /** |
||
1200 | * Deletes an entity as part of the current unit of work. |
||
1201 | * |
||
1202 | * @param object $entity The entity to remove. |
||
1203 | * |
||
1204 | * @return void |
||
1205 | */ |
||
1206 | public function remove($entity) |
||
1211 | |||
1212 | /** |
||
1213 | * Merges the state of the given detached entity into this UnitOfWork. |
||
1214 | * |
||
1215 | * @param object $entity |
||
1216 | * |
||
1217 | * @return object The managed copy of the entity. |
||
1218 | */ |
||
1219 | public function merge($entity) |
||
1225 | |||
1226 | /** |
||
1227 | * Detaches an entity from the persistence management. It's persistence will |
||
1228 | * no longer be managed by Doctrine. |
||
1229 | * |
||
1230 | * @param object $entity The entity to detach. |
||
1231 | * |
||
1232 | * @return void |
||
1233 | */ |
||
1234 | public function detach($entity) |
||
1239 | |||
1240 | /** |
||
1241 | * Helper method to show an object as string. |
||
1242 | * |
||
1243 | * @param object $obj |
||
1244 | * |
||
1245 | * @return string |
||
1246 | */ |
||
1247 | private static function objToStr($obj) |
||
1251 | |||
1252 | /** |
||
1253 | * @param ApiMetadata $class |
||
1254 | * |
||
1255 | * @return \Doctrine\Common\Persistence\ObjectManagerAware|object |
||
1256 | */ |
||
1257 | 12 | private function newInstance(ApiMetadata $class) |
|
1267 | |||
1268 | /** |
||
1269 | * @param ApiMetadata $classMetadata |
||
1270 | * |
||
1271 | * @return EntityDataCacheInterface |
||
1272 | */ |
||
1273 | 19 | private function createEntityCache(ApiMetadata $classMetadata) |
|
1293 | |||
1294 | /** |
||
1295 | * @param ApiMetadata $classMetadata |
||
1296 | * |
||
1297 | * @return CrudsApiInterface |
||
1298 | */ |
||
1299 | 19 | private function createApi(ApiMetadata $classMetadata) |
|
1314 | |||
1315 | 5 | private function doPersist($entity, $visited) |
|
1349 | |||
1350 | /** |
||
1351 | * Cascades the save operation to associated entities. |
||
1352 | * |
||
1353 | * @param object $entity |
||
1354 | * @param array $visited |
||
1355 | * |
||
1356 | * @return void |
||
1357 | * @throws \InvalidArgumentException |
||
1358 | * @throws MappingException |
||
1359 | */ |
||
1360 | 5 | private function cascadePersist($entity, array &$visited) |
|
1397 | |||
1398 | /** |
||
1399 | * @param ApiMetadata $class |
||
1400 | * @param object $entity |
||
1401 | * |
||
1402 | * @return void |
||
1403 | */ |
||
1404 | 5 | private function persistNew($class, $entity) |
|
1423 | |||
1424 | /** |
||
1425 | * Gets the commit order. |
||
1426 | * |
||
1427 | * @param array|null $entityChangeSet |
||
1428 | * |
||
1429 | * @return array |
||
1430 | */ |
||
1431 | 5 | private function getCommitOrder(array $entityChangeSet = null) |
|
1481 | |||
1482 | 5 | private function getCommitOrderCalculator() |
|
1486 | |||
1487 | /** |
||
1488 | * Only flushes the given entity according to a ruleset that keeps the UoW consistent. |
||
1489 | * |
||
1490 | * 1. All entities scheduled for insertion, (orphan) removals and changes in collections are processed as well! |
||
1491 | * 2. Read Only entities are skipped. |
||
1492 | * 3. Proxies are skipped. |
||
1493 | * 4. Only if entity is properly managed. |
||
1494 | * |
||
1495 | * @param object $entity |
||
1496 | * |
||
1497 | * @return void |
||
1498 | * |
||
1499 | * @throws \InvalidArgumentException |
||
1500 | */ |
||
1501 | private function computeSingleEntityChangeSet($entity) |
||
1528 | |||
1529 | /** |
||
1530 | * Computes the changesets of all entities scheduled for insertion. |
||
1531 | * |
||
1532 | * @return void |
||
1533 | */ |
||
1534 | 5 | private function computeScheduleInsertsChangeSets() |
|
1541 | |||
1542 | /** |
||
1543 | * Computes the changes of an association. |
||
1544 | * |
||
1545 | * @param array $assoc The association mapping. |
||
1546 | * @param mixed $value The value of the association. |
||
1547 | * |
||
1548 | * @throws \InvalidArgumentException |
||
1549 | * @throws \UnexpectedValueException |
||
1550 | * |
||
1551 | * @return void |
||
1552 | */ |
||
1553 | 2 | private function computeAssociationChanges($assoc, $value) |
|
1603 | |||
1604 | 5 | private function executeInserts(ApiMetadata $class) |
|
1650 | 1 | ||
1651 | 1 | private function executeUpdates($class) |
|
1667 | |||
1668 | /** |
||
1669 | * Executes a refresh operation on an entity. |
||
1670 | * |
||
1671 | * @param object $entity The entity to refresh. |
||
1672 | * @param array $visited The already visited entities during cascades. |
||
1673 | * |
||
1674 | * @return void |
||
1675 | * |
||
1676 | * @throws \InvalidArgumentException If the entity is not MANAGED. |
||
1677 | */ |
||
1678 | private function doRefresh($entity, array &$visited) |
||
1695 | |||
1696 | /** |
||
1697 | * Cascades a refresh operation to associated entities. |
||
1698 | * |
||
1699 | * @param object $entity |
||
1700 | * @param array $visited |
||
1701 | * |
||
1702 | * @return void |
||
1703 | */ |
||
1704 | View Code Duplication | private function cascadeRefresh($entity, array &$visited) |
|
1734 | |||
1735 | /** |
||
1736 | * Cascades a detach operation to associated entities. |
||
1737 | * |
||
1738 | * @param object $entity |
||
1739 | * @param array $visited |
||
1740 | * |
||
1741 | * @return void |
||
1742 | */ |
||
1743 | View Code Duplication | private function cascadeDetach($entity, array &$visited) |
|
1773 | |||
1774 | /** |
||
1775 | * Cascades a merge operation to associated entities. |
||
1776 | * |
||
1777 | * @param object $entity |
||
1778 | * @param object $managedCopy |
||
1779 | * @param array $visited |
||
1780 | * |
||
1781 | * @return void |
||
1782 | */ |
||
1783 | private function cascadeMerge($entity, $managedCopy, array &$visited) |
||
1812 | |||
1813 | /** |
||
1814 | * Cascades the delete operation to associated entities. |
||
1815 | * |
||
1816 | * @param object $entity |
||
1817 | * @param array $visited |
||
1818 | * |
||
1819 | * @return void |
||
1820 | */ |
||
1821 | private function cascadeRemove($entity, array &$visited) |
||
1855 | |||
1856 | /** |
||
1857 | * Executes any extra updates that have been scheduled. |
||
1858 | */ |
||
1859 | private function executeExtraUpdates() |
||
1868 | |||
1869 | private function executeDeletions(ApiMetadata $class) |
||
1892 | |||
1893 | /** |
||
1894 | * @param object $entity |
||
1895 | * @param object $managedCopy |
||
1896 | */ |
||
1897 | private function mergeEntityStateIntoManagedCopy($entity, $managedCopy) |
||
1974 | |||
1975 | /** |
||
1976 | * Deletes an entity as part of the current unit of work. |
||
1977 | * |
||
1978 | * This method is internally called during delete() cascades as it tracks |
||
1979 | * the already visited entities to prevent infinite recursions. |
||
1980 | * |
||
1981 | * @param object $entity The entity to delete. |
||
1982 | * @param array $visited The map of the already visited entities. |
||
1983 | * |
||
1984 | * @return void |
||
1985 | * |
||
1986 | * @throws \InvalidArgumentException If the instance is a detached entity. |
||
1987 | * @throws \UnexpectedValueException |
||
1988 | */ |
||
1989 | private function doRemove($entity, array &$visited) |
||
2015 | |||
2016 | /** |
||
2017 | * Tests if an entity is loaded - must either be a loaded proxy or not a proxy |
||
2018 | * |
||
2019 | * @param object $entity |
||
2020 | * |
||
2021 | * @return bool |
||
2022 | */ |
||
2023 | private function isLoaded($entity) |
||
2027 | |||
2028 | /** |
||
2029 | * Sets/adds associated managed copies into the previous entity's association field |
||
2030 | * |
||
2031 | * @param object $entity |
||
2032 | * @param array $association |
||
2033 | * @param object $previousManagedCopy |
||
2034 | * @param object $managedCopy |
||
2035 | * |
||
2036 | * @return void |
||
2037 | */ |
||
2038 | private function updateAssociationWithMergedEntity($entity, array $association, $previousManagedCopy, $managedCopy) |
||
2055 | |||
2056 | /** |
||
2057 | * Executes a merge operation on an entity. |
||
2058 | * |
||
2059 | * @param object $entity |
||
2060 | * @param array $visited |
||
2061 | * @param object|null $prevManagedCopy |
||
2062 | * @param array|null $assoc |
||
2063 | * |
||
2064 | * @return object The managed copy of the entity. |
||
2065 | * |
||
2066 | * @throws \InvalidArgumentException If the entity instance is NEW. |
||
2067 | * @throws \OutOfBoundsException |
||
2068 | */ |
||
2069 | private function doMerge($entity, array &$visited, $prevManagedCopy = null, array $assoc = []) |
||
2139 | |||
2140 | /** |
||
2141 | * Executes a detach operation on the given entity. |
||
2142 | * |
||
2143 | * @param object $entity |
||
2144 | * @param array $visited |
||
2145 | * @param boolean $noCascade if true, don't cascade detach operation. |
||
2146 | * |
||
2147 | * @return void |
||
2148 | */ |
||
2149 | private function doDetach($entity, array &$visited, $noCascade = false) |
||
2178 | } |
||
2179 |
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.