• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

conedevelopment / root / 15084089635

17 May 2025 10:00AM UTC coverage: 77.93% (+0.04%) from 77.891%
15084089635

push

github

web-flow
Modernize back-end.yml (#240)

3291 of 4223 relevant lines covered (77.93%)

36.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

9.78
/src/Widgets/Trend.php
1
<?php
2

3
namespace Cone\Root\Widgets;
4

5
use Closure;
6
use DatePeriod;
7
use Exception;
8
use Illuminate\Database\Eloquent\Builder;
9
use Illuminate\Http\Request;
10
use Illuminate\Support\Facades\Config;
11
use InvalidArgumentException;
12

13
abstract class Trend extends Metric
14
{
15
    /**
16
     * The Blade template.
17
     */
18
    protected string $template = 'root::widgets.trend';
19

20
    /**
21
     * The trend chart config.
22
     */
23
    protected array $config = [];
24

25
    /**
26
     * Create a new trend chart instance.
27
     */
28
    public function __construct()
198✔
29
    {
30
        parent::__construct();
198✔
31

32
        $this->config = Config::get('root.widgets.trend', []);
198✔
33
    }
34

35
    /**
36
     * Set the configuration.
37
     */
38
    public function withConfig(Closure $callback): static
×
39
    {
40
        $this->config = call_user_func_array($callback, [$this->config]);
×
41

42
        return $this;
×
43
    }
44

45
    /**
46
     * Get the widget configuration.
47
     */
48
    public function getConfig(): array
×
49
    {
50
        return $this->config;
×
51
    }
52

53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function periodFromRequest(Request $request, string $interval = 'day'): DatePeriod
×
57
    {
58
        return $this->period(
×
59
            $this->rangeToDateTime($this->getCurrentRange($request)),
×
60
            'now',
×
61
            $this->duration($interval)
×
62
        );
×
63
    }
64

65
    /**
66
     * {@inheritdoc}
67
     */
68
    protected function count(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
69
    {
70
        return $this->countByDays($request, $query, $column, $dateColumn);
×
71
    }
72

73
    /**
74
     * Count by minutes.
75
     */
76
    protected function countByMinutes(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
77
    {
78
        return $this->aggregateBy($request, $query, 'count', $column, $dateColumn, 'minute');
×
79
    }
80

81
    /**
82
     * Count by hours.
83
     */
84
    protected function countByHours(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
85
    {
86
        return $this->aggregateBy($request, $query, 'count', $column, $dateColumn, 'hour');
×
87
    }
88

89
    /**
90
     * Count by days.
91
     */
92
    protected function countByDays(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
93
    {
94
        return $this->aggregateBy($request, $query, 'count', $column, $dateColumn, 'day');
×
95
    }
96

97
    /**
98
     * Count by months.
99
     */
100
    protected function countByMonths(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
101
    {
102
        return $this->aggregateBy($request, $query, 'count', $column, $dateColumn, 'month');
×
103
    }
104

105
    /**
106
     * Count by years.
107
     */
108
    protected function countByYears(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
109
    {
110
        return $this->aggregateBy($request, $query, 'count', $column, $dateColumn, 'year');
×
111
    }
112

113
    /**
114
     * {@inheritdoc}
115
     */
116
    protected function avg(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
117
    {
118
        return $this->avgByDays($request, $query, $column, $dateColumn);
×
119
    }
120

121
    /**
122
     * Average by minutes.
123
     */
124
    protected function avgByMinutes(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
125
    {
126
        return $this->aggregateBy($request, $query, 'avg', $column, $dateColumn, 'minute');
×
127
    }
128

129
    /**
130
     * Average by hours.
131
     */
132
    protected function avgByHours(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
133
    {
134
        return $this->aggregateBy($request, $query, 'avg', $column, $dateColumn, 'hour');
×
135
    }
136

137
    /**
138
     * Average by days.
139
     */
140
    protected function avgByDays(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
141
    {
142
        return $this->aggregateBy($request, $query, 'avg', $column, $dateColumn, 'day');
×
143
    }
144

145
    /**
146
     * Average by months.
147
     */
148
    protected function avgByMonths(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
149
    {
150
        return $this->aggregateBy($request, $query, 'avg', $column, $dateColumn, 'month');
×
151
    }
152

153
    /**
154
     * Average by years.
155
     */
156
    protected function avgByYears(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
157
    {
158
        return $this->aggregateBy($request, $query, 'avg', $column, $dateColumn, 'year');
×
159
    }
160

161
    /**
162
     * {@inheritdoc}
163
     */
164
    protected function sum(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
165
    {
166
        return $this->sumByDays($request, $query, $column, $dateColumn);
×
167
    }
168

169
    /**
170
     * Sum by minutes.
171
     */
172
    protected function sumByMinutes(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
173
    {
174
        return $this->aggregateBy($request, $query, 'sum', $column, $dateColumn, 'minute');
×
175
    }
176

177
    /**
178
     * Sum by hours.
179
     */
180
    protected function sumByHours(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
181
    {
182
        return $this->aggregateBy($request, $query, 'sum', $column, $dateColumn, 'hour');
×
183
    }
184

185
    /**
186
     * Sum by days.
187
     */
188
    protected function sumByDays(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
189
    {
190
        return $this->aggregateBy($request, $query, 'sum', $column, $dateColumn, 'day');
×
191
    }
192

193
    /**
194
     * Sum by months.
195
     */
196
    protected function sumByMonths(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
197
    {
198
        return $this->aggregateBy($request, $query, 'sum', $column, $dateColumn, 'month');
×
199
    }
200

201
    /**
202
     * Sum by years.
203
     */
204
    protected function sumByYears(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
205
    {
206
        return $this->aggregateBy($request, $query, 'sum', $column, $dateColumn, 'year');
×
207
    }
208

209
    /**
210
     * {@inheritdoc}
211
     */
212
    protected function min(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
213
    {
214
        return $this->minByDays($request, $query, $column, $dateColumn);
×
215
    }
216

217
    /**
218
     * Min by minutes.
219
     */
220
    protected function minByMinutes(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
221
    {
222
        return $this->aggregateBy($request, $query, 'min', $column, $dateColumn, 'minute');
×
223
    }
224

225
    /**
226
     * Min by hours.
227
     */
228
    protected function minByHours(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
229
    {
230
        return $this->aggregateBy($request, $query, 'min', $column, $dateColumn, 'hour');
×
231
    }
232

233
    /**
234
     * Min by days.
235
     */
236
    protected function minByDays(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
237
    {
238
        return $this->aggregateBy($request, $query, 'min', $column, $dateColumn, 'day');
×
239
    }
240

241
    /**
242
     * Min by months.
243
     */
244
    protected function minByMonths(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
245
    {
246
        return $this->aggregateBy($request, $query, 'min', $column, $dateColumn, 'month');
×
247
    }
248

249
    /**
250
     * Min by years.
251
     */
252
    protected function minByYears(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
253
    {
254
        return $this->aggregateBy($request, $query, 'min', $column, $dateColumn, 'year');
×
255
    }
256

257
    /**
258
     * {@inheritdoc}
259
     */
260
    protected function max(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
261
    {
262
        return $this->maxByDays($request, $query, $column, $dateColumn);
×
263
    }
264

265
    /**
266
     * Max by minutes.
267
     */
268
    protected function maxByMinutes(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
269
    {
270
        return $this->aggregateBy($request, $query, 'max', $column, $dateColumn, 'minute');
×
271
    }
272

273
    /**
274
     * Max by hours.
275
     */
276
    protected function maxByHours(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
277
    {
278
        return $this->aggregateBy($request, $query, 'max', $column, $dateColumn, 'hour');
×
279
    }
280

281
    /**
282
     * Max by days.
283
     */
284
    protected function maxByDays(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
285
    {
286
        return $this->aggregateBy($request, $query, 'max', $column, $dateColumn, 'day');
×
287
    }
288

289
    /**
290
     * Max by months.
291
     */
292
    protected function maxByMonths(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
293
    {
294
        return $this->aggregateBy($request, $query, 'max', $column, $dateColumn, 'month');
×
295
    }
296

297
    /**
298
     * Max by years.
299
     */
300
    protected function maxByYears(Request $request, Builder $query, string $column = '*', ?string $dateColumn = null): array
×
301
    {
302
        return $this->aggregateBy($request, $query, 'max', $column, $dateColumn, 'year');
×
303
    }
304

305
    /**
306
     * Aggregate by the given interval.
307
     */
308
    protected function aggregateBy(Request $request, Builder $query, string $fn, string $column, ?string $dateColumn = null, string $interval = 'day'): array
×
309
    {
310
        $period = $this->periodFromRequest($request, $interval);
×
311

312
        $result = $this->result(
×
313
            $this->aggregate($query, $period, $fn, $column, $dateColumn, $interval)
×
314
        );
×
315

316
        return $this->resultBy($result, $period, $interval);
×
317
    }
318

319
    /**
320
     * {@inheritdoc}
321
     */
322
    protected function aggregate(Builder $query, DatePeriod $period, string $fn, string $column, ?string $dateColumn = null, string $interval = 'day'): Builder
×
323
    {
324
        $dateColumn ??= $query->getModel()->getCreatedAtColumn();
×
325

326
        $wrappedColumn = $query->getQuery()->getGrammar()->wrap($query->qualifyColumn($dateColumn));
×
327

328
        $format = match ($query->getQuery()->getConnection()->getDriverName()) {
×
329
            'mysql' => $this->mySqlFormat($wrappedColumn, $interval),
×
330
            'sqlite' => $this->sqliteFormat($wrappedColumn, $interval),
×
331
            'pgsql' => $this->pgsqlFormat($wrappedColumn, $interval),
×
332
            'sqlsrv' => $this->sqliteFormat($wrappedColumn, $interval),
×
333
            default => throw new Exception('Unsupported database driver.'),
×
334
        };
×
335

336
        return parent::aggregate($query, $period, $fn, $column, $dateColumn)
×
337
            ->selectRaw(sprintf('%s as `__interval`', $format))
×
338
            ->groupBy('__interval')
×
339
            ->orderBy('__interval');
×
340
    }
341

342
    /**
343
     * Get the duration by the given interval.
344
     */
345
    public function duration(string $interval): string
×
346
    {
347
        return match ($interval) {
×
348
            'minute' => 'PT1M',
×
349
            'hour' => 'PT1H',
×
350
            'day' => 'P1D',
×
351
            'month' => 'P1M',
×
352
            'year' => 'P1Y',
×
353
            default => 'P1D',
×
354
        };
×
355
    }
356

357
    /**
358
     * {@inheritdoc}
359
     */
360
    public function ranges(): array
2✔
361
    {
362
        return [
2✔
363
            'TODAY' => __('Today'),
2✔
364
            'WEEK' => __('Week to today'),
2✔
365
            'MONTH' => __('Month to today'),
2✔
366
            'QUARTER' => __('Quarter to today'),
2✔
367
            'YEAR' => __('Year to today'),
2✔
368
        ];
2✔
369
    }
370

371
    /**
372
     * Format the interval for MySQL.
373
     */
374
    protected function mySqlFormat(string $column, string $interval): string
×
375
    {
376
        $format = match ($interval) {
×
377
            'minute' => '%Y-%m-%d %H:%i:00',
×
378
            'hour' => '%Y-%m-%d %H:00:00',
×
379
            'day' => '%Y-%m-%d',
×
380
            'month' => '%Y-%m',
×
381
            'year' => '%Y',
×
382
            default => throw new InvalidArgumentException('Invalid interval for MySQL.'),
×
383
        };
×
384

385
        return sprintf("date_format(%s, '%s')", $column, $format);
×
386
    }
387

388
    /**
389
     * Format the interval for SQLite.
390
     */
391
    protected function sqliteFormat(string $column, string $interval): string
×
392
    {
393
        $format = match ($interval) {
×
394
            'minute' => '%Y-%m-%d %H:%M:00',
×
395
            'hour' => '%Y-%m-%d %H:00:00',
×
396
            'day' => '%Y-%m-%d',
×
397
            'month' => '%Y-%m',
×
398
            'year' => '%Y',
×
399
            default => throw new InvalidArgumentException('Invalid interval for SQLite.'),
×
400
        };
×
401

402
        return sprintf("strftime('%s', %s)", $format, $column);
×
403
    }
404

405
    /**
406
     * Format the interval for PgSQL.
407
     */
408
    protected function pgsqlFormat(string $column, string $interval): string
×
409
    {
410
        $format = match ($interval) {
×
411
            'minute' => 'YYYY-MM-DD HH24:MI:00',
×
412
            'hour' => 'YYYY-MM-DD HH24:00:00',
×
413
            'day' => 'YYYY-MM-DD',
×
414
            'month' => 'YYYY-MM',
×
415
            'year' => 'YYYY',
×
416
            default => throw new InvalidArgumentException('Invalid interval for PgSQL'),
×
417
        };
×
418

419
        return sprintf("to_char(%s, '%s')", $column, $format);
×
420
    }
421

422
    /**
423
     * Format the interval for SQLServer.
424
     */
425
    protected function sqlserverFormat(string $column, string $interval): string
×
426
    {
427
        $format = match ($interval) {
×
428
            'minute' => 'yyyy-MM-dd HH:mm:00:00',
×
429
            'hour' => 'yyyy-MM-dd HH:00:00',
×
430
            'day' => 'yyyy-MM-dd',
×
431
            'month' => 'yyyy-MM',
×
432
            'year' => 'yyyy',
×
433
            default => throw new InvalidArgumentException('Invalid interval for PgSQL'),
×
434
        };
×
435

436
        return sprintf("FORMAT(%s, '%s')", $column, $format);
×
437
    }
438

439
    /**
440
     * Format the interval for SQLServer.
441
     */
442
    protected function format(string $interval): string
×
443
    {
444
        return match ($interval) {
×
445
            'minute' => 'Y-m-d H:i:00',
×
446
            'hour' => 'Y-m-d H:00:00',
×
447
            'day' => 'Y-m-d',
×
448
            'month' => 'Y-m',
×
449
            'year' => 'Y',
×
450
            default => throw new InvalidArgumentException('Invalid interval.'),
×
451
        };
×
452
    }
453

454
    /**
455
     * Get the data.
456
     */
457
    public function data(Request $request): array
2✔
458
    {
459
        return array_replace_recursive([
2✔
460
            'data' => [
2✔
461
                'chart' => $request->isTurboFrameRequest() ? $this->config : [],
2✔
462
                'current' => null,
2✔
463
            ],
2✔
464
        ], parent::data($request));
2✔
465
    }
466

467
    /**
468
     * Get the results by the given interval.
469
     */
470
    public function resultBy(array $result, DatePeriod $period, string $interval): array
×
471
    {
472
        $dates = [];
×
473

474
        foreach ($period as $date) {
×
475
            $dates[$date->format($this->format($interval))] = 0;
×
476
        }
477

478
        $dates = array_replace($dates, $result);
×
479

480
        return [
×
481
            'current' => array_sum($dates),
×
482
            'chart' => [
×
483
                'series' => [
×
484
                    [
×
485
                        'name' => __('Value'),
×
486
                        'data' => array_values($dates),
×
487
                    ],
×
488
                ],
×
489
                'labels' => array_keys($dates),
×
490
            ],
×
491
        ];
×
492
    }
493
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc