1 | <?php |
||||||
2 | |||||||
3 | namespace Dtc\QueueBundle\Controller; |
||||||
4 | |||||||
5 | use Doctrine\ODM\MongoDB\DocumentManager; |
||||||
6 | use Doctrine\ORM\EntityManager; |
||||||
7 | use Dtc\QueueBundle\Doctrine\DoctrineJobTimingManager; |
||||||
8 | use Dtc\QueueBundle\Model\JobTiming; |
||||||
9 | use Dtc\QueueBundle\ODM\JobManager; |
||||||
10 | use Dtc\QueueBundle\ODM\JobTimingManager; |
||||||
11 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; |
||||||
12 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; |
||||||
13 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
||||||
14 | use Symfony\Component\HttpFoundation\JsonResponse; |
||||||
15 | use Symfony\Component\HttpFoundation\Request; |
||||||
16 | |||||||
17 | class TrendsController extends Controller |
||||||
18 | { |
||||||
19 | use ControllerTrait; |
||||||
20 | |||||||
21 | /** |
||||||
22 | * Show a graph of job trends. |
||||||
23 | * |
||||||
24 | * @Route("/trends", name="dtc_queue_trends") |
||||||
25 | * @Template("@DtcQueue/Queue/trends.html.twig") |
||||||
26 | */ |
||||||
27 | 1 | public function trendsAction() |
|||||
28 | { |
||||||
29 | 1 | $recordTimings = $this->container->getParameter('dtc_queue.timings.record'); |
|||||
30 | 1 | $foundYearFunction = class_exists('Oro\ORM\Query\AST\Platform\Functions\Mysql\Year') || class_exists('DoctrineExtensions\Query\Mysql\Year'); |
|||||
31 | 1 | $params = ['record_timings' => $recordTimings, 'states' => JobTiming::getStates(), 'found_year_function' => $foundYearFunction]; |
|||||
32 | 1 | $this->addCssJs($params); |
|||||
33 | |||||||
34 | 1 | return $params; |
|||||
35 | } |
||||||
36 | |||||||
37 | /** |
||||||
38 | * @Route("/timings", name="dtc_queue_timings") |
||||||
39 | */ |
||||||
40 | 1 | public function getTimingsAction(Request $request) |
|||||
41 | { |
||||||
42 | 1 | $begin = $request->query->get('begin'); |
|||||
43 | 1 | $end = $request->query->get('end'); |
|||||
44 | 1 | $type = $request->query->get('type', 'HOUR'); |
|||||
45 | 1 | $beginDate = \DateTime::createFromFormat('Y-m-d\TH:i:s.uO', $begin) ?: null; |
|||||
46 | 1 | if ($beginDate instanceof \DateTime) { |
|||||
47 | $beginDate->setTimezone(new \DateTimeZone(date_default_timezone_get())); |
||||||
48 | 1 | } |
|||||
49 | 1 | $endDate = \DateTime::createFromFormat('Y-m-d\TH:i:s.uO', $end) ?: \Dtc\QueueBundle\Util\Util::getMicrotimeDateTime(); |
|||||
50 | 1 | if ($endDate instanceof \DateTime) { |
|||||
0 ignored issues
–
show
introduced
by
Loading history...
|
|||||||
51 | 1 | $beginDate->setTimezone(new \DateTimeZone(date_default_timezone_get())); |
|||||
0 ignored issues
–
show
The method
setTimezone() does not exist on null .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed.
Loading history...
|
|||||||
52 | } |
||||||
53 | |||||||
54 | 1 | $recordTimings = $this->container->getParameter('dtc_queue.timings.record'); |
|||||
55 | $params = []; |
||||||
56 | if ($recordTimings) { |
||||||
57 | $params = $this->calculateTimings($type, $beginDate, $endDate); |
||||||
58 | } |
||||||
59 | |||||||
60 | return new JsonResponse($params); |
||||||
61 | 1 | } |
|||||
62 | |||||||
63 | 1 | /** |
|||||
64 | 1 | * @param \DateTime|null $beginDate |
|||||
65 | * @param \DateTime $endDate |
||||||
66 | */ |
||||||
67 | 1 | protected function calculateTimings($type, $beginDate, $endDate) |
|||||
68 | 1 | { |
|||||
69 | 1 | $params = []; |
|||||
70 | $this->validateJobTimingManager(); |
||||||
71 | 1 | ||||||
72 | /** @var DoctrineJobTimingManager $jobTimingManager */ |
||||||
73 | $jobTimingManager = $this->get('dtc_queue.manager.job_timing'); |
||||||
74 | 1 | if ($jobTimingManager instanceof JobTimingManager) { |
|||||
75 | 1 | $timings = $this->getJobTimingsOdm($type, $endDate, $beginDate); |
|||||
76 | 1 | } else { |
|||||
77 | 1 | $timings = $this->getJobTimingsOrm($type, $endDate, $beginDate); |
|||||
78 | 1 | } |
|||||
79 | |||||||
80 | 1 | $timingStates = JobTiming::getStates(); |
|||||
81 | 1 | $timingsDates = []; |
|||||
82 | foreach (array_keys($timingStates) as $state) { |
||||||
83 | if (!isset($timings[$state])) { |
||||||
84 | 1 | continue; |
|||||
85 | 1 | } |
|||||
86 | $timingsData = $timings[$state]; |
||||||
87 | $timingsDates = array_unique(array_merge(array_keys($timingsData), $timingsDates)); |
||||||
88 | } |
||||||
89 | |||||||
90 | $format = $this->getDateFormat($type); |
||||||
91 | usort($timingsDates, function ($date1str, $date2str) use ($format) { |
||||||
92 | $date1 = \DateTime::createFromFormat($format, $date1str); |
||||||
93 | $date2 = \DateTime::createFromFormat($format, $date2str); |
||||||
94 | if (!$date2) { |
||||||
95 | return false; |
||||||
96 | 1 | } |
|||||
97 | if (!$date1) { |
||||||
98 | 1 | return false; |
|||||
99 | 1 | } |
|||||
100 | 1 | $date1->setTimezone(new \DateTimeZone(date_default_timezone_get())); |
|||||
101 | 1 | $date2->setTimezone(new \DateTimeZone(date_default_timezone_get())); |
|||||
102 | |||||||
103 | 1 | return $date1 > $date2; |
|||||
104 | }); |
||||||
105 | |||||||
106 | $timingsDatesAdjusted = $this->getTimingsDatesAdjusted($timingsDates, $format); |
||||||
107 | $this->setTimingsData($timingStates, $timings, $timingsDates, $params); |
||||||
108 | $params['timings_dates'] = $timingsDates; |
||||||
109 | $params['timings_dates_rfc3339'] = $timingsDatesAdjusted; |
||||||
110 | |||||||
111 | return $params; |
||||||
112 | } |
||||||
113 | 1 | ||||||
114 | /** |
||||||
115 | 1 | * Timings offset by timezone if necessary. |
|||||
116 | 1 | * |
|||||
117 | 1 | * @param string $format |
|||||
118 | 1 | * |
|||||
119 | 1 | * @return array |
|||||
120 | */ |
||||||
121 | protected function getTimingsDatesAdjusted(array $timingsDates, $format) |
||||||
122 | { |
||||||
123 | 1 | $timezoneOffset = $this->container->getParameter('dtc_queue.timings.timezone_offset'); |
|||||
124 | $timingsDatesAdjusted = []; |
||||||
125 | foreach ($timingsDates as $dateStr) { |
||||||
126 | 1 | $date = \DateTime::createFromFormat($format, $dateStr); |
|||||
127 | if (false === $date) { |
||||||
128 | throw new \InvalidArgumentException("'$dateStr' is not in the right format: ".DATE_RFC3339); |
||||||
129 | 1 | } |
|||||
130 | $date->setTimezone(new \DateTimeZone(date_default_timezone_get())); |
||||||
131 | if (0 !== $timezoneOffset) { |
||||||
132 | 1 | // This may too simplistic in areas that observe DST - does the database or PHP code observe DST? |
|||||
133 | $date->setTimestamp($date->getTimestamp() + ($timezoneOffset * 3600)); |
||||||
134 | 1 | } |
|||||
135 | 1 | $timingsDatesAdjusted[] = $date->format(DATE_RFC3339); |
|||||
136 | 1 | } |
|||||
137 | |||||||
138 | return $timingsDatesAdjusted; |
||||||
139 | 1 | } |
|||||
140 | 1 | ||||||
141 | 1 | protected function setTimingsData(array $timingStates, array $timings, array $timingsDates, array &$params) |
|||||
142 | { |
||||||
143 | foreach (array_keys($timingStates) as $state) { |
||||||
144 | 1 | if (!isset($timings[$state])) { |
|||||
145 | continue; |
||||||
146 | } |
||||||
147 | |||||||
148 | $timingsData = $timings[$state]; |
||||||
149 | foreach ($timingsDates as $date) { |
||||||
150 | $params['timings_data_'.$state][] = isset($timingsData[$date]) ? $timingsData[$date] : 0; |
||||||
151 | } |
||||||
152 | 1 | } |
|||||
153 | } |
||||||
154 | 1 | ||||||
155 | 1 | /** |
|||||
156 | 1 | * @param string $type |
|||||
157 | 1 | * @param \Doctrine\ODM\MongoDB\Aggregation\Expr $expr |
|||||
158 | 1 | * |
|||||
159 | 1 | * @return mixed |
|||||
160 | 1 | */ |
|||||
161 | 1 | protected function addJobTimingsDateInfo($type, $expr) |
|||||
162 | 1 | { |
|||||
163 | 1 | switch ($type) { |
|||||
164 | 1 | case 'YEAR': |
|||||
165 | 1 | return $expr->field('year') |
|||||
166 | 1 | ->year('$finishedAt'); |
|||||
167 | 1 | case 'MONTH': |
|||||
168 | 1 | return $expr->field('year') |
|||||
169 | 1 | ->year('$finishedAt') |
|||||
170 | 1 | ->field('month') |
|||||
171 | 1 | ->month('$finishedAt'); |
|||||
172 | 1 | case 'DAY': |
|||||
173 | 1 | return $expr->field('year') |
|||||
174 | 1 | ->year('$finishedAt') |
|||||
175 | 1 | ->field('month') |
|||||
176 | 1 | ->month('$finishedAt') |
|||||
177 | 1 | ->field('day') |
|||||
178 | 1 | ->dayOfMonth('$finishedAt'); |
|||||
179 | 1 | case 'HOUR': |
|||||
180 | 1 | return $expr->field('year') |
|||||
181 | 1 | ->year('$finishedAt') |
|||||
182 | 1 | ->field('month') |
|||||
183 | 1 | ->month('$finishedAt') |
|||||
184 | 1 | ->field('day') |
|||||
185 | 1 | ->dayOfMonth('$finishedAt') |
|||||
186 | 1 | ->field('hour') |
|||||
187 | 1 | ->hour('$finishedAt'); |
|||||
188 | 1 | case 'MINUTE': |
|||||
189 | 1 | return $expr->field('year') |
|||||
190 | ->year('$finishedAt') |
||||||
191 | ->field('month') |
||||||
192 | ->month('$finishedAt') |
||||||
193 | ->field('day') |
||||||
194 | ->dayOfMonth('$finishedAt') |
||||||
195 | ->field('hour') |
||||||
196 | ->hour('$finishedAt') |
||||||
197 | ->field('minute') |
||||||
198 | ->minute('$finishedAt'); |
||||||
199 | default: |
||||||
200 | throw new \InvalidArgumentException("Unknown type $type"); |
||||||
201 | } |
||||||
202 | } |
||||||
203 | |||||||
204 | protected function getJobTImingsOdmMapReduce($builder, $type, \DateTime $end, \DateTime $begin = null) |
||||||
205 | { |
||||||
206 | $regexInfo = $this->getRegexDate($type); |
||||||
207 | if (!$begin) { |
||||||
208 | $begin = clone $end; |
||||||
209 | $begin->sub($regexInfo['interval']); |
||||||
210 | } |
||||||
211 | |||||||
212 | $mapFunc = 'function() { |
||||||
213 | var dateStr = this.finishedAt.toISOString(); |
||||||
214 | dateStr = dateStr.replace(/'.$regexInfo['replace']['regex']."/,'".$regexInfo['replace']['replacement']."'); |
||||||
215 | var dateBegin = new Date('".$begin->format('c')."'); |
||||||
216 | var dateEnd = new Date('".$end->format('c')."'); |
||||||
217 | if (this.finishedAt >= dateBegin && this.finishedAt <= dateEnd) { |
||||||
218 | var result = {}; |
||||||
219 | result[dateStr] = 1; |
||||||
220 | emit(this.status, result); |
||||||
221 | } |
||||||
222 | }"; |
||||||
223 | |||||||
224 | // Run a map reduce function get worker and status break down |
||||||
225 | $reduceFunc = JobManager::REDUCE_FUNCTION; |
||||||
226 | $builder->map($mapFunc) |
||||||
227 | ->reduce($reduceFunc); |
||||||
228 | $query = $builder->getQuery(); |
||||||
229 | 1 | $results = $query->execute(); |
|||||
230 | $resultHash = []; |
||||||
231 | foreach ($results as $info) { |
||||||
232 | 1 | $resultHash[$info['_id']] = $info['value']; |
|||||
233 | 1 | } |
|||||
234 | |||||||
235 | return $resultHash; |
||||||
236 | 1 | } |
|||||
237 | |||||||
238 | 1 | protected function getJobTimingsOdm($type, \DateTime $end, \DateTime $begin = null) |
|||||
239 | 1 | { |
|||||
240 | /** @var JobTimingManager $runManager */ |
||||||
241 | $jobTimingManager = $this->get('dtc_queue.manager.job_timing'); |
||||||
242 | $jobTimingClass = $jobTimingManager->getJobTimingClass(); |
||||||
243 | 1 | ||||||
244 | 1 | /** @var DocumentManager $documentManager */ |
|||||
245 | 1 | $documentManager = $jobTimingManager->getObjectManager(); |
|||||
246 | 1 | ||||||
247 | $builder = $documentManager->createQueryBuilder($jobTimingClass); |
||||||
248 | if (method_exists($builder, 'map')) { |
||||||
249 | 1 | return $this->getJobTimingsOdmMapReduce($builder, $type, $end, $begin); |
|||||
250 | 1 | } |
|||||
251 | 1 | ||||||
252 | 1 | $regexInfo = $this->getRegexDate($type); |
|||||
253 | if (!$begin) { |
||||||
254 | $begin = clone $end; |
||||||
255 | 1 | $begin->sub($regexInfo['interval']); |
|||||
256 | 1 | } |
|||||
257 | 1 | ||||||
258 | 1 | $aggregationBuilder = $documentManager->createAggregationBuilder($jobTimingClass); |
|||||
259 | 1 | $expr = $this->addJobTimingsDateInfo($type, $aggregationBuilder->expr()); |
|||||
260 | 1 | $expr = $expr->field('status') |
|||||
261 | 1 | ->expression('$status'); |
|||||
262 | 1 | ||||||
263 | 1 | $aggregationBuilder |
|||||
264 | ->match() |
||||||
265 | 1 | ->field('finishedAt') |
|||||
266 | 1 | ->gte($begin) |
|||||
267 | 1 | ->lte($end) |
|||||
268 | 1 | ->group() |
|||||
269 | 1 | ->field('id') |
|||||
270 | 1 | ->expression($expr) |
|||||
271 | ->field('value') |
||||||
272 | ->sum(1); |
||||||
273 | 1 | ||||||
274 | $results = $aggregationBuilder->execute(); |
||||||
275 | $resultHash = []; |
||||||
276 | foreach ($results as $result) { |
||||||
277 | $key = $result['_id']['status']; |
||||||
278 | $dateStr = $this->getAggregationResultDateStr($type, $result['_id']); |
||||||
279 | $resultHash[$key][$dateStr] = $result['value']; |
||||||
280 | } |
||||||
281 | |||||||
282 | return $resultHash; |
||||||
283 | 1 | } |
|||||
284 | |||||||
285 | 1 | /** |
|||||
286 | 1 | * Formats the aggregation result into the desired date string format. |
|||||
287 | 1 | * |
|||||
288 | 1 | * @param string $type |
|||||
289 | 1 | * |
|||||
290 | 1 | * @return string |
|||||
291 | 1 | */ |
|||||
292 | 1 | protected function getAggregationResultDateStr($type, array $result) |
|||||
293 | { |
||||||
294 | 1 | switch ($type) { |
|||||
295 | 1 | case 'YEAR': |
|||||
296 | 1 | return $result['year']; |
|||||
297 | 1 | case 'MONTH': |
|||||
298 | 1 | return "{$result['year']}-".str_pad($result['month'], 2, '0', STR_PAD_LEFT); |
|||||
299 | case 'DAY': |
||||||
300 | 1 | $str = "{$result['year']}-".str_pad($result['month'], 2, '0', STR_PAD_LEFT); |
|||||
301 | 1 | $str .= '-'.str_pad($result['day'], 2, '0', STR_PAD_LEFT); |
|||||
302 | 1 | ||||||
303 | 1 | return $str; |
|||||
304 | 1 | case 'HOUR': |
|||||
305 | 1 | $str = "{$result['year']}-".str_pad($result['month'], 2, '0', STR_PAD_LEFT); |
|||||
306 | $str .= '-'.str_pad($result['day'], 2, '0', STR_PAD_LEFT); |
||||||
307 | 1 | $str .= ' '.str_pad($result['hour'], 2, '0', STR_PAD_LEFT); |
|||||
308 | |||||||
309 | return $str; |
||||||
310 | case 'MINUTE': |
||||||
311 | $str = "{$result['year']}-".str_pad($result['month'], 2, '0', STR_PAD_LEFT); |
||||||
312 | $str .= '-'.str_pad($result['day'], 2, '0', STR_PAD_LEFT); |
||||||
313 | 1 | $str .= ' '.str_pad($result['hour'], 2, '0', STR_PAD_LEFT); |
|||||
314 | $str .= ':'.str_pad($result['minute'], 2, '0', STR_PAD_LEFT); |
||||||
315 | 1 | ||||||
316 | 1 | return $str; |
|||||
317 | 1 | default: |
|||||
318 | 1 | throw new \InvalidArgumentException("Invalid date format type '$type''"); |
|||||
319 | 1 | } |
|||||
320 | 1 | } |
|||||
321 | 1 | ||||||
322 | 1 | protected function getDateFormat($type) |
|||||
323 | 1 | { |
|||||
324 | 1 | switch ($type) { |
|||||
325 | 1 | case 'YEAR': |
|||||
326 | return 'Y'; |
||||||
327 | case 'MONTH': |
||||||
328 | return 'Y-m'; |
||||||
329 | case 'DAY': |
||||||
330 | return 'Y-m-d'; |
||||||
331 | 1 | case 'HOUR': |
|||||
332 | return 'Y-m-d H'; |
||||||
333 | 1 | case 'MINUTE': |
|||||
334 | 1 | return 'Y-m-d H:i'; |
|||||
335 | 1 | default: |
|||||
336 | 1 | throw new \InvalidArgumentException("Invalid date format type '$type''"); |
|||||
337 | 1 | } |
|||||
338 | 1 | } |
|||||
339 | 1 | ||||||
340 | 1 | protected function getRegexDate($type) |
|||||
341 | 1 | { |
|||||
342 | 1 | switch ($type) { |
|||||
343 | 1 | case 'YEAR': |
|||||
344 | 1 | return ['replace' => ['regex' => '(\d+)\-(\d+)\-(\d+)T(\d+):(\d+):(\d+).+$', 'replacement' => '$1'], |
|||||
345 | 1 | 'interval' => new \DateInterval('P10Y'), ]; |
|||||
346 | 1 | case 'MONTH': |
|||||
347 | 1 | return ['replace' => ['regex' => '(\d+)\-(\d+)\-(\d+)T(\d+):(\d+):(\d+).+$', 'replacement' => '$1-$2'], |
|||||
348 | 1 | 'interval' => new \DateInterval('P12M'), ]; |
|||||
349 | case 'DAY': |
||||||
350 | return ['replace' => ['regex' => '(\d+)\-(\d+)\-(\d+)T(\d+):(\d+):(\d+).+$', 'replacement' => '$1-$2-$3'], |
||||||
351 | 'interval' => new \DateInterval('P31D'), ]; |
||||||
352 | case 'HOUR': |
||||||
353 | 1 | return ['replace' => ['regex' => '(\d+)\-(\d+)\-(\d+)T(\d+):(\d+):(\d+).+$', 'replacement' => '$1-$2-$3 $4'], |
|||||
354 | 'interval' => new \DateInterval('PT24H'), ]; |
||||||
355 | 1 | case 'MINUTE': |
|||||
356 | 1 | return ['replace' => ['regex' => '(\d+)\-(\d+)\-(\d+)T(\d+):(\d+):(\d+).+$', 'replacement' => '$1-$2-$3 $4:$5'], |
|||||
357 | 1 | 'interval' => new \DateInterval('PT3600S'), ]; |
|||||
358 | 1 | } |
|||||
359 | 1 | throw new \InvalidArgumentException("Invalid type $type"); |
|||||
360 | 1 | } |
|||||
361 | 1 | ||||||
362 | 1 | protected function getOrmGroupBy($type) |
|||||
363 | 1 | { |
|||||
364 | 1 | switch ($type) { |
|||||
365 | 1 | case 'YEAR': |
|||||
366 | 1 | return ['groupby' => 'YEAR(j.finishedAt)', |
|||||
367 | 1 | 'interval' => new \DateInterval('P10Y'), ]; |
|||||
368 | 1 | case 'MONTH': |
|||||
369 | 1 | return ['groupby' => 'CONCAT(YEAR(j.finishedAt),\'-\',MONTH(j.finishedAt))', |
|||||
370 | 1 | 'interval' => new \DateInterval('P12M'), ]; |
|||||
371 | case 'DAY': |
||||||
372 | return ['groupby' => 'CONCAT(YEAR(j.finishedAt),\'-\',MONTH(j.finishedAt),\'-\',DAY(j.finishedAt))', |
||||||
373 | 'interval' => new \DateInterval('P31D'), ]; |
||||||
374 | case 'HOUR': |
||||||
375 | 1 | return ['groupby' => 'CONCAT(YEAR(j.finishedAt),\'-\',MONTH(j.finishedAt),\'-\',DAY(j.finishedAt),\' \',HOUR(j.finishedAt))', |
|||||
376 | 'interval' => new \DateInterval('PT24H'), ]; |
||||||
377 | case 'MINUTE': |
||||||
378 | 1 | return ['groupby' => 'CONCAT(YEAR(j.finishedAt),\'-\',MONTH(j.finishedAt),\'-\',DAY(j.finishedAt),\' \',HOUR(j.finishedAt),\':\',MINUTE(j.finishedAt))', |
|||||
379 | 1 | 'interval' => new \DateInterval('PT3600S'), ]; |
|||||
380 | } |
||||||
381 | 1 | throw new \InvalidArgumentException("Invalid type $type"); |
|||||
382 | } |
||||||
383 | 1 | ||||||
384 | protected function getJobTimingsOrm($type, \DateTime $end, \DateTime $begin = null) |
||||||
385 | 1 | { |
|||||
386 | 1 | /** @var JobTimingManager $jobTimingManager */ |
|||||
387 | 1 | $jobTimingManager = $this->get('dtc_queue.manager.job_timing'); |
|||||
388 | $jobTimingClass = $jobTimingManager->getJobTimingClass(); |
||||||
389 | /** @var EntityManager $entityManager */ |
||||||
390 | 1 | $entityManager = $jobTimingManager->getObjectManager(); |
|||||
391 | 1 | ||||||
392 | 1 | $groupByInfo = $this->getOrmGroupBy($type); |
|||||
393 | 1 | ||||||
394 | 1 | if (!$begin) { |
|||||
395 | 1 | $begin = clone $end; |
|||||
396 | 1 | $begin->sub($groupByInfo['interval']); |
|||||
397 | 1 | } |
|||||
398 | |||||||
399 | $queryBuilder = $entityManager->createQueryBuilder()->select("j.status as status, count(j.finishedAt) as thecount, {$groupByInfo['groupby']} as thedate") |
||||||
400 | 1 | ->from($jobTimingClass, 'j') |
|||||
401 | ->where('j.finishedAt <= :end') |
||||||
402 | 1 | ->andWhere('j.finishedAt >= :begin') |
|||||
403 | 1 | ->setParameter(':end', $end) |
|||||
404 | 1 | ->setParameter(':begin', $begin) |
|||||
405 | 1 | ->groupBy('status') |
|||||
406 | ->addGroupBy('thedate'); |
||||||
407 | |||||||
408 | 1 | $result = $queryBuilder |
|||||
409 | ->getQuery()->getArrayResult(); |
||||||
410 | |||||||
411 | 1 | $resultHash = []; |
|||||
412 | foreach ($result as $row) { |
||||||
413 | 1 | $date = $this->formatOrmDateTime($type, $row['thedate']); |
|||||
414 | $resultHash[$row['status']][$date] = intval($row['thecount']); |
||||||
415 | } |
||||||
416 | 1 | ||||||
417 | return $resultHash; |
||||||
418 | 1 | } |
|||||
419 | 1 | ||||||
420 | 1 | protected function strPadLeft($str) |
|||||
421 | { |
||||||
422 | 1 | return str_pad($str, 2, '0', STR_PAD_LEFT); |
|||||
423 | 1 | } |
|||||
424 | 1 | ||||||
425 | protected function formatOrmDateTime($type, $str) |
||||||
426 | 1 | { |
|||||
427 | 1 | switch ($type) { |
|||||
428 | 1 | case 'MONTH': |
|||||
429 | 1 | $parts = explode('-', $str); |
|||||
430 | |||||||
431 | 1 | return $parts[0].'-'.$this->strPadLeft($parts[1]); |
|||||
432 | 1 | case 'DAY': |
|||||
433 | 1 | $parts = explode('-', $str); |
|||||
434 | 1 | ||||||
435 | 1 | return $parts[0].'-'.$this->strPadLeft($parts[1]).'-'.$this->strPadLeft($parts[2]); |
|||||
436 | case 'HOUR': |
||||||
437 | 1 | $parts = explode(' ', $str); |
|||||
438 | $dateParts = explode('-', $parts[0]); |
||||||
439 | |||||||
440 | 1 | return $dateParts[0].'-'.$this->strPadLeft($dateParts[1]).'-'.$this->strPadLeft($dateParts[2]).' '.$this->strPadLeft($parts[1]); |
|||||
441 | case 'MINUTE': |
||||||
442 | $parts = explode(' ', $str); |
||||||
443 | $dateParts = explode('-', $parts[0]); |
||||||
444 | $timeParts = explode(':', $parts[1]); |
||||||
445 | |||||||
446 | return $dateParts[0].'-'.$this->strPadLeft($dateParts[1]).'-'.$this->strPadLeft($dateParts[2]).' '.$this->strPadLeft($timeParts[0]).':'.$this->strPadLeft($timeParts[1]); |
||||||
447 | } |
||||||
448 | |||||||
449 | return $str; |
||||||
450 | } |
||||||
451 | } |
||||||
452 |