Completed
Push — master ( 1842cb...2414f9 )
by ARCANEDEV
03:37
created

Trend::result()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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