Skip to content

Commit 242374f

Browse files
committed
Datatables : Ability to Map/Transform Resources
Datatables : Ability to Have closures Resolving Query, Fields on Transform and Also Datatables : Abitlity to have HasMany relations & Fixed issues with Relationships Loading
1 parent 6e25b8c commit 242374f

File tree

7 files changed

+90
-15
lines changed

7 files changed

+90
-15
lines changed

src/Datatables/Columns/Column.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Column implements CoreContracts\HasToArray
1515
use Concerns\CanBeHidden;
1616
use Concerns\CanBeSortable;
1717
use Concerns\CanBeRaw;
18+
use Concerns\CanBeSelected;
1819
use Concerns\HasLabel;
1920
use Concerns\HasName;
2021
use Concerns\HasKey;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Flavorly\VanillaComponents\Datatables\Columns\Concerns;
4+
5+
use Illuminate\Support\Str;
6+
7+
trait CanBeSelected
8+
{
9+
public function selectable(): bool
10+
{
11+
return ! Str::of($this->getName())->contains('.');
12+
}
13+
}

src/Datatables/Concerns/HasColumns.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,11 @@ protected function getColumns(): Collection
4545

4646
protected function getColumnKeys(): Collection
4747
{
48-
return collect($this->columns)->map(fn ($column) => $column->getName());
48+
return collect($this->columns)
49+
->filter(fn (Column $column) => $column->selectable())
50+
->map(function (Column $column) {
51+
return $column->getName();
52+
});
4953
}
5054

5155
public function getColumnByKey(string $columnKey): ?Column

src/Datatables/Concerns/HasPrimaryKey.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ trait HasPrimaryKey
88

99
public function primaryKey(): ?string
1010
{
11-
return $this->query?->getModel()->getKeyName();
11+
return $this->getQuery()?->getModel()->getKeyName();
1212
}
1313

1414
public function setupPrimaryKey(): void
@@ -18,6 +18,6 @@ public function setupPrimaryKey(): void
1818

1919
public function getPrimaryKey(): string
2020
{
21-
return $this->primaryKey ?? $this->query?->getModel()->getKeyName() ?? 'id';
21+
return $this->primaryKey ?? $this->primaryKey() ?? 'id';
2222
}
2323
}

src/Datatables/Concerns/HasResponse.php

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ public function response(?Builder $queryOrModel = null): DatatableResource
3535
->fromRequest();
3636

3737
// Attempt to always get a query builder
38-
$baseQuery = $this->resolveQueryOrModel($queryOrModel);
38+
if ($queryOrModel !== null) {
39+
$this->withQuery($queryOrModel);
40+
}
41+
42+
$baseQuery = $this->getQuery();
3943

4044
/** @var Model|Searchable $model */
4145
$model = $baseQuery->getModel();
@@ -49,10 +53,12 @@ public function response(?Builder $queryOrModel = null): DatatableResource
4953
function (Builder $query) use ($baseQuery) {
5054
$query
5155
// Select columns
52-
->select($this->getColumnKeys()->toArray())
56+
// TODO: check if we can resolve columns to select in a smarter way
57+
//->select($this->getColumnKeys()->toArray())
5358

5459
// Merge previous query
5560
->mergeConstraintsFrom($baseQuery)
61+
->setEagerLoads($baseQuery->getEagerLoads())
5662

5763
// Perform sorting
5864
->when($this->data->hasSorting(), function (Builder|ScoutBuilder $subQuery) {
@@ -100,6 +106,19 @@ function (Builder $query) use ($baseQuery) {
100106
// Dispatch the action
101107
$this->dispatchAction();
102108

103-
return (new DatatableResource($paginator))->rightSideMaximumPages(3);
109+
$response = (new DatatableResource($paginator));
110+
111+
// Ensure we can transform the data that is being displayed
112+
if (method_exists($this, 'transform')) {
113+
$response->transformResponseUsing(fn ($record) => $this->transform($record));
114+
}
115+
116+
// Ensure we can transform the data that is being displayed
117+
$pagination = 3;
118+
if (property_exists($this, 'paginationItems')) {
119+
$pagination = $this->paginationItems;
120+
}
121+
122+
return $response->rightSideMaximumPages($pagination);
104123
}
105124
}

src/Datatables/Concerns/InteractsWithQueryBuilder.php

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,42 @@
44

55
use Closure;
66
use Illuminate\Database\Eloquent\Builder;
7-
use Illuminate\Database\Eloquent\Model;
7+
use Illuminate\Database\Eloquent\Relations\Relation;
88
use Laravel\Scout\Builder as ScoutBuilder;
99

1010
trait InteractsWithQueryBuilder
1111
{
12-
protected Builder|ScoutBuilder|null $query = null;
12+
protected Builder|ScoutBuilder|null|Closure $query = null;
1313

14-
public function query(): Builder|ScoutBuilder|null
14+
public function query(): mixed
15+
{
16+
return $this->query;
17+
}
18+
19+
public function getQuery()
1520
{
1621
return $this->query;
1722
}
1823

1924
public function setupQuery(): void
2025
{
21-
$this->query = $this->query();
26+
$this->query = $this->resolveQueryOrModel($this->query());
2227
}
2328

24-
protected function resolveQueryOrModel(Builder|Model|string|Closure|null $queryOrModel = null): Builder
29+
public function withQuery(mixed $query)
2530
{
26-
// Query already present or set
27-
if (null !== $this->query && $queryOrModel === null) {
28-
return $this->query;
31+
if (null === $query) {
32+
return $this;
2933
}
34+
$this->query = $this->resolveQueryOrModel($query);
35+
36+
$this->setupPrimaryKey();
3037

38+
return $this;
39+
}
40+
41+
protected function resolveQueryOrModel(mixed $queryOrModel = null): Builder
42+
{
3143
// If the user has not provided a query or passed a string ( class ) we will try to
3244
// get the query from the model
3345
if (is_string($queryOrModel)) {
@@ -38,6 +50,10 @@ protected function resolveQueryOrModel(Builder|Model|string|Closure|null $queryO
3850
$queryOrModel = $this->evaluate($queryOrModel);
3951
}
4052

53+
if ($queryOrModel instanceof Relation) {
54+
return $queryOrModel->getQuery();
55+
}
56+
4157
// Attempt to always get a query builder
4258
return $queryOrModel instanceof Builder ? $queryOrModel : $queryOrModel->query();
4359
}

src/Datatables/Http/Resources/DatatableResource.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Flavorly\VanillaComponents\Datatables\Http\Resources;
44

5+
use Closure;
56
use Flavorly\VanillaComponents\Core\Concerns\InteractsWithPagination;
67
use Flavorly\VanillaComponents\Datatables\Paginator\PaginatedResourceResponse;
78
use Illuminate\Http\Resources\Json\ResourceCollection;
@@ -10,13 +11,34 @@ class DatatableResource extends ResourceCollection
1011
{
1112
use InteractsWithPagination;
1213

13-
public function toArray($request)
14+
protected ?Closure $transformUsing = null;
15+
16+
public function toArray($request): array
1417
{
18+
if (null !== $this->transformUsing) {
19+
$this->collection = $this
20+
->collection
21+
->map($this->transformUsing)
22+
->map(function ($item) {
23+
return collect($item)->map(function ($value, $key) {
24+
return $value instanceof Closure ? $value() : $value;
25+
})
26+
->toArray();
27+
});
28+
}
29+
1530
return [
1631
'data' => $this->collection,
1732
];
1833
}
1934

35+
public function transformResponseUsing(Closure $callback)
36+
{
37+
$this->transformUsing = $callback;
38+
39+
return $this;
40+
}
41+
2042
protected function preparePaginatedResponse($request)
2143
{
2244
if ($this->preserveAllQueryParameters) {

0 commit comments

Comments
 (0)