From 8460a17ef7430b0e85dbeb3b7f444301156f011b Mon Sep 17 00:00:00 2001 From: Admin <> Date: Fri, 13 Jun 2025 19:52:12 +0300 Subject: [PATCH 1/6] Add list un hydrated feature --- README.md | 2 + .../Builders/CleverEloquentBuilder.php | 74 ++++++++++++++++++- .../Controllers/ResourceControllerTrait.php | 38 ++++++++++ src/Models/BaseModel.php | 7 +- 4 files changed, 118 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d606f01..cde9c71 100644 --- a/README.md +++ b/README.md @@ -293,6 +293,8 @@ OBS Set `$returnNullOnInvalidColumnAttributeAccess = false;` in model if you want exception instead of null on accessing invalid model attributes or invalid relations (It also needs error_reporting = E_ALL in php ini file). +Set `LIST_UN_HYDRATED_WHEN_POSSIBLE = true` in model if you want to skip eloquent hydration for list db query results; note that setting this to true will not append the primary_key_identifier on response. + Set LIVE_MODE=false in your .env file for non prod environments. Use Request::getFiltered macro to sanitize data retrieved from request diff --git a/src/Eloquent/CustomRelations/Builders/CleverEloquentBuilder.php b/src/Eloquent/CustomRelations/Builders/CleverEloquentBuilder.php index b69ba72..c24f090 100644 --- a/src/Eloquent/CustomRelations/Builders/CleverEloquentBuilder.php +++ b/src/Eloquent/CustomRelations/Builders/CleverEloquentBuilder.php @@ -2,12 +2,17 @@ namespace MacropaySolutions\LaravelCrudWizard\Eloquent\CustomRelations\Builders; +use Illuminate\Contracts\Pagination\CursorPaginator; +use Illuminate\Contracts\Pagination\Paginator; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\RelationNotFoundException; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\Relation; +use Illuminate\Pagination\Cursor; +use Illuminate\Pagination\LengthAwarePaginator; +use Illuminate\Support\Collection; use MacropaySolutions\LaravelCrudWizard\Models\BaseModel; /** @@ -15,6 +20,8 @@ */ class CleverEloquentBuilder extends Builder { + protected bool $getUnHydrated = false; + /** * @inheritDoc */ @@ -41,6 +48,71 @@ public function getRelation($name): Relation return $relation; } + /** + * @throws \Throwable + */ + public function getUnHydrated(array|string $columns = ['*']): Collection + { + return $this->toBase()->get($columns); + } + + /** + * @throws \Throwable + */ + public function paginateUnHydrated( + int|null|\Closure $perPage = null, + array|string $columns = ['*'], + string $pageName = 'page', + int|null $page = null, + int|null|\Closure $total = null, + ): LengthAwarePaginator { + $this->getUnHydrated = true; + $result = $this->paginate($perPage, $columns, $pageName, $page, $total); + $this->getUnHydrated = false; + + return $result; + } + + /** + * @throws \Throwable + */ + public function simplePaginateUnHydrated( + int|null $perPage = null, + array $columns = ['*'], + string $pageName = 'page', + int|null $page = null + ): Paginator { + $this->getUnHydrated = true; + $result = $this->simplePaginate($perPage, $columns, $pageName, $page); + $this->getUnHydrated = false; + + return $result; + } + + /** + * @throws \Throwable + */ + public function cursorPaginateUnHydrated( + int|null $perPage = null, + array|string $columns = ['*'], + string $cursorName = 'cursor', + Cursor|string|null $cursor = null + ): CursorPaginator { + $this->getUnHydrated = true; + $result = $this->cursorPaginate($perPage, $columns, $cursorName, $cursor); + $this->getUnHydrated = false; + + return $result; + } + + /** + * @inheritdoc + */ + public function get($columns = ['*']): \Illuminate\Database\Eloquent\Collection|array|Collection + { + return $this->getUnHydrated ? $this->getUnHydrated($columns) : parent::get($columns); + } + /** * @inheritDoc */ @@ -100,4 +172,4 @@ public function with($relations, $callback = null): static return $this; } -} \ No newline at end of file +} diff --git a/src/Http/Controllers/ResourceControllerTrait.php b/src/Http/Controllers/ResourceControllerTrait.php index 8d43d9a..48422d1 100644 --- a/src/Http/Controllers/ResourceControllerTrait.php +++ b/src/Http/Controllers/ResourceControllerTrait.php @@ -435,8 +435,28 @@ protected function getPaginator( ): LengthAwarePaginator | Paginator | CursorPaginator { $model = $builder instanceof Relation ? $builder->getRelated() : $builder->getModel(); $limit = \max(1, (int)($allRequest['limit'] ?? $model->getPerPage())); + $listUnHydrated = false; + + if ($model::LIST_UN_HYDRATED_WHEN_POSSIBLE) { + /** @var BaseModel $first */ + $first = $model->exists() ? $model : $model::query()->first(); + $listUnHydrated = $builder->getEagerLoads() === [] + && \array_diff_key( + $first->attributesToArray(), + ['primary_key_identifier' => null] + ) === $first->getRawOriginal(); + } if (isset($allRequest['cursor'])) { + if ($listUnHydrated) { + return $builder->cursorPaginateUnHydrated( + $limit, + ['*'], + 'cursor', + $allRequest['cursor'] + ); + } + return $builder->cursorPaginate( $limit, ['*'], @@ -445,6 +465,24 @@ protected function getPaginator( ); } + if ($listUnHydrated) { + if ($this->simplePaginate) { + return $builder->simplePaginateUnHydrated( + $limit, + ['*'], + 'page', + \max((int)($allRequest['page'] ?? 1), 1) + ); + } + + return $builder->paginateUnHydrated( + $limit, + ['*'], + 'page', + \max((int)($allRequest['page'] ?? 1), 1) + ); + } + return $builder->{$this->simplePaginate ? 'simplePaginate' : 'paginate'}( $limit, ['*'], diff --git a/src/Models/BaseModel.php b/src/Models/BaseModel.php index 3c31e74..e1a6266 100644 --- a/src/Models/BaseModel.php +++ b/src/Models/BaseModel.php @@ -28,6 +28,10 @@ abstract class BaseModel extends Model public const CREATED_AT_FORMAT = 'Y-m-d H:i:s'; public const UPDATED_AT_FORMAT = 'Y-m-d H:i:s'; public const COMPOSITE_PK_SEPARATOR = '_'; + /** + * Setting this to true will not append the primary_key_identifier on response + */ + public const LIST_UN_HYDRATED_WHEN_POSSIBLE = false; public $timestamps = false; public static $snakeAttributes = false; public BaseModelAttributes $a; @@ -110,8 +114,7 @@ public function getIndexRequiredOnFilteringAttribute(): array */ public function getPrimaryKeyIdentifierAttribute(): string { - return \implode( - $this::COMPOSITE_PK_SEPARATOR, \array_map( + return \implode($this::COMPOSITE_PK_SEPARATOR, \array_map( fn (mixed $value): string => (string)(\is_array($value) ? \last($value) : $value), $this->getPrimaryKeyFilter() )); From 8a18c9cc55632de0d11ea79bd251d7dc33f9b020 Mon Sep 17 00:00:00 2001 From: Admin <> Date: Fri, 13 Jun 2025 19:54:38 +0300 Subject: [PATCH 2/6] Add list un hydrated feature --- src/Models/BaseModel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Models/BaseModel.php b/src/Models/BaseModel.php index e1a6266..4f9c013 100644 --- a/src/Models/BaseModel.php +++ b/src/Models/BaseModel.php @@ -245,7 +245,7 @@ function () use ($driver): array { Carbon::now()->addDay(), $callback )); - } catch (\Throwable $e) { + } catch (\Throwable) { return \collect($callback()); } } @@ -367,7 +367,7 @@ public function getAttributeValue($key): mixed if (!$this->hasGetMutator($key) && !$this->hasAttributeGetMutator($key)) { try { return $this->attributes[$key]; - } catch (\Throwable $e) { + } catch (\Throwable) { throw new \Exception('Undefined attribute: ' . $key . ' in model: ' . static::class); } } From 55deef284c673f4916daad3ac13ca57f934fb691 Mon Sep 17 00:00:00 2001 From: Admin <> Date: Fri, 13 Jun 2025 21:21:55 +0300 Subject: [PATCH 3/6] Add list un hydrated feature --- src/Http/Controllers/ResourceControllerTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Controllers/ResourceControllerTrait.php b/src/Http/Controllers/ResourceControllerTrait.php index 48422d1..4e84a49 100644 --- a/src/Http/Controllers/ResourceControllerTrait.php +++ b/src/Http/Controllers/ResourceControllerTrait.php @@ -439,7 +439,7 @@ protected function getPaginator( if ($model::LIST_UN_HYDRATED_WHEN_POSSIBLE) { /** @var BaseModel $first */ - $first = $model->exists() ? $model : $model::query()->first(); + $first = $model->exists() ? $model : $model::query()->firstOrNew(); $listUnHydrated = $builder->getEagerLoads() === [] && \array_diff_key( $first->attributesToArray(), From 40b802a6101894d65d9e3b8f51a42beb9be7626b Mon Sep 17 00:00:00 2001 From: Admin <> Date: Fri, 13 Jun 2025 21:22:32 +0300 Subject: [PATCH 4/6] Add list un hydrated feature --- src/Http/Controllers/ResourceControllerTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Controllers/ResourceControllerTrait.php b/src/Http/Controllers/ResourceControllerTrait.php index 4e84a49..db1f24b 100644 --- a/src/Http/Controllers/ResourceControllerTrait.php +++ b/src/Http/Controllers/ResourceControllerTrait.php @@ -439,7 +439,7 @@ protected function getPaginator( if ($model::LIST_UN_HYDRATED_WHEN_POSSIBLE) { /** @var BaseModel $first */ - $first = $model->exists() ? $model : $model::query()->firstOrNew(); + $first = $model->exists() ? $model : ($model::query()->first() ?? $model); $listUnHydrated = $builder->getEagerLoads() === [] && \array_diff_key( $first->attributesToArray(), From 9acd9939909a84c49738561b91a536d9aa4f82ae Mon Sep 17 00:00:00 2001 From: Admin <> Date: Sat, 14 Jun 2025 08:57:35 +0300 Subject: [PATCH 5/6] Add list un hydrated feature --- src/Http/Controllers/ResourceControllerTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Controllers/ResourceControllerTrait.php b/src/Http/Controllers/ResourceControllerTrait.php index db1f24b..fc5d253 100644 --- a/src/Http/Controllers/ResourceControllerTrait.php +++ b/src/Http/Controllers/ResourceControllerTrait.php @@ -439,7 +439,7 @@ protected function getPaginator( if ($model::LIST_UN_HYDRATED_WHEN_POSSIBLE) { /** @var BaseModel $first */ - $first = $model->exists() ? $model : ($model::query()->first() ?? $model); + $first = $model->exists ? $model : ($model::query()->first() ?? $model); $listUnHydrated = $builder->getEagerLoads() === [] && \array_diff_key( $first->attributesToArray(), From d595ca0bb8ec54be9b5ddc91a74a1045909740e2 Mon Sep 17 00:00:00 2001 From: Admin <> Date: Sat, 14 Jun 2025 10:38:46 +0300 Subject: [PATCH 6/6] Add list un hydrated feature avoid L 10 builder:paginate bug --- .../CustomRelations/Builders/CleverEloquentBuilder.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Eloquent/CustomRelations/Builders/CleverEloquentBuilder.php b/src/Eloquent/CustomRelations/Builders/CleverEloquentBuilder.php index c24f090..7c644ae 100644 --- a/src/Eloquent/CustomRelations/Builders/CleverEloquentBuilder.php +++ b/src/Eloquent/CustomRelations/Builders/CleverEloquentBuilder.php @@ -67,7 +67,9 @@ public function paginateUnHydrated( int|null|\Closure $total = null, ): LengthAwarePaginator { $this->getUnHydrated = true; - $result = $this->paginate($perPage, $columns, $pageName, $page, $total); + $result = $total !== null ? + $this->paginate($perPage, $columns, $pageName, $page, $total) : + $this->paginate($perPage, $columns, $pageName, $page); $this->getUnHydrated = false; return $result;