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
Push — master ( 0c6bcd...b3f485 )
by Andy
11s
created

SchedulingViewCommand   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 371
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 12

Test Coverage

Coverage 97.99%

Importance

Changes 0
Metric Value
wmc 45
lcom 2
cbo 12
dl 0
loc 371
ccs 146
cts 149
cp 0.9799
rs 8.3673
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 8 1
B process() 0 26 5
A getJobStartTimesInPeriod() 0 15 3
A createDatePeriodForJob() 0 5 1
A createDatePeriod() 0 16 3
B getJobsWhichShouldStartInPeriod() 0 21 6
C getTimelineStr() 0 60 9
B printTimeLineTable() 0 44 4
B printChildJobs() 0 42 3
B parseTimeLineStrMark() 0 16 5
B isPeriodInTimeFrame() 0 21 5

How to fix   Complexity   

Complex Class

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

1
<?php
2
/**
3
 * @package: chapi
4
 *
5
 * @author:  msiebeneicher
6
 * @since:   2015-09-09
7
 *
8
 * @link:    https://github.com/msiebeneicher/chapi/issues/24
9
 */
10
11
12
namespace Chapi\Commands;
13
14
use Chapi\Component\DatePeriod\DatePeriodFactoryInterface;
15
use Chapi\Entity\Chronos\ChronosJobEntity;
16
use Chapi\Service\Chronos\JobStatsServiceInterface;
17
use Chapi\Service\JobDependencies\JobDependencyServiceInterface;
18
use Chapi\Service\JobRepository\JobRepositoryInterface;
19
use Symfony\Component\Console\Helper\Table;
20
use Symfony\Component\Console\Input\InputOption;
21
22
class SchedulingViewCommand extends AbstractCommand
23
{
24
    /**
25
     * @var JobStatsServiceInterface $jobStatsService
26
     */
27
    private $jobStatsService;
28
29
    /**
30
     * @var JobDependencyServiceInterface $jobDependencyService
31
     */
32
    private $jobDependencyService;
33
34
    /**
35
     * @var JobRepositoryInterface  $jobRepositoryChronos
36
     */
37
    private $jobRepositoryChronos;
38
39
    /**
40
     * @var DatePeriodFactoryInterface  $datePeriodFactory
41
     */
42
    private $datePeriodFactory;
43
44
    /**
45
     * Configures the current command.
46
     */
47 3
    protected function configure()
48
    {
49 3
        $this->setName('scheduling')
50 3
            ->setDescription('Display upcoming jobs in a specified timeframe.')
51 3
            ->addOption('starttime', 's', InputOption::VALUE_OPTIONAL, 'Start time to display the jobs', null)
52 3
            ->addOption('endtime', 'e', InputOption::VALUE_OPTIONAL, 'End time to display the jobs', null)
53
        ;
54 3
    }
55
56
    /**
57
     * @return int
58
     */
59 3
    protected function process()
60
    {
61
        // init necessary services
62 3
        $this->jobStatsService = $this->getContainer()->get(JobStatsServiceInterface::DIC_NAME);
63 3
        $this->jobDependencyService = $this->getContainer()->get(JobDependencyServiceInterface::DIC_NAME);
64 3
        $this->jobRepositoryChronos = $this->getContainer()->get(JobRepositoryInterface::DIC_NAME_CHRONOS);
65 3
        $this->datePeriodFactory = $this->getContainer()->get(DatePeriodFactoryInterface::DIC_NAME);
66
67
        // init timeframe by user input
68 3
        $currentTime = time() + 60; // default 1min in the future
69
70 3
        $startTimeString = $this->input->getOption('starttime');
71 3
        $endTimeString = $this->input->getOption('endtime');
72
73 3
        $startTime = ($startTimeString == null) ? $currentTime : strtotime($startTimeString);
74 3
        if ($startTimeString != null && $startTime < $currentTime) {
75 1
            $startTime = strtotime($startTimeString . ' + 24 hours');
76
        }
77
78 3
        $endTime = ($endTimeString == null) ? $startTime + 7200 : strtotime($endTimeString);
79
80
        // print table for timeframe
81 3
        $this->printTimeLineTable($startTime, $endTime);
82
83 3
        return 0;
84
    }
85
86
    /**
87
     * @param int $startTime
88
     * @param int $endTime
89
     */
90 3
    private function printTimeLineTable($startTime, $endTime)
91
    {
92 3
        $datePeriod = $this->createDatePeriod(null, $startTime, null, $endTime, 'PT1M');
93
94 3
        $table = new Table($this->output);
95 3
        $table->setHeaders(array(
96 3
            'Job',
97 3
            'Timeline for ' . date('Y-m-d H:i', $startTime) . ' till ' . date('Y-m-d H:i', $endTime)
98
        ));
99
100 3
        $jobs = $this->getJobsWhichShouldStartInPeriod($startTime, $endTime);
101
102 3
        $rowCount = 0;
103
104
        /** @var ChronosJobEntity $jobEntity */
105 3
        foreach ($jobs as $jobEntity) {
106 3
            if (!empty($jobEntity->schedule)) {
107 3
                $printTime = (0 == ($rowCount % 5)) ? true : false;
108 3
                $jobStats = $this->jobStatsService->getJobStats($jobEntity->name);
109
110 3
                $jobDatePeriod = $this->createDatePeriodForJob($jobEntity, $endTime);
111 3
                $jobRunTime = $jobStats->histogram->mean / 1000;
112
113 3
                $table->addRow(
114
                    array(
115 3
                        $jobEntity->name,
116 3
                        $this->getTimelineStr(
117 3
                            $datePeriod,
118 3
                            $jobDatePeriod,
119 3
                            $jobRunTime,
120 3
                            $printTime
121
                        )
122
                    )
123
                );
124
125 3
                ++$rowCount;
126
127
                // print child jobs
128 3
                $this->printChildJobs($table, $datePeriod, $jobDatePeriod, $jobEntity->name, $jobRunTime, $rowCount, 0);
129
            }
130
        }
131
132 3
        $table->render();
133 3
    }
134
135
    /**
136
     * @param Table $table
137
     * @param \DatePeriod $displayPeriod
138
     * @param \DatePeriod $jobDatePeriod
139
     * @param string $parentJobName
140
     * @param float $parentJobRunTime
141
     * @param int $rowCount
142
     * @param int $currentChildLevel
143
     */
144 3
    private function printChildJobs(
145
        Table $table,
146
        \DatePeriod $displayPeriod,
147
        \DatePeriod $jobDatePeriod,
148
        $parentJobName,
149
        $parentJobRunTime,
150
        &$rowCount,
151
        $currentChildLevel = 0
152
    ) {
153 3
        $childJobs = $this->jobDependencyService->getChildJobs($parentJobName, JobDependencyServiceInterface::REPOSITORY_LOCAL);
154
155 3
        foreach ($childJobs as $childJobName) {
156 1
            $printTime = (0 == ($rowCount % 5)) ? true : false;
157 1
            $childJobStats = $this->jobStatsService->getJobStats($childJobName);
158
159 1
            $table->addRow(
160
                array(
161 1
                    str_repeat('   ', $currentChildLevel) . '|_ ' . $childJobName,
162 1
                    $this->getTimelineStr(
163 1
                        $displayPeriod,
164 1
                        $jobDatePeriod,
165 1
                        $childJobStats->histogram->mean / 1000,
166 1
                        $printTime,
167 1
                        round($parentJobRunTime)
168
                    )
169
                )
170
            );
171
172 1
            ++$rowCount;
173
174
            // next level
175 1
            $this->printChildJobs(
176 1
                $table,
177 1
                $displayPeriod,
178 1
                $jobDatePeriod,
179 1
                $childJobName,
180 1
                $childJobStats->histogram->mean / 1000 + $parentJobRunTime,
181 1
                $rowCount,
182 1
                ++$currentChildLevel
183
            );
184
        }
185 3
    }
186
187
    /**
188
     * @param \DatePeriod $datePeriod
189
     * @param \DatePeriod $jobDatePeriod
190
     * @param float $runSeconds
191
     * @param boolean $printTime
192
     * @param int $jobStartTimeDelay
193
     * @return string
194
     */
195 3
    private function getTimelineStr(
196
        \DatePeriod $datePeriod,
197
        \DatePeriod $jobDatePeriod,
198
        $runSeconds = 0.0,
199
        $printTime = true,
200
        $jobStartTimeDelay = 0
201
    ) {
202 3
        $timeline = '';
203 3
        $startTimes = $this->getJobStartTimesInPeriod($jobDatePeriod, $jobStartTimeDelay);
204
205 3
        $jobStarted = false;
206 3
        $spacer = '-';
207
208 3
        $runMinutes = ($runSeconds > 0) ? round($runSeconds / 60) : 0;
209 3
        $printedRunMinutes = 0;
210
211 3
        $hasToCloseFinalTag = false;
212
213
        /** @var \DateTime $time */
214 3
        foreach ($datePeriod as $time) {
215 3
            $printJobEnd = false;
216 3
            $printJobStart = false;
217
218 3
            if (isset($startTimes[$time->format('YmdHi')])) {
219 3
                $jobStarted = true;
220 3
                $printJobStart = true;
221 3
                $spacer = '=';
222
            }
223
224 3
            if ($jobStarted) {
225 3
                ++$printedRunMinutes;
226
227 3
                if ($runMinutes <= $printedRunMinutes) {
228 3
                    $jobStarted = false;
229 3
                    $printJobEnd = true;
230 3
                    $spacer = '-';
231 3
                    $printedRunMinutes = 0;
232
                }
233
            }
234
235 3
            $mod = ((int) $time->format('i')) % 15;
236
237 3
            if ($mod == 0) {
238 3
                if ($printTime) {
239 3
                    $timeline .= $this->parseTimeLineStrMark($printJobStart, $printJobEnd, $hasToCloseFinalTag, $time->format('H>i'), $time->format('H:i'));
240
                } else {
241 3
                    $timeline .= $this->parseTimeLineStrMark($printJobStart, $printJobEnd, $hasToCloseFinalTag, str_repeat('>', 5), str_repeat($spacer, 5));
242
                }
243
            } else {
244 3
                $timeline .= $this->parseTimeLineStrMark($printJobStart, $printJobEnd, $hasToCloseFinalTag, '>', $spacer);
245
            }
246
        }
247
248
        // add final tag to the end if you runs longer than current timeframe
249 3
        if ($hasToCloseFinalTag) {
250 1
            $timeline .= '</comment>';
251
        }
252
253 3
        return $timeline;
254
    }
255
256
    /**
257
     * @param bool $printJobStart
258
     * @param bool $printJobEnd
259
     * @param bool $bHasToCloseFinalTag
260
     * @param string $startStopMark
261
     * @param string $spacer
262
     * @return string
263
     */
264 3
    private function parseTimeLineStrMark($printJobStart, $printJobEnd, &$bHasToCloseFinalTag, $startStopMark, $spacer)
265
    {
266 3
        if ($printJobStart && $printJobEnd) {
267
            $timelineSnippet = sprintf('<comment>%s</comment>', $startStopMark);
268 3
        } elseif ($printJobStart) {
269 3
            $timelineSnippet = sprintf('<comment>%s', $startStopMark);
270 3
            $bHasToCloseFinalTag = true;
271 3
        } elseif ($printJobEnd) {
272 3
            $timelineSnippet = sprintf('%s</comment>', $startStopMark);
273 3
            $bHasToCloseFinalTag = false;
274
        } else {
275 3
            $timelineSnippet = $spacer;
276
        }
277
278 3
        return $timelineSnippet;
279
    }
280
281
    /**
282
     * @param \DatePeriod $jobDatePeriod
283
     * @param int $jobStartTimeDelay
284
     * @return array
285
     */
286 3
    private function getJobStartTimesInPeriod(\DatePeriod $jobDatePeriod, $jobStartTimeDelay = 0)
287
    {
288 3
        $startTimes = [];
289
290
        /** @var \DateTime $jobTime */
291 3
        foreach ($jobDatePeriod as $jobTime) {
292 3
            if ($jobStartTimeDelay > 0) {
293 1
                $jobTime->add(new \DateInterval('PT' . $jobStartTimeDelay . 'S'));
294
            }
295
296 3
            $startTimes[$jobTime->format('YmdHi')] = $jobTime;
297
        }
298
299 3
        return $startTimes;
300
    }
301
302
    /**
303
     * @param ChronosJobEntity $jobEntity
304
     * @param int $endTime
305
     * @return \DatePeriod
306
     */
307 3
    private function createDatePeriodForJob(ChronosJobEntity $jobEntity, $endTime)
308
    {
309 3
        $iso8601Entity = $this->datePeriodFactory->createIso8601Entity($jobEntity->schedule);
310 3
        return $this->createDatePeriod($iso8601Entity->startTime, 0, null, $endTime, $iso8601Entity->interval);
311
    }
312
313
    /**
314
     * @param string $dateTimeStart
315
     * @param int $timestampStart
316
     * @param string $dateTimeEnd
317
     * @param int $timestampEnd
318
     * @param string $dateInterval
319
     * @return \DatePeriod
320
     */
321 3
    private function createDatePeriod($dateTimeStart = '', $timestampStart = 0, $dateTimeEnd = '', $timestampEnd = 0, $dateInterval = 'PT1M')
322
    {
323 3
        $dateStart = new \DateTime($dateTimeStart);
324 3
        if ($timestampStart > 0) {
325 3
            $dateStart->setTimestamp($timestampStart);
326
        }
327
328 3
        $dateEnd = new \DateTime($dateTimeEnd);
329 3
        if ($timestampEnd > 0) {
330 3
            $dateEnd->setTimestamp($timestampEnd);
331
        }
332
333 3
        $_oDateInterval = new \DateInterval($dateInterval);
334
335 3
        return new \DatePeriod($dateStart, $_oDateInterval, $dateEnd);
336
    }
337
338
    /**
339
     * @param int $startTime
340
     * @param int $endTime
341
     * @return ChronosJobEntity[]
342
     */
343 3
    private function getJobsWhichShouldStartInPeriod($startTime, $endTime)
344
    {
345 3
        $jobCollection = $this->jobRepositoryChronos->getJobs();
346
347 3
        $jobs = [];
348
349
        /** @var ChronosJobEntity $jobEntity */
350 3
        foreach ($jobCollection as $jobEntity) {
351 3
            if ($jobEntity->isSchedulingJob()
352 3
                && false === $jobEntity->disabled
353 3
                && false === strpos($jobEntity->schedule, 'R0')
354
            ) {
355 3
                $jobDatePeriod = $this->createDatePeriodForJob($jobEntity, $endTime);
356 3
                if ($this->isPeriodInTimeFrame($jobDatePeriod, $startTime, $endTime)) {
357 3
                    $jobs[] = $jobEntity;
358
                }
359
            }
360
        }
361
362 3
        return $jobs;
363
    }
364
365
    /**
366
     * @param \DatePeriod $jobDatePeriod
367
     * @param int $startTime
368
     * @param int $endTime
369
     * @return bool
370
     */
371 3
    private function isPeriodInTimeFrame(\DatePeriod $jobDatePeriod, $startTime, $endTime)
372
    {
373 3
        $lastTime = 0;
374
375
        /** @var \DateTime $jobTime */
376 3
        foreach ($jobDatePeriod as $jobTime) {
377
            // jobs under 1 hours should always be displayed (break after the second loop)
378 3
            if ($jobTime->getTimestamp() - $lastTime <= 3600) {
379 3
                return true;
380
            }
381
382
            // is one starting point in timeframe?
383 3
            if ($jobTime->getTimestamp() >= $startTime && $jobTime->getTimestamp() <= $endTime) {
384
                return true;
385
            }
386
387 3
            $lastTime = $jobTime->getTimestamp();
388
        }
389
390
        return false;
391
    }
392
}
393