diff --git a/src/Widgets/Metric.php b/src/Widgets/Metric.php index 8d8fb904..3dd51948 100644 --- a/src/Widgets/Metric.php +++ b/src/Widgets/Metric.php @@ -4,6 +4,7 @@ use Closure; use Cone\Root\Exceptions\QueryResolutionException; +use Cone\Root\Widgets\Results\Result; use DateTimeInterface; use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Request; @@ -24,7 +25,7 @@ abstract class Metric extends Widget /** * Calculate the metric data. */ - abstract public function calculate(Request $request): array; + abstract public function calculate(Request $request): Result; /** * Set the query. @@ -89,12 +90,13 @@ public function getCurrentRange(Request $request): string } /** - * Create a new method. + * Calculate the range. */ protected function range(DateTimeInterface $date, string $range): mixed { return match ($range) { 'TODAY' => $date->startOfDay(), + 'DAY' => $date->subDay(), 'WEEK' => $date->subWeek(), 'MONTH' => $date->subMonth(), 'QUARTER' => $date->subQuarter(), @@ -126,7 +128,7 @@ public function data(Request $request): array { return array_merge(parent::data($request), [ 'ranges' => $this->ranges(), - 'data' => $this->calculate($request), + 'data' => $this->calculate($request)->toArray(), ]); } } diff --git a/src/Widgets/Results/Result.php b/src/Widgets/Results/Result.php new file mode 100644 index 00000000..1d6780cf --- /dev/null +++ b/src/Widgets/Results/Result.php @@ -0,0 +1,10 @@ +current = round($current, 2); + $this->previous = round($previous, 2); + } + + /** + * Calculate the trend. + */ + public function trend(): float + { + return $this->previous === 0 ? 0 : round(($this->current - $this->previous) / (($this->current + $this->previous) / 2) * 100, 1); + } + + /** + * Convert the result as an array. + */ + public function toArray(): array + { + return [ + 'previous' => $this->previous, + 'current' => $this->current, + 'trend' => $this->trend(), + ]; + } +} diff --git a/src/Widgets/Trend.php b/src/Widgets/Trend.php index 8fc67fa9..fe1aadab 100644 --- a/src/Widgets/Trend.php +++ b/src/Widgets/Trend.php @@ -2,20 +2,10 @@ namespace Cone\Root\Widgets; -use Illuminate\Http\Request; - abstract class Trend extends Metric { /** * The Blade template. */ protected string $template = 'root::widgets.trend'; - - /** - * Calculate the metric data. - */ - public function calculate(Request $request): array - { - return []; - } } diff --git a/src/Widgets/Value.php b/src/Widgets/Value.php index 3c5ae40a..6b7d3bb9 100644 --- a/src/Widgets/Value.php +++ b/src/Widgets/Value.php @@ -2,6 +2,7 @@ namespace Cone\Root\Widgets; +use Cone\Root\Widgets\Results\ValueResult; use DateTimeInterface; use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Request; @@ -43,7 +44,9 @@ public function previous(Request $request): DateTimeInterface { $from = $this->from($request); - return $this->range($from, $this->getCurrentRange($request)); + $range = $this->getCurrentRange($request); + + return $this->range($from, $range === 'TODAY' ? 'DAY' : $range); } /** @@ -61,44 +64,51 @@ public function resolveQuery(Request $request): Builder $column = $query->getModel()->getQualifiedCreatedAtColumn(); - return $query->whereBetween($column, [$previous, $to])->groupByRaw(sprintf( - "(case when %s between '%s' and '%s' then 0 else 1 end)", + return $query->selectRaw(sprintf( + "(case when %s between '%s' and '%s' then 'previous' else 'current' end) as `__interval`", $query->getQuery()->getGrammar()->wrap($column), (string) $previous, (string) $from - )); + ))->whereBetween($column, [$previous, $to])->groupBy('__interval'); }); } /** - * Count values. + * Aggregate count values. */ - public function count(Request $request, string $column = '*'): array + public function count(Request $request, Builder $query, string $column = '*'): ValueResult { - return $this->resolveQuery($request) - ->getQuery() - ->selectRaw(sprintf('count(%s) as `total`', $column)) - ->get() - ->pluck('total') - ->toArray(); + return $this->toResult( + $query->selectRaw(sprintf('count(%s) as `__value`', $query->getQuery()->getGrammar()->wrap($column))) + ); } /** - * Calculate the metric data. + * Aggregate average values. */ - public function calculate(Request $request): array + public function avg(Request $request, Builder $query, string $column): ValueResult { - $data = $this->count($request); + return $this->toResult( + $query->selectRaw(sprintf('avg(%s) as `__value`', $query->getQuery()->getGrammar()->wrap($column))) + ); + } - $previous = count($data) === 1 ? 0 : $data[0]; + /** + * Calculate the metric data. + */ + public function calculate(Request $request): ValueResult + { + return $this->avg($request, $this->resolveQuery($request), 'discount'); + } - $current = count($data) === 1 ? $data[0] : $data[1]; + /** + * Convert the query to result. + */ + public function toResult(Builder $query): ValueResult + { + $data = $query->getQuery()->get()->pluck('__value', '__interval')->all(); - return [ - 'previous' => $previous, - 'current' => $current, - 'trend' => $previous === 0 ? 0 : round(($current - $previous) / (($current + $previous) / 2) * 100, 1), - ]; + return new ValueResult($data['current'] ?? 0, $data['previous'] ?? 0); } /**