Completed
Push — master ( 7d470a...9bd53b )
by ARCANEDEV
24s queued 10s
created

Trend::toArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arcanedev\LaravelMetrics\Metrics;
6
7
use Arcanedev\LaravelMetrics\Exceptions\InvalidTrendUnitException;
8
use Arcanedev\LaravelMetrics\Helpers\TrendDatePeriod;
9
use Arcanedev\LaravelMetrics\Results\TrendResult;
10
use Cake\Chronos\Chronos;
11
use Illuminate\Support\Facades\DB;
12
13
/**
14
 * Class     Trend
15
 *
16
 * @package  Arcanedev\LaravelMetrics\Metrics
17
 * @author   ARCANEDEV <[email protected]>
18
 */
19
abstract class Trend extends Metric
20
{
21
    /* -----------------------------------------------------------------
22
     |  Constants
23
     | -----------------------------------------------------------------
24
     */
25
26
    /**
27
     * Trend metric unit constants.
28
     */
29
    const BY_MONTHS  = 'month';
30
    const BY_WEEKS   = 'week';
31
    const BY_DAYS    = 'day';
32
    const BY_HOURS   = 'hour';
33
    const BY_MINUTES = 'minute';
34
35
    /* -----------------------------------------------------------------
36
     |  Traits
37
     | -----------------------------------------------------------------
38
     */
39
40
    use Concerns\AggregatesTrends,
41
        Concerns\HasExpressions,
42
        Concerns\HasRanges,
43
        Concerns\HasRoundedValue,
44
        Concerns\FormatsTrends;
45
46
    /* -----------------------------------------------------------------
47
     |  Getters
48
     | -----------------------------------------------------------------
49
     */
50
51
    /**
52
     * Get the metric type.
53
     *
54
     * @return string
55
     */
56 36
    public function type(): string
57
    {
58 36
        return 'trend';
59
    }
60
61
    /* -----------------------------------------------------------------
62
     |  Main Methods
63
     | -----------------------------------------------------------------
64
     */
65
66
    /**
67
     * Calculate the `count` of the metric.
68
     *
69
     * @param  string                                        $unit
70
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
71
     * @param  string|null                                   $dateColumn
72
     * @param  string|null                                   $column
73
     *
74
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
75
     */
76 42
    public function count($unit, $model, $dateColumn = null, $column = null)
77
    {
78 42
        return $this->aggregate('count', $unit, $model, $column, $dateColumn);
79
    }
80
81
    /**
82
     * Return a value result showing a average aggregate over time.
83
     *
84
     * @param  string                                        $unit
85
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
86
     * @param  string                                        $column
87
     * @param  string|null                                   $dateColumn
88
     *
89
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
90
     */
91 12
    public function average(string $unit, $model, $column, $dateColumn = null)
92
    {
93 12
        return $this->aggregate('avg', $unit, $model, $column, $dateColumn);
94
    }
95
96
    /**
97
     * Return a value result showing a sum aggregate over time.
98
     *
99
     * @param  string                                        $unit
100
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
101
     * @param  string                                        $column
102
     * @param  string|null                                   $dateColumn
103
     *
104
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
105
     */
106
    public function sum(string $unit, $model, $column, $dateColumn = null)
107
    {
108
        return $this->aggregate('sum', $unit, $model, $column, $dateColumn);
109
    }
110
111
    /**
112
     * Return a value result showing a max aggregate over time.
113
     *
114
     * @param  string                                        $unit
115
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
116
     * @param  string                                        $column
117
     * @param  string|null                                   $dateColumn
118
     *
119
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
120
     */
121
    public function max(string $unit, $model, $column, $dateColumn = null)
122
    {
123
        return $this->aggregate('max', $unit, $model, $column, $dateColumn);
124
    }
125
126
    /**
127
     * Return a value result showing a min aggregate over time.
128
     *
129
     * @param  string                                        $unit
130
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
131
     * @param  string                                        $column
132
     * @param  string|null                                   $dateColumn
133
     *
134
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
135
     */
136
    public function min(string $unit, $model, $column, $dateColumn = null)
137
    {
138
        return $this->aggregate('min', $unit, $model, $column, $dateColumn);
139
    }
140
141
    /**
142
     * Make a new result instance.
143
     *
144
     * @param  mixed|null  $value
145
     *
146
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
147
     */
148 54
    protected function result($value = null)
149
    {
150 54
        return new TrendResult($value);
151
    }
152
153
    /* -----------------------------------------------------------------
154
     |  Other Methods
155
     | -----------------------------------------------------------------
156
     */
157
158
    /**
159
     * Handle the aggregate calculation of the metric.
160
     *
161
     * @param  string                                        $method
162
     * @param  string                                        $unit
163
     * @param  \Illuminate\Database\Eloquent\Builder|string  $model
164
     * @param  string|null                                   $column
165
     * @param  string|null                                   $dateColumn
166
     *
167
     * @return \Arcanedev\LaravelMetrics\Results\TrendResult|mixed
168
     */
169 54
    protected function aggregate(string $method, string $unit, $model, ?string $column = null, ?string $dateColumn = null)
170
    {
171 54
        $range          = $this->request->input('range');
172 54
        $timezone       = $this->getCurrentTimezone($this->request);
173 54
        $twelveHourTime = $this->request->input('twelveHourTime') === 'true';
174
175 54
        $query      = static::getQuery($model);
176 54
        $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...
177 54
        $dateColumn = $dateColumn ?? $query->getModel()->getCreatedAtColumn();
178 54
        $expression = static::getExpression($query, 'trend_date_format', $dateColumn, [$unit, $query, $timezone]);
179
180 54
        $dates = TrendDatePeriod::make(
181 54
            $startingDate = TrendDatePeriod::getStartingDate($unit, $range),
182 54
            $endingDate = Chronos::now(),
183 18
            $unit,
184 18
            $timezone
185
        )->mapWithKeys(function (Chronos $date) use ($twelveHourTime, $unit) {
186
            return [
187 54
                static::formatAggregateKey($date, $unit) => [
188 54
                    'label' => static::formatLabelBy($date, $unit, $twelveHourTime),
189 54
                    'value' => 0,
190
                ]
191
            ];
192 54
        });
193
194 54
        $wrappedColumn = $query->getQuery()->getGrammar()->wrap($column);
195
196 54
        $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...
197 54
                DB::raw("{$expression} as date_result"),
198 54
                DB::raw("{$method}({$wrappedColumn}) as aggregate")
199
            ])
