From 1660734da85e0b44c04585bba7dcbdb979402777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=2E=20Nagy=20Gerg=C5=91?= Date: Wed, 29 May 2024 12:12:46 +0200 Subject: [PATCH] wip --- src/Fields/Relation.php | 50 +++++++++++++++++++++++++++++++++++--- src/Resources/Resource.php | 20 ++++++++++++++- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/Fields/Relation.php b/src/Fields/Relation.php index e32ada2a..783f9c9d 100644 --- a/src/Fields/Relation.php +++ b/src/Fields/Relation.php @@ -82,6 +82,16 @@ abstract class Relation extends Field implements Form */ protected ?Closure $queryResolver = null; + /** + * Determine if the field is computed. + */ + protected ?Closure $aggregateResolver = null; + + /** + * Determine whether the relation values are aggregated. + */ + protected bool $aggregated = false; + /** * The option group resolver. */ @@ -209,10 +219,6 @@ public function asSubResource(bool $value = true): static { $this->asSubResource = $value; - $this->format(function (Request $request, Model $model): ?int { - return $model->getAttribute(sprintf('%s_count', $this->getRelationName())); - }); - return $this; } @@ -335,6 +341,10 @@ public function resolveDisplay(Model $related): ?string */ public function getValue(Model $model): mixed { + if ($this->aggregated) { + return parent::getValue($model); + } + $name = $this->getRelationName(); if ($this->relation instanceof Closure && ! $model->relationLoaded($name)) { @@ -353,6 +363,10 @@ public function resolveFormat(Request $request, Model $model): ?string $this->formatResolver = function (Request $request, Model $model): mixed { $default = $this->getValue($model); + if ($this->aggregated) { + return $default; + } + return Collection::wrap($default)->map(function (Model $related) use ($model, $request): mixed { return $this->formatRelated($request, $model, $related); })->filter()->join(', '); @@ -465,6 +479,34 @@ public function resolveRelatableQuery(Request $request, Model $model): Builder }); } + /** + * Aggregate relation values. + */ + public function aggregate(string $fn = 'count', string $column = '*'): static + { + $this->aggregateResolver = function (Request $request, Builder $query) use ($fn, $column): Builder { + $this->setModelAttribute(sprintf('%s_%s', $this->getRelationName(), $fn)); + + $this->aggregated = true; + + return $query->withAggregate($this->getRelationName(), $column, $fn); + }; + + return $this; + } + + /** + * Resolve the aggregate query. + */ + public function resolveAggregate(Request $request, Builder $query): Builder + { + if (! is_null($this->aggregateResolver)) { + $query = call_user_func_array($this->aggregateResolver, [$request, $query]); + } + + return $query; + } + /** * Set the group resolver attribute. */ diff --git a/src/Resources/Resource.php b/src/Resources/Resource.php index 76e1a452..efd682d2 100644 --- a/src/Resources/Resource.php +++ b/src/Resources/Resource.php @@ -4,9 +4,13 @@ use Cone\Root\Actions\Action; use Cone\Root\Exceptions\SaveFormDataException; +use Cone\Root\Fields\BelongsToMany; use Cone\Root\Fields\Events; use Cone\Root\Fields\Field; use Cone\Root\Fields\Fields; +use Cone\Root\Fields\HasMany; +use Cone\Root\Fields\Meta; +use Cone\Root\Fields\MorphMany; use Cone\Root\Fields\Relation; use Cone\Root\Filters\Filter; use Cone\Root\Filters\RenderableFilter; @@ -403,6 +407,21 @@ public function getSortKey(): string public function paginate(Request $request): LengthAwarePaginator { return $this->resolveFilteredQuery($request) + ->tap(function (Builder $query) use ($request): void { + $this->resolveFields($request) + ->authorized($request, $query->getModel()) + ->visible('index') + ->filter(fn (Field $field): bool => $field instanceof Relation) + ->each(static function (Relation $relation) use ($query, $request): void { + if ($relation instanceof BelongsToMany || $relation instanceof HasMany || $relation instanceof MorphMany) { + $relation->resolveAggregate($request, $query); + } elseif ($relation instanceof Meta) { + $query->with('metaData'); + } else { + $query->with($relation->getRelationName()); + } + }); + }) ->latest() ->paginate($request->input($this->getPerPageKey())) ->withQueryString() @@ -422,7 +441,6 @@ public function mapModel(Request $request, Model $model): array 'model' => $model, 'abilities' => $this->mapModelAbilities($request, $model), 'fields' => $this->resolveFields($request) - ->subResource(false) ->authorized($request, $model) ->visible('index') ->mapToDisplay($request, $model),