Completed
Push — master ( 0f05a9...994973 )
by ARCANEDEV
06:19
created

Trend   D

Complexity

Total Complexity 57

Size/Duplication

Total Lines 672
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 43.71%

Importance

Changes 0
Metric Value
dl 0
loc 672
c 0
b 0
f 0
wmc 57
lcom 1
cbo 12
ccs 66
cts 151
cp 0.4371
rs 4.968

37 Methods

Rating   Name   Duplication   Size   Complexity  
A type() 0 4 1
A countByMonths() 0 4 1
A countByWeeks() 0 4 1
A countByDays() 0 4 1
A countByHours() 0 4 1
A countByMinutes() 0 4 1
A count() 0 4 1
A averageByMonths() 0 4 1
A averageByWeeks() 0 4 1
A averageByDays() 0 4 1
A averageByHours() 0 4 1
A averageByMinutes() 0 4 1
A average() 0 4 1
A sumByMonths() 0 4 1
A sumByWeeks() 0 4 1
A sumByDays() 0 4 1
A sumByHours() 0 4 1
A sumByMinutes() 0 4 1
A sum() 0 4 1
A maxByMonths() 0 4 1
A maxByWeeks() 0 4 1
A maxByDays() 0 4 1
A maxByHours() 0 4 1
A maxByMinutes() 0 4 1
A max() 0 4 1
A minByMonths() 0 4 1
A minByWeeks() 0 4 1
A minByDays() 0 4 1
A minByHours() 0 4 1
A minByMinutes() 0 4 1
A min() 0 4 1
A result() 0 4 1
A aggregate() 0 48 3
B parseDateResult() 0 23 6
B getAggregateStartingDate() 0 28 6
B getAllPossibleDateResults() 0 37 9
A toArray() 0 7 1

How to fix   Complexity   

Complex Class

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

1
<?php namespace Arcanedev\LaravelMetrics\Metrics;
2
3
use Arcanedev\LaravelMetrics\Exceptions\InvalidTrendUnitException;
4
use Arcanedev\LaravelMetrics\Metrics\Concerns\HasExpressions;
5
use Arcanedev\LaravelMetrics\Results\TrendResult;
6
use Cake\Chronos\Chronos;
7
use DateTime;
8
use Illuminate\Database\Eloquent\Builder;
9
use Illuminate\Support\Facades\DB;
10
11
/**
12
 * Class     Trend
13
 *
14
 * @package  Arcanedev\LaravelMetrics\Metrics
15
 * @author   ARCANEDEV <[email protected]>
16
 */
