From e84527b32d5f1c7e58f838c193e6a3698d2d1a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=2E=20Nagy=20Gerg=C5=91?= Date: Wed, 15 Nov 2023 11:38:35 +0100 Subject: [PATCH] wip --- src/Fields/BelongsToMany.php | 3 - src/Fields/Fields.php | 26 +++++++- src/Fields/Media.php | 27 --------- src/Fields/Relation.php | 106 +++++++++++++++++++++++++++++++++ src/Interfaces/Table.php | 19 ------ src/Resources/Resource.php | 14 ++++- src/Traits/ResolvesActions.php | 23 +++++++ src/Traits/ResolvesFields.php | 6 +- src/Traits/ResolvesFilters.php | 23 +++++++ 9 files changed, 191 insertions(+), 56 deletions(-) delete mode 100644 src/Interfaces/Table.php diff --git a/src/Fields/BelongsToMany.php b/src/Fields/BelongsToMany.php index 1d4e7efc..465d1277 100644 --- a/src/Fields/BelongsToMany.php +++ b/src/Fields/BelongsToMany.php @@ -3,7 +3,6 @@ namespace Cone\Root\Fields; use Closure; -use Cone\Root\Traits\ResolvesFields; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany as EloquentRelation; use Illuminate\Http\Request; @@ -11,8 +10,6 @@ class BelongsToMany extends Relation { - use ResolvesFields; - /** * The pivot fields resolver callback. */ diff --git a/src/Fields/Fields.php b/src/Fields/Fields.php index c1398fc0..c3cd6e9e 100644 --- a/src/Fields/Fields.php +++ b/src/Fields/Fields.php @@ -67,6 +67,28 @@ public function sortable(): static return $this->filter->isSortable(); } + /** + * Filter the relation fields. + */ + public function relation(): static + { + return $this->filter(static function (Field $field): bool { + return $field instanceof Relation; + }); + } + + /** + * Filter the subresource fields. + */ + public function subResource(bool $value = true): static + { + return $this->filter(static function (Field $field) use ($value): bool { + return $value + ? $field instanceof Relation && $field->isSubResource() + : ! $field instanceof Relation || ! $field->isSubResource(); + }); + } + /** * Map the fields to validate. */ @@ -82,7 +104,7 @@ public function mapToValidate(Request $request, Model $model): array */ public function mapToDisplay(Request $request, Model $model): array { - return $this->map->toDisplay($request, $model)->all(); + return $this->map->toDisplay($request, $model)->filter()->values()->all(); } /** @@ -90,7 +112,7 @@ public function mapToDisplay(Request $request, Model $model): array */ public function mapToInputs(Request $request, Model $model): array { - return $this->map->toInput($request, $model)->all(); + return $this->map->toInput($request, $model)->filter()->values()->all(); } /** diff --git a/src/Fields/Media.php b/src/Fields/Media.php index 88fabc85..acf70173 100644 --- a/src/Fields/Media.php +++ b/src/Fields/Media.php @@ -10,8 +10,6 @@ use Cone\Root\Http\Controllers\MediaController; use Cone\Root\Models\Medium; use Cone\Root\Traits\HasMedia; -use Cone\Root\Traits\RegistersRoutes; -use Cone\Root\Traits\ResolvesFilters; use Illuminate\Database\Eloquent\Model; use Illuminate\Http\Request; use Illuminate\Http\UploadedFile; @@ -24,11 +22,6 @@ class Media extends File { - use RegistersRoutes { - RegistersRoutes::registerRoutes as __registerRoutes; - } - use ResolvesFilters; - /** * Indicates if the component is multiple. */ @@ -44,14 +37,6 @@ class Media extends File */ protected ?Closure $filtersResolver = null; - /** - * Get the URI key. - */ - public function getUriKey(): string - { - return str_replace('.', '-', $this->getRequestKey()); - } - /** * Get the route parameter name. */ @@ -218,18 +203,6 @@ public function buildUri(Request $request, Model $model): ?string return rtrim($uri, '?'); } - /** - * Register the routes using the given router. - */ - public function registerRoutes(Request $request, Router $router): void - { - $this->__registerRoutes($request, $router); - - $router->prefix($this->getUriKey())->group(function (Router $router) use ($request): void { - $this->resolveFields($request)->registerRoutes($request, $router); - }); - } - /** * The routes that should be registered. */ diff --git a/src/Fields/Relation.php b/src/Fields/Relation.php index 63ef4b2a..538ba377 100644 --- a/src/Fields/Relation.php +++ b/src/Fields/Relation.php @@ -3,16 +3,29 @@ namespace Cone\Root\Fields; use Closure; +use Cone\Root\Filters\RenderableFilter; use Cone\Root\Root; +use Cone\Root\Traits\RegistersRoutes; +use Cone\Root\Traits\ResolvesActions; +use Cone\Root\Traits\ResolvesFields; +use Cone\Root\Traits\ResolvesFilters; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Relation as EloquentRelation; use Illuminate\Http\Request; +use Illuminate\Routing\Router; use Illuminate\Support\Collection; use Illuminate\Support\Str; abstract class Relation extends Field { + use ResolvesActions; + use ResolvesFilters; + use ResolvesFields; + use RegistersRoutes { + RegistersRoutes::registerRoutes as __registerRoutes; + } + /** * The relation name on the model. */ @@ -53,6 +66,11 @@ abstract class Relation extends Field */ protected string|Closure|null $groupResolver = null; + /** + * Indicates wheter the relation is a sub resource. + */ + protected bool $asSubResource = false; + /** * The query scopes. */ @@ -106,6 +124,32 @@ public function getRelationName(): string : $this->relation; } + /** + * Get the URI key. + */ + public function getUriKey(): string + { + return str_replace('.', '-', $this->getRequestKey()); + } + + /** + * Set the as subresource attribute. + */ + public function asSubResource(bool $value = true): static + { + $this->asSubResource = $value; + + return $this; + } + + /** + * Determine if the relation is a subresource. + */ + public function isSubResource(): bool + { + return $this->asSubResource; + } + /** * Set the nullable attribute. */ @@ -299,6 +343,44 @@ public function newOption(Model $related, string $label): Option return new Option($related->getKey(), $label); } + /** + * Get the per page options. + */ + public function getPerPageOptions(): array + { + return [5, 10, 15, 25]; + } + + /** + * Paginate the results. + */ + public function paginate(Request $request, Model $model): array + { + return [ + // + ]; + } + + /** + * Register the routes using the given router. + */ + public function registerRoutes(Request $request, Router $router): void + { + $this->__registerRoutes($request, $router); + + $router->prefix($this->getUriKey())->group(function (Router $router) use ($request): void { + $this->resolveFields($request)->registerRoutes($request, $router); + }); + } + + /** + * Register the routes. + */ + public function routes(Router $router): void + { + // + } + /** * Get the option representation of the model and the related model. */ @@ -321,4 +403,28 @@ public function toInput(Request $request, Model $model): array 'options' => $this->resolveOptions($request, $model), ]); } + + /** + * Get the index representation of the relation. + */ + public function toIndex(Request $request, Model $model): array + { + return array_merge($this->toArray(), [ + 'title' => $this->getRelatedName(), + 'actions' => $this->resolveActions($request) + ->authorized($request, $model) + ->visible('index') + ->mapToForms($request, $model), + 'data' => $this->paginate($request, $model), + 'perPageOptions' => $this->getPerPageOptions(), + 'filters' => $this->resolveFilters($request) + ->authorized($request) + ->renderable() + ->map(static function (RenderableFilter $filter) use ($request, $model): array { + return $filter->toField()->toInput($request, $model); + }) + ->all(), + 'activeFilters' => $this->resolveFilters($request)->active($request)->count(), + ]); + } } diff --git a/src/Interfaces/Table.php b/src/Interfaces/Table.php deleted file mode 100644 index 086a9719..00000000 --- a/src/Interfaces/Table.php +++ /dev/null @@ -1,19 +0,0 @@ - $this->modelUrl($model), 'model' => $model, 'fields' => $this->resolveFields($request) + ->subResource(false) ->authorized($request, $model) ->visible('index') ->mapToDisplay($request, $model), @@ -365,6 +366,7 @@ public function toCreate(Request $request): array 'action' => $this->getUri(), 'method' => 'POST', 'fields' => $this->resolveFields($request) + ->subResource(false) ->authorized($request, $model) ->visible('create') ->mapToInputs($request, $model), @@ -382,6 +384,7 @@ public function toShow(Request $request, Model $model): array 'action' => $this->modelUrl($model), 'method' => 'PATCH', 'fields' => $this->resolveFields($request) + ->subResource(false) ->authorized($request, $model) ->visible('show') ->mapToDisplay($request, $model), @@ -393,6 +396,12 @@ public function toShow(Request $request, Model $model): array ->authorized($request, $model) ->visible('show') ->toArray(), + 'relations' => $this->resolveFields($request) + ->subResource() + ->authorized($request, $model) + ->map(static function (Relation $relation) use ($request, $model): array { + return $relation->toIndex($request, $model); + }), ]); } @@ -407,6 +416,7 @@ public function toEdit(Request $request, Model $model): array 'action' => $this->modelUrl($model), 'method' => 'PATCH', 'fields' => $this->resolveFields($request) + ->subResource(false) ->authorized($request, $model) ->visible('update') ->mapToInputs($request, $model), diff --git a/src/Traits/ResolvesActions.php b/src/Traits/ResolvesActions.php index cc42b1d9..30e8fcd8 100644 --- a/src/Traits/ResolvesActions.php +++ b/src/Traits/ResolvesActions.php @@ -2,9 +2,11 @@ namespace Cone\Root\Traits; +use Closure; use Cone\Root\Actions\Action; use Cone\Root\Actions\Actions; use Illuminate\Http\Request; +use Illuminate\Support\Arr; trait ResolvesActions { @@ -13,6 +15,11 @@ trait ResolvesActions */ protected ?Actions $actions = null; + /** + * The actions resolver callback. + */ + protected ?Closure $actionsResolver = null; + /** * Define the actions for the object. */ @@ -21,6 +28,16 @@ public function actions(Request $request): array return []; } + /** + * Set the actions resolver callback. + */ + public function withActions(Closure $callback): static + { + $this->actionsResolver = $callback; + + return $this; + } + /** * Resolve the actions collection. */ @@ -29,6 +46,12 @@ public function resolveActions(Request $request): Actions if (is_null($this->actions)) { $this->actions = new Actions($this->actions($request)); + $this->actions->when(! is_null($this->actionsResolver), function (Actions $actions) use ($request): void { + $actions->register( + Arr::wrap(call_user_func_array($this->actionsResolver, [$request])) + ); + }); + $this->actions->each(function (Action $action) use ($request): void { $this->resolveAction($request, $action); }); diff --git a/src/Traits/ResolvesFields.php b/src/Traits/ResolvesFields.php index d1fb8fd8..a7666593 100644 --- a/src/Traits/ResolvesFields.php +++ b/src/Traits/ResolvesFields.php @@ -46,11 +46,11 @@ public function resolveFields(Request $request): Fields if (is_null($this->fields)) { $this->fields = new Fields($this->fields($request)); - if (! is_null($this->fieldsResolver)) { - $this->fields->register( + $this->fields->when(! is_null($this->fieldsResolver), function (Fields $fields) use ($request): void { + $fields->register( Arr::wrap(call_user_func_array($this->fieldsResolver, [$request])) ); - } + }); $this->fields->each(function (Field $field) use ($request): void { $this->resolveField($request, $field); diff --git a/src/Traits/ResolvesFilters.php b/src/Traits/ResolvesFilters.php index c247b39f..78639cc6 100644 --- a/src/Traits/ResolvesFilters.php +++ b/src/Traits/ResolvesFilters.php @@ -2,6 +2,7 @@ namespace Cone\Root\Traits; +use Closure; use Cone\Root\Fields\Fields; use Cone\Root\Filters\Filter; use Cone\Root\Filters\Filters; @@ -10,6 +11,7 @@ use Cone\Root\Filters\TrashStatus; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Http\Request; +use Illuminate\Support\Arr; trait ResolvesFilters { @@ -18,6 +20,11 @@ trait ResolvesFilters */ protected ?Filters $filters = null; + /** + * The filters resolver callback. + */ + protected ?Closure $filtersResolver = null; + /** * Define the filters for the object. */ @@ -28,6 +35,16 @@ public function filters(Request $request): array ]; } + /** + * Set the filters resolver callback. + */ + public function withFilters(Closure $callback): static + { + $this->filtersResolver = $callback; + + return $this; + } + /** * Resolve the filters collection. */ @@ -42,6 +59,12 @@ public function resolveFilters(Request $request): Filters $this->filters->prepend(new Search($fields)); }); + $this->filters->when(! is_null($this->filtersResolver), function (Filters $filters) use ($request): void { + $filters->register( + Arr::wrap(call_user_func_array($this->filtersResolver, [$request])) + ); + }); + $this->resolveFields($request) ->sortable() ->whenNotEmpty(function (Fields $fields): void {