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