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:
| 1 | <?php |
||
| 19 | class objectmanager |
||
| 20 | { |
||
| 21 | private $em; |
||
| 22 | |||
| 23 | 114 | public function __construct(EntityManager $em) |
|
| 27 | |||
| 28 | 114 | public function create(dbobject $entity) |
|
| 29 | { |
||
| 30 | 114 | foreach ($this->em->getClassMetadata(get_class($entity))->getAssociationNames() as $name) { |
|
| 31 | 101 | if (!empty($entity->$name)) { |
|
| 32 | //This makes sure that we don't have stale references |
||
| 33 | 30 | $entity->$name = $entity->$name; |
|
| 34 | 30 | } |
|
| 35 | 114 | } |
|
| 36 | |||
| 37 | //workaround for possible oid collisions in UnitOfWork |
||
| 38 | //see http://www.doctrine-project.org/jira/browse/DDC-2785 |
||
| 39 | 114 | View Code Duplication | if ($this->em->getUnitOfWork()->getEntityState($entity) != UnitOfWork::STATE_NEW) { |
| 40 | connection::log()->warning('oid collision during create detected, detaching ' . spl_object_hash($entity)); |
||
| 41 | $this->em->detach($entity); |
||
| 42 | } |
||
| 43 | |||
| 44 | 114 | $this->em->persist($entity); |
|
| 45 | 114 | $this->em->flush($entity); |
|
| 46 | 114 | $this->em->detach($entity); |
|
| 47 | 114 | } |
|
| 48 | |||
| 49 | 15 | public function update(dbobject $entity) |
|
| 50 | { |
||
| 51 | // if entities are loaded by querybuilder, they are managed at this point already, |
||
| 52 | // which can in very rare (and very unreproducable) circumstances lead to the update |
||
| 53 | // getting lost silently (because originalEntityData somehow is empty), so we detach |
||
| 54 | // before doing anything else |
||
| 55 | 15 | $this->em->detach($entity); |
|
| 56 | 15 | $merged = $this->em->merge($entity); |
|
| 57 | 15 | $this->copy_associations($entity, $merged); |
|
| 58 | 15 | $this->em->persist($merged); |
|
| 59 | 15 | $this->em->flush($merged); |
|
| 60 | 15 | $this->em->detach($merged); |
|
| 61 | 15 | $this->copy_metadata($merged, $entity); |
|
| 62 | 15 | } |
|
| 63 | |||
| 64 | /** |
||
| 65 | * This is basically a workaround for some quirks when merging detached entities with changed associations |
||
| 66 | * |
||
| 67 | * @todo: This may or may not be a bug in Doctrine |
||
| 68 | */ |
||
| 69 | 15 | private function copy_associations($source, $target) |
|
| 75 | |||
| 76 | 26 | private function kill_potential_proxies($entity) |
|
| 77 | { |
||
| 78 | 26 | $classname = ClassUtils::getRealClass(get_class($entity)); |
|
| 79 | 26 | $cm = $this->em->getClassMetadata($classname); |
|
| 80 | 26 | $changed_associations = $entity->__get_changed_associations(); |
|
| 81 | |||
| 82 | 26 | foreach ($cm->getAssociationNames() as $name) { |
|
| 83 | 23 | if ($entity->$name === 0) { |
|
| 84 | //This is necessary to kill potential proxy objects pointing to purged entities |
||
| 85 | 20 | $entity->$name = 0; |
|
| 86 | 23 | } elseif (!array_key_exists($name, $changed_associations)) { |
|
| 87 | 10 | $value = $cm->getReflectionProperty($name)->getValue($entity); |
|
| 88 | 10 | if ($value instanceof Proxy) { |
|
| 89 | //This makes sure that the associated entity doesn't end up in the changeset calculation |
||
| 90 | 10 | $value->__isInitialized__ = false; |
|
| 91 | 10 | continue; |
|
| 92 | } |
||
| 93 | } |
||
| 94 | 26 | } |
|
| 95 | 26 | } |
|
| 96 | |||
| 97 | 26 | public function delete(dbobject $entity) |
|
| 98 | { |
||
| 99 | //we might deal with a proxy here, so we translate the classname |
||
| 100 | 26 | $classname = ClassUtils::getRealClass(get_class($entity)); |
|
| 101 | 26 | $copy = new $classname($entity->id); |
|
| 102 | |||
| 103 | //workaround for possible oid collisions in UnitOfWork |
||
| 104 | //see http://www.doctrine-project.org/jira/browse/DDC-2785 |
||
| 105 | 26 | View Code Duplication | if ($this->em->getUnitOfWork()->getEntityState($copy) != UnitOfWork::STATE_DETACHED) { |
| 106 | connection::log()->warning('oid collision during delete detected, detaching ' . spl_object_hash($copy)); |
||
| 107 | $this->em->detach($copy); |
||
| 108 | } |
||
| 109 | |||
| 110 | 26 | $copy = $this->em->merge($copy); |
|
| 111 | 26 | $this->kill_potential_proxies($copy); |
|
| 112 | 26 | $copy->metadata_deleted = true; |
|
| 113 | |||
| 114 | 26 | $this->em->persist($copy); |
|
| 115 | 26 | $this->em->flush($copy); |
|
| 116 | 26 | $this->em->detach($copy); |
|
| 117 | 26 | $this->em->detach($entity); |
|
| 118 | 26 | $this->copy_metadata($copy, $entity, 'delete'); |
|
| 119 | 26 | } |
|
| 120 | |||
| 121 | 3 | public function undelete(dbobject $entity) |
|
| 130 | |||
| 131 | 18 | public function purge(dbobject $entity) |
|
| 132 | { |
||
| 133 | 18 | $this->em->getFilters()->disable('softdelete'); |
|
| 134 | try { |
||
| 143 | |||
| 144 | 2 | View Code Duplication | public function approve(dbobject $entity) |
| 157 | |||
| 158 | 1 | View Code Duplication | public function unapprove(dbobject $entity) |
| 171 | |||
| 172 | 2 | View Code Duplication | public function lock(dbobject $entity) |
| 185 | |||
| 186 | 1 | public function unlock(dbobject $entity) |
|
| 196 | |||
| 197 | /** |
||
| 198 | * @param string $classname |
||
| 199 | * @return dbobject |
||
| 200 | */ |
||
| 201 | 114 | public function new_instance($classname) |
|
| 218 | |||
| 219 | 39 | private function copy_metadata($source, $target, $action = 'update') |
|
| 241 | } |
||
| 242 |
The
EntityManagermight become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:If that code throws an exception and the
EntityManageris closed. Any other code which depends on the same instance of theEntityManagerduring this request will fail.On the other hand, if you instead inject the
ManagerRegistry, thegetManager()method guarantees that you will always get a usable manager instance.