GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#45)
by Marc
02:47
created

JobComparisonBusinessCase   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 349
Duplicated Lines 2.58 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 72.9%

Importance

Changes 11
Bugs 4 Features 3
Metric Value
wmc 46
c 11
b 4
f 3
lcom 1
cbo 7
dl 9
loc 349
ccs 113
cts 155
cp 0.729
rs 8.4

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getLocalMissingJobs() 0 7 1
A getChronosMissingJobs() 0 7 1
B getLocalJobUpdates() 0 23 4
A getJobDiff() 0 22 2
A hasSameJobType() 0 7 4
B compareJobEntities() 0 29 4
A isScheduleTimeZonePropertyIdentical() 0 17 4
C isSchedulePropertyIdentical() 0 59 9
A createDateTimeObj() 9 16 2
A isEqualInterval() 0 7 1
A getMissingJobsInCollectionA() 0 7 1
A __construct() 0 14 1
C isJobEntityValueIdentical() 0 32 12

How to fix   Duplicated Code    Complexity   

Duplicated Code

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 Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like JobComparisonBusinessCase 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 JobComparisonBusinessCase, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package: chapi
4
 *
5
 * @author:  msiebeneicher
6
 * @since:   2015-07-29
7
 *
8
 */
9
10
namespace Chapi\BusinessCase\Comparison;
11
12
use Chapi\Component\Comparison\DiffCompareInterface;
13
use Chapi\Component\DatePeriod\DatePeriodFactoryInterface;
14
use Chapi\Entity\Chronos\JobCollection;
15
use Chapi\Entity\Chronos\JobEntity;
16
use Chapi\Service\JobRepository\JobRepositoryInterface;
17
use Psr\Log\LoggerInterface;
18
19
class JobComparisonBusinessCase implements JobComparisonInterface
20
{
21
    /**
22
     * @var JobRepositoryInterface
23
     */
24
    private $oJobRepositoryLocal;
25
26
    /**
27
     * @var JobRepositoryInterface
28
     */
29
    private $oJobRepositoryChronos;
30
31
    /**
32
     * @var DiffCompareInterface
33
     */
34
    private $oDiffCompare;
35
36
    /**
37
     * @var DatePeriodFactoryInterface
38
     */
39
    private $oDatePeriodFactory;
40
41
    /**
42
     * @var LoggerInterface
43
     */
44
    private $oLogger;
45
46
47
    /**
48
     * @param JobRepositoryInterface $oJobRepositoryLocal
49
     * @param JobRepositoryInterface $oJobRepositoryChronos
50
     * @param DiffCompareInterface $oDiffCompare
51
     * @param DatePeriodFactoryInterface $oDatePeriodFactory
52
     * @param LoggerInterface $oLogger
53
     */
54 4
    public function __construct(
55
        JobRepositoryInterface $oJobRepositoryLocal,
56
        JobRepositoryInterface $oJobRepositoryChronos,
57
        DiffCompareInterface $oDiffCompare,
58
        DatePeriodFactoryInterface $oDatePeriodFactory,
59
        LoggerInterface $oLogger
60
    )
61
    {
62 4
        $this->oJobRepositoryLocal = $oJobRepositoryLocal;
63 4
        $this->oJobRepositoryChronos = $oJobRepositoryChronos;
64 4
        $this->oDiffCompare = $oDiffCompare;
65 4
        $this->oDatePeriodFactory = $oDatePeriodFactory;
66 4
        $this->oLogger = $oLogger;
67 4
    }
68
69
    /**
70
     * @return string[]
0 ignored issues
show
Documentation introduced by
Should the return type not be array<integer|string>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
71
     */
72
    public function getLocalMissingJobs()
73
    {
74
        return $this->getMissingJobsInCollectionA(
75
            $this->oJobRepositoryLocal->getJobs(),
76
            $this->oJobRepositoryChronos->getJobs()
77
        );
78
    }
79
80
    /**
81
     * @return string[]
0 ignored issues
show
Documentation introduced by
Should the return type not be array<integer|string>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
82
     */
83
    public function getChronosMissingJobs()
84
    {
85
        return $this->getMissingJobsInCollectionA(
86
            $this->oJobRepositoryChronos->getJobs(),
87
            $this->oJobRepositoryLocal->getJobs()
88
        );
89
    }
90
91
    /**
92
     * @return string[]
93
     */
94 2
    public function getLocalJobUpdates()
95
    {
96 2
        $_aJobsLocal = $this->oJobRepositoryLocal->getJobs();
97 2
        $_aLocalJobUpdates = [];
98
99
        /** @var JobEntity $_oJobEntity */
100 2
        foreach ($_aJobsLocal as $_oJobEntityLocal)
101
        {
102 2
            $_oJobEntityChronos = $this->oJobRepositoryChronos->getJob($_oJobEntityLocal->name);
103
104
            // if job already exist in chronos (not new or deleted in chronos)
105 2
            if (!empty($_oJobEntityChronos->name))
106 2
            {
107 2
                $_aNonidenticalProperties = $this->compareJobEntities($_oJobEntityLocal, $_oJobEntityChronos);
108 2
                if (!empty($_aNonidenticalProperties))
109 2
                {
110 2
                    $_aLocalJobUpdates[] = $_oJobEntityLocal->name;
111 2
                }
112 2
            }
113 2
        }
114
115 2
        return $_aLocalJobUpdates;
116
    }
117
118
    /**
119
     * @param string $sJobName
120
     * @return string[]
121
     */
122
    public function getJobDiff($sJobName)
123
    {
124
        $_aReturn = [];
125
126
        $_oJobEntityLocal = $this->oJobRepositoryLocal->getJob($sJobName);
127
        $_oJobEntityChronos = $this->oJobRepositoryChronos->getJob($sJobName);
128
129
        $_aNonidenticalProperties = $this->compareJobEntities(
130
            $_oJobEntityLocal,
131
            $_oJobEntityChronos
132
        );
133
134
        foreach ($_aNonidenticalProperties as $_sProperty)
135
        {
136
            $_aReturn[$_sProperty] = $this->oDiffCompare->compare(
137
                $_oJobEntityChronos->{$_sProperty},
138
                $_oJobEntityLocal->{$_sProperty}
139
            );
140
        }
141
142
        return $_aReturn;
143
    }
144
145
    /**
146
     * @param JobEntity $oJobEntityA
147
     * @param JobEntity $oJobEntityB
148
     * @return bool
149
     */
150 2
    public function hasSameJobType(JobEntity $oJobEntityA, JobEntity $oJobEntityB)
151
    {
152
        return (
153 2
            ($oJobEntityA->isSchedulingJob() && $oJobEntityB->isSchedulingJob())
154 2
            || ($oJobEntityA->isDependencyJob() && $oJobEntityB->isDependencyJob())
155 2
        );
156
    }
157
158
    /**
159
     * @param JobEntity $oJobEntityA
160
     * @param JobEntity $oJobEntityB
161
     * @return array
162
     */
163 2
    private function compareJobEntities(JobEntity $oJobEntityA, JobEntity $oJobEntityB)
164
    {
165 2
        $_aNonidenticalProperties = [];
166
167 2
        $_aDiff = array_merge(
168 2
            array_diff_assoc(
169 2
                $oJobEntityA->getSimpleArrayCopy(),
170 2
                $oJobEntityB->getSimpleArrayCopy()
171 2
            ),
172 2
            array_diff_assoc(
173 2
                $oJobEntityB->getSimpleArrayCopy(),
174 2
                $oJobEntityA->getSimpleArrayCopy()
175 2
            )
176 2
        );
177
178 2
        if (count($_aDiff) > 0)
179 2
        {
180 2
            $_aDiffKeys = array_keys($_aDiff);
181 2
            foreach ($_aDiffKeys as $_sDiffKey)
182
            {
183 2
                if (!$this->isJobEntityValueIdentical($_sDiffKey, $oJobEntityA, $oJobEntityB))
184 2
                {
185 2
                    $_aNonidenticalProperties[] = $_sDiffKey;
186 2
                }
187 2
            }
188 2
        }
189
190 2
        return $_aNonidenticalProperties;
191
    }
192
193
    /**
194
     * @param string $sProperty
195
     * @param JobEntity $oJobEntityA
196
     * @param JobEntity $oJobEntityB
197
     * @return bool
198
     */
199 2
    private function isJobEntityValueIdentical($sProperty, JobEntity $oJobEntityA, JobEntity $oJobEntityB)
200
    {
201 2
        $mValueA = $oJobEntityA->{$sProperty};
202 2
        $mValueB = $oJobEntityB->{$sProperty};
203
204
        switch ($sProperty)
205
        {
206 2
            case 'schedule':
207 1
                return $this->isSchedulePropertyIdentical($oJobEntityA, $oJobEntityB);
208
209 2
            case 'scheduleTimeZone':
210 1
                return $this->isScheduleTimeZonePropertyIdentical($oJobEntityA, $oJobEntityB);
211
212 1
            case 'parents':
213
                return (
214
                    is_array($mValueA)
215
                    && is_array($mValueB)
216
                    && count(array_diff($mValueA, $mValueB)) == 0
217
                    && count(array_diff($mValueB, $mValueA)) == 0
218
                );
219
220 1
            case 'successCount':
221 1
            case 'lastSuccess':
222 1
            case 'errorCount':
223 1
            case 'errorsSinceLastSuccess':
224 1
            case 'lastError':
225
                return true;
226
227 1
            default:
228 1
                return ($mValueA == $mValueB);
229 1
        }
230
    }
231
232
    /**
233
     * @param JobEntity $oJobEntityA
234
     * @param JobEntity $oJobEntityB
235
     * @return bool
236
     */
237 1
    private function isScheduleTimeZonePropertyIdentical(JobEntity $oJobEntityA, JobEntity $oJobEntityB)
238
    {
239 1
        if ($oJobEntityA->scheduleTimeZone == $oJobEntityB->scheduleTimeZone)
240 1
        {
241
            return true;
242
        }
243
244 1
        if (!empty($oJobEntityA->schedule) && !empty($oJobEntityB->schedule))
245 1
        {
246 1
            $_oDateA = $this->createDateTimeObj($oJobEntityA->schedule, $oJobEntityA->scheduleTimeZone);
247 1
            $_oDateB = $this->createDateTimeObj($oJobEntityB->schedule, $oJobEntityB->scheduleTimeZone);
248
249 1
            return ($_oDateA->getOffset() == $_oDateB->getOffset());
250
        }
251
252
        return false;
253
    }
254
255
    /**
256
     * @param JobEntity $oJobEntityA
257
     * @param JobEntity $oJobEntityB
258
     * @return bool
259
     */
260 1
    private function isSchedulePropertyIdentical(JobEntity $oJobEntityA, JobEntity $oJobEntityB)
261
    {
262
        // if values are exact the same
263 1
        if ($oJobEntityA->schedule === $oJobEntityB->schedule)
264 1
        {
265
            $this->oLogger->debug(sprintf('%s::EXCACT INTERVAL FOR "%s"', 'ScheduleComparison', $oJobEntityA->name));
266
            return true;
267
        }
268
269
        // if one value is empty and not both, compare the time periods
270 1
        if (!empty($oJobEntityA->schedule) && !empty($oJobEntityB->schedule))
271 1
        {
272
            // if the clean interval is different return directly false (P1D != P1M)
273 1
            if (!$this->isEqualInterval($oJobEntityA->schedule, $oJobEntityB->schedule))
274 1
            {
275 1
                $this->oLogger->debug(sprintf('%s::DIFFERENT INTERVAL FOR "%s"', 'ScheduleComparison', $oJobEntityA->name));
276 1
                return false;
277
            }
278
279
            // start to check by DatePeriods
280 1
            $_aDatesA = [];
281 1
            $_aDatesB = [];
282
283
            /** @var \DatePeriod $_oPeriodB */
284 1
            $_oPeriodA = $this->oDatePeriodFactory->createDatePeriod($oJobEntityA->schedule, $oJobEntityA->scheduleTimeZone);
285
286
            /** @var \DateTime $_oDateTime */
287 1
            foreach ($_oPeriodA as $_oDateTime) {
288 1
                $_aDatesA[] = $_oDateTime;
289 1
            }
290
291
            /** @var \DatePeriod $_oPeriodB */
292 1
            $_oPeriodB = $this->oDatePeriodFactory->createDatePeriod($oJobEntityB->schedule, $oJobEntityB->scheduleTimeZone);
293
294
            /** @var \DateTime $_oDateTime */
295 1
            foreach ($_oPeriodB as $_oDateTime) {
296 1
                $_aDatesB[] = $_oDateTime;
297 1
            }
298
299
            /** @var \DateTime $_oLastDateTimeA */
300 1
            $_oLastDateTimeA = end($_aDatesA);
301
            /** @var \DateTime $_oLastDateTimeB */
302 1
            $_oLastDateTimeB = end($_aDatesB);
303
304
            // $_oLastDateTimeA !== false happen if no dates are in the period
305 1
            if ($_oLastDateTimeA !== false && $_oLastDateTimeB !== false)
306 1
            {
307 1
                $_oDiffInterval = $_oLastDateTimeA->diff($_oLastDateTimeB);
308 1
                $_iDiffInterval = (int) $_oDiffInterval->format('%Y%M%D%H%I');
309
310 1
                $this->oLogger->debug(sprintf('%s::INTERVAL DIFF OF "%d" FOR "%s"', 'ScheduleComparison', $_iDiffInterval, $oJobEntityA->name));
311
312 1
                return ($_iDiffInterval == 0);
313
            }
314
        }
315
316
        $this->oLogger->warning(sprintf('%s::CAN\'T COMPARE INTERVAL FOR "%s"', 'ScheduleComparison', $oJobEntityA->name));
317
        return false;
318
    }
319
320
    /**
321
     * @param string $sIso8601String
322
     * @param string $sTimeZone
323
     * @return \DateTime
324
     */
325 1
    private function createDateTimeObj($sIso8601String, $sTimeZone = '')
326
    {
327 1
        $_oIso8601Entity = $this->oDatePeriodFactory->createIso8601Entity($sIso8601String);
328
329 1 View Code Duplication
        if (!empty($sTimeZone))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
330 1
        {
331 1
            $_oDateTime = new \DateTime(str_replace('Z', '', $_oIso8601Entity->sStartTime));
332 1
            $_oDateTime->setTimezone(new \DateTimeZone($sTimeZone));
333 1
        }
334
        else
335
        {
336 1
            $_oDateTime = new \DateTime($_oIso8601Entity->sStartTime);
337
        }
338
339 1
        return $_oDateTime;
340
    }
341
342
    /**
343
     * @param string $sIso8601StringA
344
     * @param string $sIso8601StringB
345
     * @return bool
346
     */
347 1
    private function isEqualInterval($sIso8601StringA, $sIso8601StringB)
348
    {
349 1
        $_oIso8601EntityA = $this->oDatePeriodFactory->createIso8601Entity($sIso8601StringA);
350 1
        $_oIso8601EntityB = $this->oDatePeriodFactory->createIso8601Entity($sIso8601StringB);
351
352 1
        return ($_oIso8601EntityA->sInterval == $_oIso8601EntityB->sInterval);
353
    }
354
355
    /**
356
     * @param JobCollection $oJobCollectionA
357
     * @param JobCollection $oJobCollectionB
358
     * @return string[]
0 ignored issues
show
Documentation introduced by
Should the return type not be array<integer|string>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
359
     */
360
    private function getMissingJobsInCollectionA(JobCollection $oJobCollectionA, JobCollection $oJobCollectionB)
361
    {
362
        return array_diff(
363
            array_keys($oJobCollectionB->getArrayCopy()),
364
            array_keys($oJobCollectionA->getArrayCopy())
365
        );
366
    }
367
}