200 54
            ->whereBetween($dateColumn, [$startingDate, $endingDate])
201 54
            ->groupBy('date_result')
202 54
            ->orderBy('date_result')
203 54
            ->get()
204
            ->mapWithKeys(function ($result) use ($method, $unit, $twelveHourTime) {
205 54
                $date  = static::parseDateResult($result->getAttribute('date_result'), $unit);
206 54
                $value = $result->getAttribute('aggregate');
207
208
                return [
209 54
                    static::formatAggregateKey($date, $unit) => [
210 54
                        'label' => static::formatLabelBy($date, $unit, $twelveHourTime),
211 54
                        'value' => $method === 'count' ? intval($value) : $this->roundValue($value),
212
                    ],
213
                ];
214 54
            });
215
216 54
        $results = $dates->merge($results)->sortKeys();
217
218 54
        if ($results->count() > $range)
219 30
            $results->shift();
220
221 54
        return $this->result()->trend($results->all());
222
    }
223
224
    /**
225
     * Parse the date result.
226
     *
227
     * @param  string  $date
228
     * @param  string  $unit
229
     *
230
     * @return \Cake\Chronos\Chronos
231
     */
232 54
    protected function parseDateResult(string $date, string $unit): Chronos
233
    {
234
        switch ($unit) {
235 54
            case self::BY_MONTHS:
236 30
                [$year, $month] = explode('-', $date);
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 $month 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...
237 30
                return Chronos::create((int) $year, (int) $month, 1);
238
239 24
            case self::BY_WEEKS:
240 6
                [$year, $week] = explode('-', $date);
0 ignored issues
show
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...
241 6
                return (new Chronos)->setISODate((int) $year, (int) $week)->setTime(0, 0);
242
243 18
            case self::BY_DAYS:
244 6
                return Chronos::createFromFormat('Y-m-d', $date);
245
246 12
            case self::BY_HOURS:
247 6
                return Chronos::createFromFormat('Y-m-d H:00', $date);
248
249 6
            case self::BY_MINUTES:
250 6
                return Chronos::createFromFormat('Y-m-d H:i:00', $date);
251
252
            default:
253
                throw InvalidTrendUnitException::make($unit);
254
        }
255
    }
256
257
    /**
258
     * Get the instance as an array.
259
     *
260
     * @return array
261
     */
262 6
    public function toArray(): array
263
    {
264 6
        return array_merge(
265 6
            parent::toArray(),
266 6
            ['ranges' => $this->rangesToArray()]
267
        );
268
    }
269
}
270