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 |
||
| 13 | class EntityVersionLockService |
||
| 14 | { |
||
| 15 | /** |
||
| 16 | * @var ObjectManager |
||
| 17 | */ |
||
| 18 | private $objectManager; |
||
| 19 | |||
| 20 | /** |
||
| 21 | * @var int |
||
| 22 | */ |
||
| 23 | private $threshold; |
||
| 24 | |||
| 25 | /** |
||
| 26 | * @var bool |
||
| 27 | */ |
||
| 28 | private $lockEnabled; |
||
| 29 | |||
| 30 | 6 | public function __construct(ObjectManager $em, $threshold, $lockEnabled) |
|
| 36 | |||
| 37 | /** |
||
| 38 | * @param LockableEntityInterface $entity |
||
| 39 | * |
||
| 40 | * @return bool |
||
| 41 | */ |
||
| 42 | 3 | public function isEntityBelowThreshold(LockableEntityInterface $entity) |
|
| 57 | |||
| 58 | /** |
||
| 59 | * @param User $user |
||
| 60 | * @param LockableEntityInterface $entity |
||
| 61 | * |
||
| 62 | * @return bool |
||
| 63 | */ |
||
| 64 | 2 | public function isEntityLocked(/*\Kunstmaan\AdminBundle\Entity\UserInterface*/ $user, LockableEntityInterface $entity) |
|
| 65 | { |
||
| 66 | // NEXT_MAJOR: remove type check and enable parameter typehint |
||
| 67 | 2 | View Code Duplication | if (!$user instanceof User && !$user instanceof UserInterface) { |
|
|
|||
| 68 | throw new \InvalidArgumentException(sprintf('The "$user" argument must be of type "%s" or implement the "%s" interface', User::class, UserInterface::class)); |
||
| 69 | } |
||
| 70 | |||
| 71 | /** @var LockableEntity $lockable */ |
||
| 72 | 2 | $lockable = $this->getLockableEntity($entity); |
|
| 73 | |||
| 74 | 2 | if ($this->lockEnabled) { |
|
| 75 | 2 | $this->removeExpiredLocks($lockable); |
|
| 76 | 2 | $locks = $this->getEntityVersionLocksByLockableEntity($lockable, $user); |
|
| 77 | |||
| 78 | 2 | if ($locks === null || !\count($locks)) { |
|
| 79 | 1 | $this->createEntityVersionLock($user, $lockable); |
|
| 80 | |||
| 81 | 1 | $lockable->setUpdated(new \DateTime()); |
|
| 82 | 1 | $this->objectManager->flush(); |
|
| 83 | |||
| 84 | 1 | return false; |
|
| 85 | } |
||
| 86 | |||
| 87 | 1 | return true; |
|
| 88 | } |
||
| 89 | |||
| 90 | return false; |
||
| 91 | } |
||
| 92 | |||
| 93 | /** |
||
| 94 | * When editing the entity, create a new entity translation lock. |
||
| 95 | * |
||
| 96 | * @param User $user |
||
| 97 | * @param LockableEntity $entity |
||
| 98 | */ |
||
| 99 | 1 | protected function createEntityVersionLock(/*\Kunstmaan\AdminBundle\Entity\UserInterface*/ $user, LockableEntity $entity) |
|
| 100 | { |
||
| 101 | // NEXT_MAJOR: remove type check and enable parameter typehint |
||
| 102 | 1 | View Code Duplication | if (!$user instanceof User && !$user instanceof UserInterface) { |
| 103 | throw new \InvalidArgumentException(sprintf('The "$user" argument must be of type "%s" or implement the "%s" interface', User::class, UserInterface::class)); |
||
| 104 | } |
||
| 105 | |||
| 106 | /** @var EntityVersionLock $lock */ |
||
| 107 | 1 | $lock = $this->objectManager->getRepository(EntityVersionLock::class)->findOneBy([ |
|
| 108 | 1 | 'owner' => $user->getUsername(), |
|
| 109 | 1 | 'lockableEntity' => $entity, |
|
| 110 | ]); |
||
| 111 | 1 | if (!$lock) { |
|
| 112 | $lock = new EntityVersionLock(); |
||
| 113 | } |
||
| 114 | 1 | $lock->setOwner($user->getUsername()); |
|
| 115 | 1 | $lock->setLockableEntity($entity); |
|
| 116 | 1 | $lock->setCreatedAt(new \DateTime()); |
|
| 117 | 1 | $this->objectManager->persist($lock); |
|
| 118 | 1 | $this->objectManager->flush(); |
|
| 119 | 1 | } |
|
| 120 | |||
| 121 | /** |
||
| 122 | * @param LockableEntityInterface $entity |
||
| 123 | * @param User $userToExclude |
||
| 124 | * |
||
| 125 | * @return array |
||
| 126 | */ |
||
| 127 | 1 | public function getUsersWithEntityVersionLock(LockableEntityInterface $entity, /*\Kunstmaan\AdminBundle\Entity\UserInterface*/ $userToExclude = null) |
|
| 128 | { |
||
| 129 | // NEXT_MAJOR: remove type check and enable parameter typehint |
||
| 130 | 1 | View Code Duplication | if (!$userToExclude instanceof User && !$userToExclude instanceof UserInterface) { |
| 131 | throw new \InvalidArgumentException(sprintf('The "$userToExclude" argument must be of type "%s" or implement the "%s" interface', User::class, UserInterface::class)); |
||
| 132 | } |
||
| 133 | |||
| 134 | /** @var LockableEntity $lockable */ |
||
| 135 | 1 | $lockable = $this->getLockableEntity($entity); |
|
| 136 | |||
| 137 | 1 | return array_reduce( |
|
| 138 | 1 | $this->getEntityVersionLocksByLockableEntity($lockable, $userToExclude), |
|
| 139 | function ($return, EntityVersionLock $item) { |
||
| 140 | 1 | $return[] = $item->getOwner(); |
|
| 141 | |||
| 142 | 1 | return $return; |
|
| 143 | 1 | }, |
|
| 144 | 1 | [] |
|
| 145 | ); |
||
| 146 | } |
||
| 147 | |||
| 148 | /** |
||
| 149 | * @param LockableEntity $entity |
||
| 150 | */ |
||
| 151 | 2 | protected function removeExpiredLocks(LockableEntity $entity) |
|
| 158 | |||
| 159 | /** |
||
| 160 | * When editing an entity, check if there is a lock for this entity. |
||
| 161 | * |
||
| 162 | * @param LockableEntity $entity |
||
| 163 | * @param User $userToExclude |
||
| 164 | * |
||
| 165 | * @return EntityVersionLock[] |
||
| 166 | */ |
||
| 167 | 3 | protected function getEntityVersionLocksByLockableEntity(LockableEntity $entity, /*\Kunstmaan\AdminBundle\Entity\UserInterface*/ $userToExclude = null) |
|
| 179 | |||
| 180 | /** |
||
| 181 | * Get or create a LockableEntity for an entity with LockableEntityInterface |
||
| 182 | * |
||
| 183 | * @param LockableEntityInterface $entity |
||
| 184 | * |
||
| 185 | * @return LockableEntity |
||
| 186 | */ |
||
| 187 | 6 | protected function getLockableEntity(LockableEntityInterface $entity, $create = true) |
|
| 199 | |||
| 200 | /** |
||
| 201 | * @param ObjectManager $objectManager |
||
| 202 | */ |
||
| 203 | 6 | public function setObjectManager($objectManager) |
|
| 207 | |||
| 208 | /** |
||
| 209 | * @param int $threshold |
||
| 210 | */ |
||
| 211 | 6 | public function setThreshold($threshold) |
|
| 215 | |||
| 216 | /** |
||
| 217 | * @param bool lockEnabled |
||
| 218 | */ |
||
| 219 | 6 | public function setLockEnabled($lockEnabled) |
|
| 223 | } |
||
| 224 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.