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 |
||
| 21 | class ChronosJobComparisonBusinessCase extends AbstractJobComparisionBusinessCase |
||
| 22 | { |
||
| 23 | /** |
||
| 24 | * @var DatePeriodFactoryInterface |
||
| 25 | */ |
||
| 26 | private $datePeriodFactory; |
||
| 27 | |||
| 28 | /** |
||
| 29 | * @var LoggerInterface |
||
| 30 | */ |
||
| 31 | private $logger; |
||
| 32 | |||
| 33 | |||
| 34 | /** |
||
| 35 | * @param JobRepositoryInterface $jobRepositoryLocalChronos |
||
| 36 | * @param JobRepositoryInterface $jobRepositoryChronos |
||
| 37 | * @param DiffCompareInterface $diffCompare |
||
| 38 | * @param DatePeriodFactoryInterface $datePeriodFactory |
||
| 39 | * @param LoggerInterface $logger |
||
| 40 | */ |
||
| 41 | 7 | public function __construct( |
|
| 54 | |||
| 55 | |||
| 56 | 5 | protected function preCompareModifications(JobEntityInterface &$localJob, JobEntityInterface &$remoteJob) |
|
| 61 | |||
| 62 | |||
| 63 | protected function getEntitySetWithDefaults() |
||
| 64 | { |
||
| 65 | return new ChronosJobEntity(); |
||
| 66 | } |
||
| 67 | |||
| 68 | /** |
||
| 69 | * @param JobEntityInterface|ChronosJobEntity $jobEntityA |
||
| 70 | * @param JobEntityInterface|ChronosJobEntity $jobEntityB |
||
| 71 | * @return bool |
||
| 72 | */ |
||
| 73 | 2 | public function hasSameJobType(JobEntityInterface $jobEntityA, JobEntityInterface $jobEntityB) |
|
| 80 | |||
| 81 | /** |
||
| 82 | * @param string $property |
||
| 83 | * @param JobEntityInterface $jobEntityA |
||
| 84 | * @param JobEntityInterface $jobEntityB |
||
| 85 | * @return bool |
||
| 86 | */ |
||
| 87 | 5 | protected function isEntityEqual($property, JobEntityInterface $jobEntityA, JobEntityInterface $jobEntityB) |
|
| 88 | { |
||
| 89 | 5 | if (!$jobEntityA instanceof ChronosJobEntity || |
|
| 90 | 5 | !$jobEntityB instanceof ChronosJobEntity |
|
| 91 | ) { |
||
| 92 | throw new \RuntimeException('Required ChronosJobEntity. Something else encountered'); |
||
| 93 | } |
||
| 94 | |||
| 95 | 5 | $valueA = $jobEntityA->{$property}; |
|
| 96 | 5 | $valueB = $jobEntityB->{$property}; |
|
| 97 | |||
| 98 | switch ($property) { |
||
| 99 | 5 | case 'schedule': |
|
| 100 | 1 | return $this->isSchedulePropertyIdentical($jobEntityA, $jobEntityB); |
|
| 101 | |||
| 102 | 5 | case 'scheduleTimeZone': |
|
| 103 | 1 | return $this->isScheduleTimeZonePropertyIdentical($jobEntityA, $jobEntityB); |
|
| 104 | |||
| 105 | 4 | case 'parents': |
|
| 106 | return ( |
||
| 107 | is_array($valueA) |
||
| 108 | && is_array($valueB) |
||
| 109 | && count(array_diff($valueA, $valueB)) == 0 |
||
| 110 | && count(array_diff($valueB, $valueA)) == 0 |
||
| 111 | ); |
||
| 112 | |||
| 113 | 4 | case 'successCount': |
|
| 114 | 4 | case 'lastSuccess': |
|
| 115 | 4 | case 'errorCount': |
|
| 116 | 4 | case 'errorsSinceLastSuccess': |
|
| 117 | 4 | case 'lastError': |
|
| 118 | return true; |
||
| 119 | |||
| 120 | default: |
||
| 121 | 4 | return ($valueA == $valueB); |
|
| 122 | } |
||
| 123 | } |
||
| 124 | |||
| 125 | /** |
||
| 126 | * @param ChronosJobEntity $jobEntityA |
||
| 127 | * @param ChronosJobEntity $jobEntityB |
||
| 128 | * @return bool |
||
| 129 | */ |
||
| 130 | 1 | private function isScheduleTimeZonePropertyIdentical(ChronosJobEntity $jobEntityA, ChronosJobEntity $jobEntityB) |
|
| 131 | { |
||
| 132 | 1 | if ($jobEntityA->scheduleTimeZone == $jobEntityB->scheduleTimeZone) { |
|
| 133 | return true; |
||
| 134 | } |
||
| 135 | |||
| 136 | 1 | if (!empty($jobEntityA->schedule) && !empty($jobEntityB->schedule)) { |
|
| 137 | 1 | $dateA = $this->createDateTimeObj($jobEntityA->schedule, $jobEntityA->scheduleTimeZone); |
|
| 138 | 1 | $dateB = $this->createDateTimeObj($jobEntityB->schedule, $jobEntityB->scheduleTimeZone); |
|
| 139 | |||
| 140 | 1 | return ($dateA->getOffset() == $dateB->getOffset()); |
|
| 141 | } |
||
| 142 | |||
| 143 | return false; |
||
| 144 | } |
||
| 145 | |||
| 146 | /** |
||
| 147 | * @param ChronosJobEntity $jobEntityA |
||
| 148 | * @param ChronosJobEntity $jobEntityB |
||
| 149 | * @return bool |
||
| 150 | */ |
||
| 151 | 1 | private function isSchedulePropertyIdentical(ChronosJobEntity $jobEntityA, ChronosJobEntity $jobEntityB) |
|
| 152 | { |
||
| 153 | // if values are exact the same |
||
| 154 | 1 | if ($jobEntityA->schedule === $jobEntityB->schedule) { |
|
| 155 | $this->logger->debug(sprintf('%s::EXCACT INTERVAL FOR "%s"', 'ScheduleComparison', $jobEntityA->name)); |
||
| 156 | return true; |
||
| 157 | } |
||
| 158 | |||
| 159 | // if one value is empty and not both, compare the time periods |
||
| 160 | 1 | if (!empty($jobEntityA->schedule) && !empty($jobEntityB->schedule)) { |
|
| 161 | 1 | $iso8601EntityA = $this->datePeriodFactory->createIso8601Entity($jobEntityA->schedule); |
|
| 162 | 1 | $iso8601EntityB = $this->datePeriodFactory->createIso8601Entity($jobEntityB->schedule); |
|
| 163 | |||
| 164 | // if the clean interval is different return directly false (P1D != P1M) |
||
| 165 | 1 | if ($iso8601EntityA->interval != $iso8601EntityB->interval) { |
|
| 166 | 1 | $this->logger->debug(sprintf('%s::DIFFERENT INTERVAL FOR "%s"', 'ScheduleComparison', $jobEntityA->name)); |
|
| 167 | 1 | return false; |
|
| 168 | } |
||
| 169 | |||
| 170 | // else if the interval is <= 1Min return directly true (performance) |
||
| 171 | 1 | if ($iso8601EntityA->interval == 'PT1M' || $iso8601EntityA->interval == 'PT1S') { |
|
| 172 | 1 | $this->logger->debug(sprintf('%s::PT1M|PT1S INTERVAL FOR "%s" - Job execution should be equal', 'ScheduleComparison', $jobEntityA->name)); |
|
| 173 | 1 | return true; |
|
| 174 | } |
||
| 175 | |||
| 176 | // start to check by DatePeriods |
||
| 177 | 1 | $lastDateTimeA = null; |
|
| 178 | 1 | $lastDateTimeB = null; |
|
| 179 | |||
| 180 | /** @var \DatePeriod $periodB */ |
||
| 181 | 1 | $periodA = $this->datePeriodFactory->createDatePeriod($jobEntityA->schedule, $jobEntityA->scheduleTimeZone); |
|
| 182 | |||
| 183 | /** @var \DateTime $dateTime */ |
||
| 184 | 1 | foreach ($periodA as $dateTime) { |
|
| 185 | 1 | $lastDateTimeA = $dateTime; |
|
| 186 | } |
||
| 187 | |||
| 188 | /** @var \DatePeriod $periodB */ |
||
| 189 | 1 | $periodB = $this->datePeriodFactory->createDatePeriod($jobEntityB->schedule, $jobEntityB->scheduleTimeZone); |
|
| 190 | |||
| 191 | /** @var \DateTime $dateTime */ |
||
| 192 | 1 | foreach ($periodB as $dateTime) { |
|
| 193 | 1 | $lastDateTimeB = $dateTime; |
|
| 194 | } |
||
| 195 | |||
| 196 | // $lastDateTimeA !== false happen if no dates are in the period |
||
| 197 | 1 | if ($lastDateTimeA !== null && $lastDateTimeB !== null) { |
|
| 198 | 1 | $diffInterval = $lastDateTimeA->diff($lastDateTimeB); |
|
| 199 | 1 | $formattedDiffInterval = (int) $diffInterval->format('%Y%M%D%H%I'); |
|
| 200 | |||
| 201 | 1 | $this->logger->debug(sprintf('%s::INTERVAL DIFF OF "%d" FOR "%s"', 'ScheduleComparison', $formattedDiffInterval, $jobEntityA->name)); |
|
| 202 | 1 | return ($formattedDiffInterval == 0); |
|
| 203 | } |
||
| 204 | } |
||
| 205 | |||
| 206 | $this->logger->warning(sprintf('%s::CAN\'T COMPARE INTERVAL FOR "%s"', 'ScheduleComparison', $jobEntityA->name)); |
||
| 207 | return false; |
||
| 208 | } |
||
| 209 | |||
| 210 | /** |
||
| 211 | * @param string $iso8601String |
||
| 212 | * @param string $timeZone |
||
| 213 | * @return \DateTime |
||
| 214 | */ |
||
| 215 | 1 | private function createDateTimeObj($iso8601String, $timeZone = '') |
|
| 228 | } |
||
| 229 |