TrendsController   F
last analyzed

Complexity

Total Complexity 80

Size/Duplication

Total Lines 471
Duplicated Lines 0 %

Test Coverage

Coverage 85.05%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 289
c 1
b 1
f 0
dl 0
loc 471
ccs 256
cts 301
cp 0.8505
rs 2
wmc 80

18 Methods

Rating   Name   Duplication   Size   Complexity  
B calculateTimings() 0 45 6
A __construct() 0 3 1
A trends() 0 13 2
A getDatabasePlatform() 0 8 2
B testForYearFunction() 0 20 8
A getTimingsDatesAdjusted() 0 18 4
A getJobTimingsOrm() 0 34 3
A setTimingsData() 0 10 5
A strPadLeft() 0 3 1
A timings() 0 21 6
A getJobTImingsOdmMapReduce() 0 32 3
A getJobTimingsOdm() 0 45 4
A getDateFormat() 0 15 6
B addJobTimingsDateInfo() 0 40 6
A getOrmGroupBy() 0 20 6
B getAggregationResultDateStr() 0 27 6
A formatOrmDateTime() 0 25 5
A getRegexDate() 0 20 6

How to fix   Complexity   

Complex Class

Complex classes like TrendsController 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.

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 TrendsController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Dtc\QueueBundle\Controller;
4
5
use Doctrine\DBAL\Platforms\MariaDb1027Platform;
0 ignored issues
show
Bug introduced by
The type Doctrine\DBAL\Platforms\MariaDb1027Platform was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Doctrine\DBAL\Platforms\MySqlPlatform;
0 ignored issues
show
Bug introduced by
The type Doctrine\DBAL\Platforms\MySqlPlatform was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Doctrine\DBAL\Platforms\OraclePlatform;
0 ignored issues
show
Bug introduced by
The type Doctrine\DBAL\Platforms\OraclePlatform was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
0 ignored issues
show
Bug introduced by
The type Doctrine\DBAL\Platforms\PostgreSqlPlatform was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use Doctrine\DBAL\Platforms\SqlitePlatform;
0 ignored issues
show
Bug introduced by
The type Doctrine\DBAL\Platforms\SqlitePlatform was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use Doctrine\ODM\MongoDB\DocumentManager;
0 ignored issues
show
Bug introduced by
The type Doctrine\ODM\MongoDB\DocumentManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use Doctrine\ORM\EntityManager;
0 ignored issues
show
Bug introduced by
The type Doctrine\ORM\EntityManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use Dtc\QueueBundle\Doctrine\DoctrineJobTimingManager;
13
use Dtc\QueueBundle\Model\JobTiming;
14
use Dtc\QueueBundle\ODM\JobManager;
15
use Dtc\QueueBundle\ODM\JobTimingManager;
16
use Symfony\Component\DependencyInjection\ContainerInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Depend...tion\ContainerInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use Symfony\Component\HttpFoundation\JsonResponse;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\HttpFoundation\JsonResponse was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use Symfony\Component\HttpFoundation\Request;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\HttpFoundation\Request was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
20
class TrendsController
21
{
22 1
    use ControllerTrait;
23
24
    private $container;
25
26 2
    public function __construct(ContainerInterface $container)
27
    {
28 2
        $this->container = $container;
29 2
    }
30
31 1
    public function getDatabasePlatform(\Dtc\QueueBundle\ORM\JobTimingManager $jobTimingManager)
32
    {
33 1
        $connection = $jobTimingManager->getObjectManager()->getConnection();
34 1
        if (method_exists($connection, 'getDatabasePlatform')) {
35 1
            return $connection->getDatabasePlatform();
36
        }
37
38
        return null;
39
    }
40
41 1
    private function testForYearFunction(\Dtc\QueueBundle\ORM\JobTimingManager $jobTimingManager)
42
    {
43 1
        $foundYearFunction = false;
44 1
        $platform = $this->getDatabasePlatform($jobTimingManager);
45 1
        $reason = 'Platform: '.get_class($platform).' not supported';
0 ignored issues
show
Bug introduced by
It seems like $platform can also be of type null; however, parameter $object of get_class() does only seem to accept object, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

45
        $reason = 'Platform: '.get_class(/** @scrutinizer ignore-type */ $platform).' not supported';
Loading history...
46 1
        if ($platform instanceof MySqlPlatform || $platform instanceof MariaDb1027Platform) {
47 1
            $foundYearFunction = class_exists('Oro\ORM\Query\AST\Platform\Functions\Mysql\Year') || class_exists('DoctrineExtensions\Query\Mysql\Year');
48 1
            $reason = "<h2>Please install (composer require) one of the following:</h2>\n<pre>\noro/doctrine-extensions\nbeberlei/DoctrineExtensions</pre>";
49
        } elseif ($platform instanceof PostgreSqlPlatform) {
50
            $foundYearFunction = class_exists('Oro\ORM\Query\AST\Platform\Functions\Postgresql\Year') || class_exists('DoctrineExtensions\Query\Postgresql\Year');
51
            $reason = "<h2>Please install (composer require) one of the following:</h2>\n<pre>\noro/doctrine-extensions\nbeberlei/DoctrineExtensions</pre>";
52
        } elseif ($platform instanceof OraclePlatform) {
53
            $foundYearFunction = class_exists('DoctrineExtensions\Query\Oracle\Year');
54
            $reason = "<h2>Please install (composer require) the following:</h2><pre>\nbeberlei/DoctrineExtensions</pre>";
55
        } elseif ($platform instanceof SqlitePlatform) {
56
            $foundYearFunction = class_exists('DoctrineExtensions\Query\Sqlite\Year');
57
            $reason = "<h2>Please install (composer require) the following:</h2><pre>\nbeberlei/DoctrineExtensions</pre>";
58
        }
59
60 1
        return [$foundYearFunction, $reason];
61
    }
62
63
    /**
64
     * Show a graph of job trends.
65
     */
66 1
    public function trends()
67
    {
68 1
        $recordTimings = $this->container->getParameter('dtc_queue.timings.record');
69 1
        $jobTimingManager = $this->container->get('dtc_queue.manager.job_timing');
70 1
        $foundYearFunction = true;
71 1
        $reason = null;
72 1
        if ($jobTimingManager instanceof \Dtc\QueueBundle\ORM\JobTimingManager) {
73 1
            list($foundYearFunction, $reason) = $this->testForYearFunction($jobTimingManager);
74
        }
75 1
        $params = ['record_timings' => $recordTimings, 'states' => JobTiming::getStates(), 'found_year_function' => $foundYearFunction, 'found_year_reason' => $reason];
76 1
        $this->addCssJs($params);
77
78 1
        return $this->render('@DtcQueue/Queue/trends.html.twig', $params);
79
    }
80
81 1
    public function timings(Request $request)
82
    {
83 1
        $begin = $request->query->get('begin');
84 1
        $end = $request->query->get('end');
85 1
        $type = $request->query->get('type', 'HOUR');
86 1
        $beginDate = \DateTime::createFromFormat('Y-m-d\TH:i:s.uO', $begin) ?: null;
87 1
        if ($beginDate instanceof \DateTime) {
88
            $beginDate->setTimezone(new \DateTimeZone(date_default_timezone_get()));
89
        }
90 1
        $endDate = \DateTime::createFromFormat('Y-m-d\TH:i:s.uO', $end) ?: \Dtc\QueueBundle\Util\Util::getMicrotimeDateTime();
91 1
        if ($endDate instanceof \DateTime) {
0 ignored issues
show
introduced by
$endDate is always a sub-type of DateTime.
Loading history...
92 1
            $endDate->setTimezone(new \DateTimeZone(date_default_timezone_get()));
93
        }
94
95 1
        $recordTimings = $this->container->getParameter('dtc_queue.timings.record');
96 1
        $params = [];
97 1
        if ($recordTimings) {
98 1
            $params = $this->calculateTimings($type, $beginDate, $endDate);
99
        }
100
101 1
        return new JsonResponse($params);
102
    }
103
104
    /**
105
     * @param \DateTime|null $beginDate
106
     * @param \DateTime      $endDate
107
     */
108 1
    protected function calculateTimings($type, $beginDate, $endDate)
109
    {
110 1
        $params = [];
111 1
        $this->validateJobTimingManager();
112
113
        /** @var DoctrineJobTimingManager $jobTimingManager */
114 1
        $jobTimingManager = $this->container->get('dtc_queue.manager.job_timing');
115 1
        if ($jobTimingManager instanceof JobTimingManager) {
116 1
            $timings = $this->getJobTimingsOdm($type, $endDate, $beginDate);
117
        } else {
118 1
            $timings = $this->getJobTimingsOrm($type, $endDate, $beginDate);
119
        }
120
121 1
        $timingStates = JobTiming::getStates();
122 1
        $timingsDates = [];
123 1
        foreach (array_keys($timingStates) as $state) {
124 1
            if (!isset($timings[$state])) {
125 1
                continue;
126
            }
127 1
            $timingsData = $timings[$state];
128 1
            $timingsDates = array_unique(array_merge(array_keys($timingsData), $timingsDates));
129
        }
130
131 1
        $format = $this->getDateFormat($type);
132 1
        usort($timingsDates, function ($date1str, $date2str) use ($format) {
133
            $date1 = \DateTime::createFromFormat($format, $date1str);
134
            $date2 = \DateTime::createFromFormat($format, $date2str);
135
            if (!$date2) {
0 ignored issues
show
introduced by
$date2 is of type DateTime, thus it always evaluated to true.
Loading history...
136
                return false;
137
            }
138
            if (!$date1) {
0 ignored issues
show
introduced by
$date1 is of type DateTime, thus it always evaluated to true.
Loading history...
139
                return false;
140
            }
141
            $date1->setTimezone(new \DateTimeZone(date_default_timezone_get()));
142
            $date2->setTimezone(new \DateTimeZone(date_default_timezone_get()));
143
144
            return $date1 > $date2;
145 1
        });
146
147 1
        $timingsDatesAdjusted = $this->getTimingsDatesAdjusted($timingsDates, $format);
148 1
        $this->setTimingsData($timingStates, $timings, $timingsDates, $params);
149 1
        $params['timings_dates'] = $timingsDates;
150 1
        $params['timings_dates_rfc3339'] = $timingsDatesAdjusted;
151
152 1
        return $params;
153
    }
154
155
    /**
156
     * Timings offset by timezone if necessary.
157
     *
158
     * @param string $format
159
     *
160
     * @return array
161
     */
162 1
    protected function getTimingsDatesAdjusted(array $timingsDates, $format)
163
    {
164 1
        $timezoneOffset = $this->container->getParameter('dtc_queue.timings.timezone_offset');
165 1
        $timingsDatesAdjusted = [];
166 1
        foreach ($timingsDates as $dateStr) {
167 1
            $date = \DateTime::createFromFormat($format, $dateStr);
168 1
            if (false === $date) {
169
                throw new \InvalidArgumentException("'$dateStr' is not in the right format: ".DATE_RFC3339);
170
            }
171 1
            $date->setTimezone(new \DateTimeZone(date_default_timezone_get()));
172 1
            if (0 !== $timezoneOffset) {
173
                // This may too simplistic in areas that observe DST - does the database or PHP code observe DST?
174
                $date->setTimestamp($date->getTimestamp() + ($timezoneOffset * 3600));
175
            }
176 1
            $timingsDatesAdjusted[] = $date->format(DATE_RFC3339);
177
        }
178
179 1
        return $timingsDatesAdjusted;
180
    }
181
182 1
    protected function setTimingsData(array $timingStates, array $timings, array $timingsDates, array &$params)
183
    {
184 1
        foreach (array_keys($timingStates) as $state) {
185 1
            if (!isset($timings[$state])) {
186 1
                continue;
187
            }
188
189 1
            $timingsData = $timings[$state];
190 1
            foreach ($timingsDates as $date) {
191 1
                $params['timings_data_'.$state][] = isset($timingsData[$date]) ? $timingsData[$date] : 0;
192
            }
193
        }
194 1
    }
195
196
    /**
197
     * @param string                                 $type
198
     * @param \Doctrine\ODM\MongoDB\Aggregation\Expr $expr
0 ignored issues
show
Bug introduced by
The type Doctrine\ODM\MongoDB\Aggregation\Expr was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
199
     *
200
     * @return mixed
201
     */
202 1
    protected function addJobTimingsDateInfo($type, $expr)
203
    {
204 1
        switch ($type) {
205 1
            case 'YEAR':
206 1
                return $expr->field('year')
207 1
                    ->year('$finishedAt');
208 1
            case 'MONTH':
209 1
                return $expr->field('year')
210 1
                    ->year('$finishedAt')
211 1
                    ->field('month')
212 1
                    ->month('$finishedAt');
213 1
            case 'DAY':
214 1
                return $expr->field('year')
215 1
                    ->year('$finishedAt')
216 1
                    ->field('month')
217 1
                    ->month('$finishedAt')
218 1
                    ->field('day')
219 1
                    ->dayOfMonth('$finishedAt');
220 1
            case 'HOUR':
221 1
                return $expr->field('year')
222 1
                    ->year('$finishedAt')
223 1
                    ->field('month')
224 1
                    ->month('$finishedAt')
225 1
                    ->field('day')
226 1
                    ->dayOfMonth('$finishedAt')
227 1
                    ->field('hour')
228 1
                    ->hour('$finishedAt');
229 1
            case 'MINUTE':
230 1
                return $expr->field('year')
231 1
                    ->year('$finishedAt')
232 1
                    ->field('month')
233 1
                    ->month('$finishedAt')
234 1
                    ->field('day')
235 1
                    ->dayOfMonth('$finishedAt')
236 1
                    ->field('hour')
237 1
                    ->hour('$finishedAt')
238 1
                    ->field('minute')
239 1
                    ->minute('$finishedAt');
240
            default:
241
                throw new \InvalidArgumentException("Unknown type $type");
242
        }
243
    }
244
245
    protected function getJobTImingsOdmMapReduce($builder, $type, \DateTime $end, \DateTime $begin = null)
246
    {
247
        $regexInfo = $this->getRegexDate($type);
248
        if (!$begin) {
249
            $begin = clone $end;
250
            $begin->sub($regexInfo['interval']);
251
        }
252
253
        $mapFunc = 'function() {
254
            var dateStr = this.finishedAt.toISOString();
255
            dateStr = dateStr.replace(/'.$regexInfo['replace']['regex']."/,'".$regexInfo['replace']['replacement']."');
256
            var dateBegin = new Date('".$begin->format('c')."');
257
            var dateEnd = new Date('".$end->format('c')."');
258
            if (this.finishedAt >= dateBegin && this.finishedAt <= dateEnd) {
259
                var result = {};
260
                result[dateStr] = 1;
261
                emit(this.status, result);
262
            }
263
        }";
264
265
        // Run a map reduce function get worker and status break down
266
        $reduceFunc = JobManager::REDUCE_FUNCTION;
267
        $builder->map($mapFunc)
268
            ->reduce($reduceFunc);
269
        $query = $builder->getQuery();
270
        $results = $query->execute();
271
        $resultHash = [];
272
        foreach ($results as $info) {
273
            $resultHash[$info['_id']] = $info['value'];
274
        }
275
276
        return $resultHash;
277
    }
278
279 1
    protected function getJobTimingsOdm($type, \DateTime $end, \DateTime $begin = null)
280
    {
281
        /** @var JobTimingManager $runManager */
282 1
        $jobTimingManager = $this->container->get('dtc_queue.manager.job_timing');
283 1
        $jobTimingClass = $jobTimingManager->getJobTimingClass();
284
285
        /** @var DocumentManager $documentManager */
286 1
        $documentManager = $jobTimingManager->getObjectManager();
287
288 1
        $builder = $documentManager->createQueryBuilder($jobTimingClass);
289 1
        if (method_exists($builder, 'map')) {
290
            return $this->getJobTimingsOdmMapReduce($builder, $type, $end, $begin);
291
        }
292
293 1
        $regexInfo = $this->getRegexDate($type);
294 1
        if (!$begin) {
295 1
            $begin = clone $end;
296 1
            $begin->sub($regexInfo['interval']);
297
        }
298
299 1
        $aggregationBuilder = $documentManager->createAggregationBuilder($jobTimingClass);
300 1
        $expr = $this->addJobTimingsDateInfo($type, $aggregationBuilder->expr());
301 1
        $expr = $expr->field('status')
302 1
                ->expression('$status');
303
304
        $aggregationBuilder
305 1
            ->match()
306 1
                ->field('finishedAt')
307 1
                ->gte($begin)
308 1
                ->lte($end)
309 1
            ->group()
310 1
                    ->field('id')
311 1
                    ->expression($expr)
312 1
                    ->field('value')
313 1
                    ->sum(1);
314
315 1
        $results = $aggregationBuilder->execute();
316 1
        $resultHash = [];
317 1
        foreach ($results as $result) {
318 1
            $key = $result['_id']['status'];
319 1
            $dateStr = $this->getAggregationResultDateStr($type, $result['_id']);
320 1
            $resultHash[$key][$dateStr] = $result['value'];
321
        }
322
323 1
        return $resultHash;
324
    }
325
326
    /**
327
     * Formats the aggregation result into the desired date string format.
328
     *
329
     * @param string $type
330
     *
331
     * @return string
332
     */
333 1
    protected function getAggregationResultDateStr($type, array $result)
334
    {
335 1
        switch ($type) {
336 1
            case 'YEAR':
337 1
                return $result['year'];
338 1
            case 'MONTH':
339 1
                return "{$result['year']}-".str_pad($result['month'], 2, '0', STR_PAD_LEFT);
340 1
            case 'DAY':
341 1
                $str = "{$result['year']}-".str_pad($result['month'], 2, '0', STR_PAD_LEFT);
342 1
                $str .= '-'.str_pad($result['day'], 2, '0', STR_PAD_LEFT);
343
344 1
                return $str;
345 1
            case 'HOUR':
346 1
                $str = "{$result['year']}-".str_pad($result['month'], 2, '0', STR_PAD_LEFT);
347 1
                $str .= '-'.str_pad($result['day'], 2, '0', STR_PAD_LEFT);
348 1
                $str .= ' '.str_pad($result['hour'], 2, '0', STR_PAD_LEFT);
349
350 1
                return $str;
351 1
            case 'MINUTE':
352 1
                $str = "{$result['year']}-".str_pad($result['month'], 2, '0', STR_PAD_LEFT);
353 1
                $str .= '-'.str_pad($result['day'], 2, '0', STR_PAD_LEFT);
354 1
                $str .= ' '.str_pad($result['hour'], 2, '0', STR_PAD_LEFT);
355 1
                $str .= ':'.str_pad($result['minute'], 2, '0', STR_PAD_LEFT);
356
357 1
                return $str;
358
            default:
359
                throw new \InvalidArgumentException("Invalid date format type '$type''");
360
        }
361
    }
362
363 1
    protected function getDateFormat($type)
364
    {
365 1
        switch ($type) {
366 1
            case 'YEAR':
367 1
                return 'Y';
368 1
            case 'MONTH':
369 1
                return 'Y-m';
370 1
            case 'DAY':
371 1
                return 'Y-m-d';
372 1
            case 'HOUR':
373 1
                return 'Y-m-d H';
374 1
            case 'MINUTE':
375 1
                return 'Y-m-d H:i';
376
            default:
377
                throw new \InvalidArgumentException("Invalid date format type '$type''");
378
        }
379
    }
380
381 1
    protected function getRegexDate($type)
382
    {
383 1
        switch ($type) {
384 1
            case 'YEAR':
385 1
                return ['replace' => ['regex' => '(\d+)\-(\d+)\-(\d+)T(\d+):(\d+):(\d+).+$', 'replacement' => '$1'],
386 1
                    'interval' => new \DateInterval('P10Y'), ];
387 1
            case 'MONTH':
388 1
                return ['replace' => ['regex' => '(\d+)\-(\d+)\-(\d+)T(\d+):(\d+):(\d+).+$', 'replacement' => '$1-$2'],
389 1
                    'interval' => new \DateInterval('P12M'), ];
390 1
            case 'DAY':
391 1
                return ['replace' => ['regex' => '(\d+)\-(\d+)\-(\d+)T(\d+):(\d+):(\d+).+$', 'replacement' => '$1-$2-$3'],
392 1
                    'interval' => new \DateInterval('P31D'), ];
393 1
            case 'HOUR':
394 1
                return ['replace' => ['regex' => '(\d+)\-(\d+)\-(\d+)T(\d+):(\d+):(\d+).+$', 'replacement' => '$1-$2-$3 $4'],
395 1
                    'interval' => new \DateInterval('PT24H'), ];
396 1
            case 'MINUTE':
397 1
                return ['replace' => ['regex' => '(\d+)\-(\d+)\-(\d+)T(\d+):(\d+):(\d+).+$', 'replacement' => '$1-$2-$3 $4:$5'],
398 1
                    'interval' => new \DateInterval('PT3600S'), ];
399
        }
400
        throw new \InvalidArgumentException("Invalid type $type");
401
    }
402
403 1
    protected function getOrmGroupBy($type)
404
    {
405 1
        switch ($type) {
406 1
            case 'YEAR':
407 1
                return ['groupby' => 'YEAR(j.finishedAt)',
408 1
                    'interval' => new \DateInterval('P10Y'), ];
409 1
            case 'MONTH':
410 1
                return ['groupby' => 'CONCAT(YEAR(j.finishedAt),\'-\',MONTH(j.finishedAt))',
411 1
                    'interval' => new \DateInterval('P12M'), ];
412 1
            case 'DAY':
413 1
                return ['groupby' => 'CONCAT(YEAR(j.finishedAt),\'-\',MONTH(j.finishedAt),\'-\',DAY(j.finishedAt))',
414 1
                    'interval' => new \DateInterval('P31D'), ];
415 1
            case 'HOUR':
416 1
                return ['groupby' => 'CONCAT(YEAR(j.finishedAt),\'-\',MONTH(j.finishedAt),\'-\',DAY(j.finishedAt),\' \',HOUR(j.finishedAt))',
417 1
                    'interval' => new \DateInterval('PT24H'), ];
418 1
            case 'MINUTE':
419 1
                return ['groupby' => 'CONCAT(YEAR(j.finishedAt),\'-\',MONTH(j.finishedAt),\'-\',DAY(j.finishedAt),\' \',HOUR(j.finishedAt),\':\',MINUTE(j.finishedAt))',
420 1
                    'interval' => new \DateInterval('PT3600S'), ];
421
        }
422
        throw new \InvalidArgumentException("Invalid type $type");
423
    }
424
425 1
    protected function getJobTimingsOrm($type, \DateTime $end, \DateTime $begin = null)
426
    {
427
        /** @var JobTimingManager $jobTimingManager */
428 1
        $jobTimingManager = $this->container->get('dtc_queue.manager.job_timing');
429 1
        $jobTimingClass = $jobTimingManager->getJobTimingClass();
430
        /** @var EntityManager $entityManager */
431 1
        $entityManager = $jobTimingManager->getObjectManager();
432
433 1
        $groupByInfo = $this->getOrmGroupBy($type);
434
435 1
        if (!$begin) {
436 1
            $begin = clone $end;
437 1
            $begin->sub($groupByInfo['interval']);
438
        }
439
440 1
        $queryBuilder = $entityManager->createQueryBuilder()->select("j.status as status, count(j.finishedAt) as thecount, {$groupByInfo['groupby']} as thedate")
441 1
            ->from($jobTimingClass, 'j')
442 1
            ->where('j.finishedAt <= :end')
443 1
            ->andWhere('j.finishedAt >= :begin')
444 1
            ->setParameter(':end', $end)
445 1
            ->setParameter(':begin', $begin)
446 1
            ->groupBy('status')
447 1
            ->addGroupBy('thedate');
448
449
        $result = $queryBuilder
450 1
            ->getQuery()->getArrayResult();
451
452 1
        $resultHash = [];
453 1
        foreach ($result as $row) {
454 1
            $date = $this->formatOrmDateTime($type, $row['thedate']);
455 1
            $resultHash[$row['status']][$date] = intval($row['thecount']);
456
        }
457
458 1
        return $resultHash;
459
    }
460
461 1
    protected function strPadLeft($str)
462
    {
463 1
        return str_pad($str, 2, '0', STR_PAD_LEFT);
464
    }
465
466 1
    protected function formatOrmDateTime($type, $str)
467
    {
468 1
        switch ($type) {
469 1
            case 'MONTH':
470 1
                $parts = explode('-', $str);
471
472 1
                return $parts[0].'-'.$this->strPadLeft($parts[1]);
473 1
            case 'DAY':
474 1
                $parts = explode('-', $str);
475
476 1
                return $parts[0].'-'.$this->strPadLeft($parts[1]).'-'.$this->strPadLeft($parts[2]);
477 1
            case 'HOUR':
478 1
                $parts = explode(' ', $str);
479 1
                $dateParts = explode('-', $parts[0]);
480
481 1
                return $dateParts[0].'-'.$this->strPadLeft($dateParts[1]).'-'.$this->strPadLeft($dateParts[2]).' '.$this->strPadLeft($parts[1]);
482 1
            case 'MINUTE':
483 1
                $parts = explode(' ', $str);
484 1
                $dateParts = explode('-', $parts[0]);
485 1
                $timeParts = explode(':', $parts[1]);
486
487 1
                return $dateParts[0].'-'.$this->strPadLeft($dateParts[1]).'-'.$this->strPadLeft($dateParts[2]).' '.$this->strPadLeft($timeParts[0]).':'.$this->strPadLeft($timeParts[1]);
488
        }
489
490 1
        return $str;
491
    }
492
}
493