17
abstract class Trend extends Metric
18
{
19
    /* -----------------------------------------------------------------
20
     |  Constants
21
     | -----------------------------------------------------------------
22
     */
23
24
    /**
25
     * Trend metric unit constants.
26
     */
27
    const BY_MONTHS  = 'month';
28
    const BY_WEEKS   = 'week';
29
    const BY_DAYS    = 'day';
30
    const BY_HOURS   = 'hour';
31
    const BY_MINUTES = 'minute';
32
33
    /* -----------------------------------------------------------------
34
     |  Traits
35
     | -----------------------------------------------------------------
36
     */
37
38
    use HasExpressions,
39
        Concerns\HasRanges,
40
        Concerns\FormatsTrends;
41
42
    /* -----------------------------------------------------------------
43
     |  Getters
44
     | -----------------------------------------------------------------
45
     */
46
47
    /**
48
     * Get the metric type.
49
     *
50
     * @return string
51
     */
52 8
    public function type(): string
53
    {
54 8
        return 'trend';
55
    }
56
57
    /* -----------------------------------------------------------------
58
     |  Main Methods
59
     | -----------------------------------------------------------------
60
     */
61
62
    /**
63
     * Return a value result showing a count aggregate over months.
64
     *
65
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
66
     * @param  string|null                                   $column
67
     *
68
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
69
     */
70
    public function countByMonths($model, $column = null)
71
    {
72
        return $this->count(self::BY_MONTHS, $model, $column);
73
    }
74
75
    /**
76
     * Return a value result showing a count aggregate over weeks.
77
     *
78
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
79
     * @param  string|null                                   $column
80
     *
81
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
82
     */
83
    public function countByWeeks($model, $column = null)
84
    {
85
        return $this->count(self::BY_WEEKS, $model, $column);
86
    }
87
88
    /**
89
     * Return a value result showing a count aggregate over days.
90
     *
91
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
92
     * @param  string|null                                   $column
93
     *
94
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
95
     */
96 8
    public function countByDays($model, $column = null)
97
    {
98 8
        return $this->count(self::BY_DAYS, $model, $column);
99
    }
100
101
    /**
102
     * Return a value result showing a count aggregate over hours.
103
     *
104
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
105
     * @param  string|null                                   $column
106
     *
107
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
108
     */
109
    public function countByHours($model, $column = null)
110
    {
111
        return $this->count(self::BY_HOURS, $model, $column);
112
    }
113
114
    /**
115
     * Return a value result showing a count aggregate over minutes.
116
     *
117
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
118
     * @param  string|null                                   $column
119
     *
120
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
121
     */
122
    public function countByMinutes($model, $column = null)
123
    {
124
        return $this->count(self::BY_MINUTES, $model, $column);
125
    }
126
127
    /**
128
     * Return a value result showing a count aggregate over time.
129
     *
130
     * @param  string                                        $unit
131
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
132
     * @param  string|null                                   $dateColumn
133
     * @param  string|null                                   $column
134
     *
135
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
136
     */
137 8
    public function count($unit, $model, $dateColumn = null, $column = null)
138
    {
139 8
        return $this->aggregate('count', $unit, $model, $column, $dateColumn);
140
    }
141
142
    /**
143
     * Return a value result showing a average aggregate over months.
144
     *
145
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
146
     * @param  string                                        $column
147
     * @param  string|null                                   $dateColumn
148
     *
149
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
150
     */
151
    public function averageByMonths($model, $column, $dateColumn = null)
152
    {
153
        return $this->average(self::BY_MONTHS, $model, $column, $dateColumn);
154
    }
155
156
    /**
157
     * Return a value result showing a average aggregate over weeks.
158
     *
159
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
160
     * @param  string                                        $column
161
     * @param  string|null                                   $dateColumn
162
     *
163
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
164
     */
165
    public function averageByWeeks($model, $column, $dateColumn = null)
166
    {
167
        return $this->average(self::BY_WEEKS, $model, $column, $dateColumn);
168
    }
169
170
    /**
171
     * Return a value result showing a average aggregate over days.
172
     *
173
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
174
     * @param  string                                        $column
175
     * @param  string|null                                   $dateColumn
176
     *
177
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
178
     */
179
    public function averageByDays($model, $column, $dateColumn = null)
180
    {
181
        return $this->average(self::BY_DAYS, $model, $column, $dateColumn);
182
    }
183
184
    /**
185
     * Return a value result showing a average aggregate over hours.
186
     *
187
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
188
     * @param  string                                        $column
189
     * @param  string|null                                   $dateColumn
190
     *
191
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
192
     */
193
    public function averageByHours($model, $column, $dateColumn = null)
194
    {
195
        return $this->average(self::BY_HOURS, $model, $column, $dateColumn);
196
    }
197
198
    /**
199
     * Return a value result showing a average aggregate over minutes.
200
     *
201
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
202
     * @param  string                                        $column
203
     * @param  string|null                                   $dateColumn
204
     *
205
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
206
     */
207
    public function averageByMinutes($model, $column, $dateColumn = null)
208
    {
209
        return $this->average(self::BY_MINUTES, $model, $column, $dateColumn);
210
    }
211
212
    /**
213
     * Return a value result showing a average aggregate over time.
214
     *
215
     * @param  string                                        $unit
216
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
217
     * @param  string                                        $column
218
     * @param  string|null                                   $dateColumn
219
     *
220
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
221
     */
222
    public function average(string $unit, $model, $column, $dateColumn = null)
223
    {
224
        return $this->aggregate('avg', $unit, $model, $column, $dateColumn);
225
    }
226
227
    /**
228
     * Return a value result showing a sum aggregate over months.
229
     *
230
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
231
     * @param  string                                        $column
232
     * @param  string|null                                   $dateColumn
233
     *
234
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
235
     */
236
    public function sumByMonths($model, $column, $dateColumn = null)
237
    {
238
        return $this->sum(self::BY_MONTHS, $model, $column, $dateColumn);
239
    }
240
241
    /**
242
     * Return a value result showing a sum aggregate over weeks.
243
     *
244
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
245
     * @param  string                                        $column
246
     * @param  string                                        $dateColumn
247
     *
248
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
249
     */
250
    public function sumByWeeks($model, $column, $dateColumn = null)
251
    {
252
        return $this->sum(self::BY_WEEKS, $model, $column, $dateColumn);
253
    }
254
255
    /**
256
     * Return a value result showing a sum aggregate over days.
257
     *
258
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
259
     * @param  string                                        $column
260
     * @param  string|null                                   $dateColumn
261
     *
262
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
263
     */
264
    public function sumByDays($model, $column, $dateColumn = null)
265
    {
266
        return $this->sum(self::BY_DAYS, $model, $column, $dateColumn);
267
    }
268
269
    /**
270
     * Return a value result showing a sum aggregate over hours.
271
     *
272
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
273
     * @param  string                                        $column
274
     * @param  string                                        $dateColumn
275
     *
276
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
277
     */
278
    public function sumByHours($model, $column, $dateColumn = null)
279
    {
280
        return $this->sum(self::BY_HOURS, $model, $column, $dateColumn);
281
    }
282
283
    /**
284
     * Return a value result showing a sum aggregate over minutes.
285
     *
286
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
287
     * @param  string                                        $column
288
     * @param  string|null                                   $dateColumn
289
     *
290
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
291
     */
292
    public function sumByMinutes($model, $column, $dateColumn = null)
293
    {
294
        return $this->sum(self::BY_MINUTES, $model, $column, $dateColumn);
295
    }
296
297
    /**
298
     * Return a value result showing a sum aggregate over time.
299
     *
300
     * @param  string                                        $unit
301
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
302
     * @param  string                                        $column
303
     * @param  string|null                                   $dateColumn
304
     *
305
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
306
     */
307
    public function sum(string $unit, $model, $column, $dateColumn = null)
308
    {
309
        return $this->aggregate('sum', $unit, $model, $column, $dateColumn);
310
    }
311
312
    /**
313
     * Return a value result showing a max aggregate over months.
314
     *
315
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
316
     * @param  string                                        $column
317
     * @param  string|null                                   $dateColumn
318
     *
319
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
320
     */
321
    public function maxByMonths($model, $column, $dateColumn = null)
322
    {
323
        return $this->max(self::BY_MONTHS, $model, $column, $dateColumn);
324
    }
325
326
    /**
327
     * Return a value result showing a max aggregate over weeks.
328
     *
329
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
330
     * @param  string                                        $column
331
     * @param  string|null                                   $dateColumn
332
     *
333
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
334
     */
335
    public function maxByWeeks($model, $column, $dateColumn = null)
336
    {
337
        return $this->max(self::BY_WEEKS, $model, $column, $dateColumn);
338
    }
339
340
    /**
341
     * Return a value result showing a max aggregate over days.
342
     *
343
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
344
     * @param  string                                        $column
345
     * @param  string|null                                   $dateColumn
346
     *
347
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
348
     */
349
    public function maxByDays($model, $column, $dateColumn = null)
350
    {
351
        return $this->max(self::BY_DAYS, $model, $column, $dateColumn);
352
    }
353
354
    /**
355
     * Return a value result showing a max aggregate over hours.
356
     *
357
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
358
     * @param  string                                        $column
359
     * @param  string|null                                   $dateColumn
360
     *
361
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
362
     */
363
    public function maxByHours($model, $column, $dateColumn = null)
364
    {
365
        return $this->max(self::BY_HOURS, $model, $column, $dateColumn);
366
    }
367
368
    /**
369
     * Return a value result showing a max aggregate over minutes.
370
     *
371
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
372
     * @param  string                                        $column
373
     * @param  string|null                                   $dateColumn
374
     *
375
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
376
     */
377
    public function maxByMinutes($model, $column, $dateColumn = null)
378
    {
379
        return $this->max(self::BY_MINUTES, $model, $column, $dateColumn);
380
    }
381
382
    /**
383
     * Return a value result showing a max aggregate over time.
384
     *
385
     * @param  string                                        $unit
386
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
387
     * @param  string                                        $column
388
     * @param  string|null                                   $dateColumn
389
     *
390
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
391
     */
392
    public function max(string $unit, $model, $column, $dateColumn = null)
393
    {
394
        return $this->aggregate('max', $unit, $model, $column, $dateColumn);
395
    }
396
397
    /**
398
     * Return a value result showing a min aggregate over months.
399
     *
400
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
401
     * @param  string                                        $column
402
     * @param  string|null                                   $dateColumn
403
     *
404
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
405
     */
406
    public function minByMonths($model, $column, $dateColumn = null)
407
    {
408
        return $this->min(self::BY_MONTHS, $model, $column, $dateColumn);
409
    }
410
411
    /**
412
     * Return a value result showing a min aggregate over weeks.
413
     *
414
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
415
     * @param  string                                        $column
416
     * @param  string|null                                   $dateColumn
417
     *
418
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
419
     */
420
    public function minByWeeks($model, $column, $dateColumn = null)
421
    {
422
        return $this->min(self::BY_WEEKS, $model, $column, $dateColumn);
423
    }
424
425
    /**
426
     * Return a value result showing a min aggregate over days.
427
     *
428
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
429
     * @param  string                                        $column
430
     * @param  string|null                                   $dateColumn
431
     *
432
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
433
     */
434
    public function minByDays($model, $column, $dateColumn = null)
435
    {
436
        return $this->min(self::BY_DAYS, $model, $column, $dateColumn);
437
    }
438
439
    /**
440
     * Return a value result showing a min aggregate over hours.
441
     *
442
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
443
     * @param  string                                        $column
444
     * @param  string|null                                   $dateColumn
445
     *
446
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
447
     */
448
    public function minByHours($model, $column, $dateColumn = null)
449
    {
450
        return $this->min(self::BY_HOURS, $model, $column, $dateColumn);
451
    }
452
453
    /**
454
     * Return a value result showing a min aggregate over minutes.
455
     *
456
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
457
     * @param  string                                        $column
458
     * @param  string|null                                   $dateColumn
459
     *
460
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
461
     */
462
    public function minByMinutes($model, $column, $dateColumn = null)
463
    {
464
        return $this->min(self::BY_MINUTES, $model, $column, $dateColumn);
465
    }
466
467
    /**
468
     * Return a value result showing a min aggregate over time.
469
     *
470
     * @param  string                                        $unit
471
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
472
     * @param  string                                        $column
473
     * @param  string|null                                   $dateColumn
474
     *
475
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
476
     */
477
    public function min(string $unit, $model, $column, $dateColumn = null)
478
    {
479
        return $this->aggregate('min', $unit, $model, $column, $dateColumn);
480
    }
481
482
    /**
483
     * Make a new result instance.
484
     *
485
     * @param  mixed|null  $value
486
     *
487
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
488
     */
489 8
    protected function result($value = null)
490
    {
491 8
        return new TrendResult($value);
492
    }
493
494
    /* -----------------------------------------------------------------
495
     |  Other Methods
496
     | -----------------------------------------------------------------
497
     */
498
499
    /**
500
     * Handle the aggregate calculation of the metric.
501
     *
502
     * @param  string                                        $method
503
     * @param  string                                        $unit
504
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
505
     * @param  string|null                                   $column
506
     * @param  string|null                                   $dateColumn
507
     *
508
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
509
     */
510 8
    protected function aggregate(string $method, string $unit, $model, ?string $column = null, ?string $dateColumn = null)
511
    {
512 8
        $range          = (int) $this->request->input('range');
513 8
        $timezone       = $this->request->input('timezone');
514 8
        $twelveHourTime = $this->request->input('twelveHourTime') === 'true';
515
516 8
        $query      = static::getQuery($model);
517 8
        $column     = $column ?? $query->getModel()->getCreatedAtColumn();
0 ignored issues
show
Bug introduced by
The method getCreatedAtColumn does only exist in Illuminate\Database\Eloquent\Model, but not in Illuminate\Database\Eloquent\Builder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
518 8
        $dateColumn = $dateColumn ?? $query->getModel()->getCreatedAtColumn();
519 8
        $expression = $this->getExpression($query, 'trend_date_format', $dateColumn, [$unit, $query, $timezone]);
520
521 8
        $possibleDateResults = $this->getAllPossibleDateResults(
522 8
            $startingDate = $this->getAggregateStartingDate($unit),
523 8
            $endingDate = Chronos::now(),
524 4
            $unit,
525 4
            $timezone,
526 4
            $twelveHourTime
527
        );
528
529 8
        $wrappedColumn = $query->getQuery()->getGrammar()->wrap($column);
530
531 8
        $results = $query->select([
0 ignored issues
show
Bug introduced by
The method select() does not exist on Illuminate\Database\Eloquent\Builder. Did you maybe mean createSelectWithConstraint()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
532 8
                DB::raw("{$expression} as date_result"),
533 8
                DB::raw("{$method}({$wrappedColumn}) as aggregate")
534
            ])
535 8
            ->whereBetween($dateColumn, [$startingDate, $endingDate])
536 8
            ->groupBy(DB::raw($expression))
537 8
            ->orderBy('date_result')
538 8
            ->get();
539
540
        $results = array_merge($possibleDateResults, $results->mapWithKeys(function ($result) use ($method, $unit, $twelveHourTime) {
541
            return with(static::parseDateResult($result->getAttribute('date_result'), $unit), function ($date) use ($method, $unit, $twelveHourTime, $result) {
542 8
                $value = $result->getAttribute('aggregate');
543
544
                return [
545 8
                    $this->formatAggregateKey($date, $unit) => [
546 8
                        'label' => $this->formatLabelBy($date, $unit, $twelveHourTime),
547 8
                        'value' => $method === 'count' ? intval($value) : round($value, 0),
548
                    ],
549
                ];
550 8
            });
551 8
        })->all());
552
553 8
        if (count($results) > $range)
554 8
            array_shift($results);
555
556 8
        return $this->result()->trend($results);
557
    }
558
559
    /**
560
     * Parse the date result.
561
     *
562
     * @param  string  $dateResult
563
     * @param  string  $unit
564
     *
565
     * @return \Cake\Chronos\Chronos
566
     */
567 8
    protected function parseDateResult(string $dateResult, string $unit): Chronos
568
    {
569
        switch ($unit) {
570 8
            case self::BY_MONTHS:
571
                return Chronos::createFromFormat('Y-m', $dateResult);
572
573 8
            case self::BY_WEEKS:
574
                [$year, $week] = explode('-', $dateResult);
0 ignored issues
show
Bug introduced by
The variable $year does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $week does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
575
                return Chronos::instance((new DateTime)->setISODate($year, $week)->setTime(0, 0));
576
577 8
            case self::BY_DAYS:
578 8
                return Chronos::createFromFormat('Y-m-d', $dateResult);
579
580
            case self::BY_HOURS:
581
                return Chronos::createFromFormat('Y-m-d H:00', $dateResult);
582
583
            case self::BY_MINUTES:
584
                return Chronos::createFromFormat('Y-m-d H:i:00', $dateResult);
585
586
            default:
587
                throw InvalidTrendUnitException::make($unit);
588
        }
589
    }
590
591
    /**
592
     * Determine the proper aggregate starting date.
593
     *
594
     * @param  string  $unit
595
     *
596
     * @return \Cake\Chronos\Chronos
597
     */
598 8
    protected function getAggregateStartingDate(string $unit): Chronos
599
    {
600 8
        $range = $this->request->input('range', 2);
601
602
        switch ($unit) {
603 8
            case self::BY_MONTHS:
604
                return Chronos::now()->subMonths($range - 1)->firstOfMonth()->setTime(0, 0);
605
606 8
            case self::BY_WEEKS:
607
                return Chronos::now()->subWeeks($range - 1)->startOfWeek()->setTime(0, 0);
608
609 8
            case self::BY_DAYS:
610 8
                return Chronos::now()->subDays($range - 1)->setTime(0, 0);
611
612
            case self::BY_HOURS:
613
                return with(Chronos::now()->subHours($range - 1), function (Chronos $now) {
614
                    return $now->setTimeFromTimeString("{$now->hour}:00");
615
                });
616
617
            case self::BY_MINUTES:
618
                return with(Chronos::now()->subMinutes($range - 1), function (Chronos $now) {
619
                    return $now->setTimeFromTimeString("{$now->hour}:{$now->minute}:00");
620
                });
621
622
            default:
623
                throw InvalidTrendUnitException::make($unit);
624
        }
625
    }
626
627
    /**
628
     * Get all of the possible date results for the given units.
629
     *
630
     * @param  \Cake\Chronos\Chronos  $startDate
631
     * @param  \Cake\Chronos\Chronos  $endDate
632
     * @param  string                 $unit
633
     * @param  mixed                  $timezone
634
     * @param  bool                   $twelveHourTime
635
     *
636
     * @return array
637
     */
638 8
    protected function getAllPossibleDateResults(
639
        Chronos $startDate, Chronos $endDate, string $unit, $timezone, bool $twelveHourTime
640
    ): array
641
    {
642 8
        $nextDate = $startDate;
643
644 8
        if ( ! empty($timezone)) {
645
            $nextDate = $startDate->setTimezone($timezone);
646
            $endDate  = $endDate->setTimezone($timezone);
647
        }
648
649 8
        $possibleDateResults[static::formatAggregateKey($nextDate, $unit)] = [
0 ignored issues
show
Coding Style Comprehensibility introduced by
$possibleDateResults was never initialized. Although not strictly required by PHP, it is generally a good practice to add $possibleDateResults = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
650 8
            'label' => static::formatLabelBy($nextDate, $unit, $twelveHourTime),
651 8
            'value' => 0,
652
        ];
653
654 8
        while ($nextDate->lt($endDate)) {
655 8
            if ($unit === self::BY_MONTHS)
656
                $nextDate = $nextDate->addMonths(1);
657 8
            elseif ($unit === self::BY_WEEKS)
658
                $nextDate = $nextDate->addWeeks(1);
659 8
            elseif ($unit === self::BY_DAYS)
660 8
                $nextDate = $nextDate->addDays(1);
661
            elseif ($unit === self::BY_HOURS)
662
                $nextDate = $nextDate->addHours(1);
663
            elseif ($unit === self::BY_MINUTES)
664
                $nextDate = $nextDate->addMinutes(1);
665
666 8
            if ($nextDate->lte($endDate))
667 8
                $possibleDateResults[static::formatAggregateKey($nextDate, $unit)] = [
668 8
                    'label' => static::formatLabelBy($nextDate, $unit, $twelveHourTime),
669 8
                    'value' => 0,
670
                ];
671
        }
672
673 8
        return $possibleDateResults;
674
    }
675
676
    /**
677
     * Prepare the metric for JSON serialization.
678
     *
679
     * @return array
680
     */
681
    public function toArray(): array
682
    {
683
        return array_merge(
684
            parent::toArray(),
685
            ['ranges' => $this->rangesToArray()]
686
        );
687
    }
688
}
689