Skip to content

List un hydrated #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
76 changes: 75 additions & 1 deletion src/Eloquent/CustomRelations/Builders/CleverEloquentBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,26 @@

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;

/**
* @method Model createHydrated(array $attributes = [])
*/
class CleverEloquentBuilder extends Builder
{
protected bool $getUnHydrated = false;

/**
* @inheritDoc
*/
Expand All @@ -41,6 +48,73 @@ 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 = $total !== null ?
$this->paginate($perPage, $columns, $pageName, $page, $total) :
$this->paginate($perPage, $columns, $pageName, $page);
$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
*/
Expand Down Expand Up @@ -100,4 +174,4 @@ public function with($relations, $callback = null): static

return $this;
}
}
}
38 changes: 38 additions & 0 deletions src/Http/Controllers/ResourceControllerTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -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() ?? $model);
$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,
['*'],
Expand All @@ -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,
['*'],
Expand Down
11 changes: 7 additions & 4 deletions src/Models/BaseModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()
));
Expand Down Expand Up @@ -242,7 +245,7 @@ function () use ($driver): array {
Carbon::now()->addDay(),
$callback
));
} catch (\Throwable $e) {
} catch (\Throwable) {
return \collect($callback());
}
}
Expand Down Expand Up @@ -364,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);
}
}
Expand Down