Skip to content

Commit a60acba

Browse files
committed
Update package
0 parents  commit a60acba

File tree

8 files changed

+1240
-0
lines changed

8 files changed

+1240
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/vendor

composer.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "marsflow/cached-datatable",
3+
"description": "Yajra datatable with cache",
4+
"authors": [
5+
{
6+
"name": "Stevan Aji",
7+
"email": "[email protected]"
8+
}
9+
],
10+
"minimum-stability": "dev",
11+
"extra": {
12+
"laravel": {
13+
"providers": [
14+
"marsflow\\cached-datatable\\CachedDataTableServiceProvider"
15+
]
16+
}
17+
},
18+
"autoload": {
19+
"psr-4": {
20+
"Marsflow\\CachedDataTable\\": "src/"
21+
}
22+
},
23+
"require": {}
24+
}

src/CachedDataTable.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Marsflow\CachedDataTable;
4+
5+
use Marsflow\CachedDataTable\CachedDataTableAbstract;
6+
use Marsflow\CachedDataTable\CachedEloquentDataTable;
7+
use Marsflow\CachedDataTable\CachedQueryDataTable;
8+
use Yajra\DataTables\DataTables;
9+
10+
class CachedDataTable extends DataTables
11+
{
12+
13+
/**
14+
* DataTables using Query.
15+
*
16+
* @param \Illuminate\Database\Query\Builder|mixed $builder
17+
* @return DataTableAbstract|QueryDataTable
18+
*/
19+
public function query($builder)
20+
{
21+
return CachedQueryDataTable::create($builder);
22+
}
23+
24+
/**
25+
* DataTables using Eloquent Builder.
26+
*
27+
* @param \Illuminate\Database\Eloquent\Builder|mixed $builder
28+
* @return DataTableAbstract|EloquentDataTable
29+
*/
30+
public function eloquent($builder)
31+
{
32+
return CachedEloquentDataTable::create($builder);
33+
}
34+
35+
}

src/CachedDataTableAbstract.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Marsflow\CachedDataTable;
4+
5+
use Yajra\DataTables\DataTableAbstract;
6+
7+
abstract class CachedDataTableAbstract extends DataTableAbstract
8+
{
9+
10+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
namespace Marsflow\CachedDataTable;
4+
5+
use Yajra\DataTables\DataTablesServiceProvider;
6+
use Yajra\DataTables\Utilities\Config;
7+
use Yajra\DataTables\Utilities\Request;
8+
use Illuminate\Support\Str;
9+
10+
use Marsflow\CachedDataTable\CachedDataTable;
11+
12+
class CachedDataTableServiceProvider extends DataTablesServiceProvider
13+
{
14+
15+
/**
16+
* Register the service provider.
17+
*
18+
* @return void
19+
*/
20+
public function register()
21+
{
22+
if ($this->isLumen()) {
23+
require_once 'lumen.php';
24+
}
25+
26+
$this->setupAssets();
27+
28+
$this->app->alias('datatables', CachedDataTable::class);
29+
$this->app->singleton('datatables', function () {
30+
return new CachedDataTable;
31+
});
32+
33+
$this->app->singleton('datatables.request', function () {
34+
return new Request;
35+
});
36+
37+
$this->app->singleton('datatables.config', Config::class);
38+
}
39+
40+
/**
41+
* Boot the instance, add macros for datatable engines.
42+
*
43+
* @return void
44+
*/
45+
public function boot()
46+
{
47+
$engines = (array) config('datatables.engines');
48+
foreach ($engines as $engine => $class) {
49+
$engine = Str::camel($engine);
50+
51+
if (! method_exists(DataTables::class, $engine) && ! CachedDataTable::hasMacro($engine)) {
52+
CachedDataTable::macro($engine, function () use ($class) {
53+
if (! call_user_func_array([$class, 'canCreate'], func_get_args())) {
54+
throw new \InvalidArgumentException();
55+
}
56+
57+
return call_user_func_array([$class, 'create'], func_get_args());
58+
});
59+
}
60+
}
61+
}
62+
63+
}

src/CachedEloquentDataTable.php

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
<?php
2+
3+
namespace Marsflow\CachedDataTable;
4+
5+
use Marsflow\CachedDataTable\CachedQueryDataTable;
6+
7+
use Illuminate\Database\Eloquent\Builder;
8+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
9+
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
10+
use Illuminate\Database\Eloquent\Relations\HasOneOrMany;
11+
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
12+
use Illuminate\Database\Eloquent\Relations\MorphTo;
13+
use Illuminate\Database\Eloquent\Relations\Relation;
14+
use Yajra\DataTables\Exceptions\Exception;
15+
use Yajra\DataTables\QueryDataTable;
16+
17+
class CachedEloquentDataTable extends CachedQueryDataTable
18+
{
19+
20+
/**
21+
* @var \Illuminate\Database\Eloquent\Builder
22+
*/
23+
protected $query;
24+
25+
/**
26+
* Can the DataTable engine be created with these parameters.
27+
*
28+
* @param mixed $source
29+
* @return bool
30+
*/
31+
public static function canCreate($source)
32+
{
33+
return $source instanceof Builder || $source instanceof Relation;
34+
}
35+
36+
/**
37+
* EloquentEngine constructor.
38+
*
39+
* @param mixed $model
40+
*/
41+
public function __construct($model)
42+
{
43+
$builder = $model instanceof Builder ? $model : $model->getQuery();
44+
parent::__construct($builder->getQuery());
45+
46+
$this->query = $builder;
47+
}
48+
49+
/**
50+
* Add columns in collection.
51+
*
52+
* @param array $names
53+
* @param bool|int $order
54+
* @return $this
55+
*/
56+
public function addColumns(array $names, $order = false)
57+
{
58+
foreach ($names as $name => $attribute) {
59+
if (is_int($name)) {
60+
$name = $attribute;
61+
}
62+
63+
$this->addColumn($name, function ($model) use ($attribute) {
64+
return $model->getAttribute($attribute);
65+
}, is_int($order) ? $order++ : $order);
66+
}
67+
68+
return $this;
69+
}
70+
71+
/**
72+
* If column name could not be resolved then use primary key.
73+
*
74+
* @return string
75+
*/
76+
protected function getPrimaryKeyName()
77+
{
78+
return $this->query->getModel()->getKeyName();
79+
}
80+
81+
/**
82+
* Compile query builder where clause depending on configurations.
83+
*
84+
* @param mixed $query
85+
* @param string $columnName
86+
* @param string $keyword
87+
* @param string $boolean
88+
*/
89+
protected function compileQuerySearch($query, $columnName, $keyword, $boolean = 'or')
90+
{
91+
$parts = explode('.', $columnName);
92+
$column = array_pop($parts);
93+
$relation = implode('.', $parts);
94+
95+
if ($this->isNotEagerLoaded($relation)) {
96+
return parent::compileQuerySearch($query, $columnName, $keyword, $boolean);
97+
}
98+
99+
if ($this->isMorphRelation($relation)) {
100+
$query->{$boolean . 'WhereHasMorph'}($relation, '*', function (Builder $query) use ($column, $keyword) {
101+
parent::compileQuerySearch($query, $column, $keyword, '');
102+
});
103+
} else {
104+
$query->{$boolean . 'WhereHas'}($relation, function (Builder $query) use ($column, $keyword) {
105+
parent::compileQuerySearch($query, $column, $keyword, '');
106+
});
107+
}
108+
}
109+
110+
/**
111+
* Resolve the proper column name be used.
112+
*
113+
* @param string $column
114+
* @return string
115+
*/
116+
protected function resolveRelationColumn($column)
117+
{
118+
$parts = explode('.', $column);
119+
$columnName = array_pop($parts);
120+
$relation = implode('.', $parts);
121+
122+
if ($this->isNotEagerLoaded($relation)) {
123+
return $column;
124+
}
125+
126+
return $this->joinEagerLoadedColumn($relation, $columnName);
127+
}
128+
129+
/**
130+
* Check if a relation is a morphed one or not.
131+
*
132+
* @param string $relation
133+
* @return bool
134+
*/
135+
protected function isMorphRelation($relation)
136+
{
137+
$isMorph = false;
138+
if ($relation !== null && $relation !== '') {
139+
$relationParts = explode('.', $relation);
140+
$firstRelation = array_shift($relationParts);
141+
$model = $this->query->getModel();
142+
$isMorph = method_exists($model, $firstRelation) && $model->$firstRelation() instanceof MorphTo;
143+
}
144+
145+
return $isMorph;
146+
}
147+
148+
/**
149+
* Check if a relation was not used on eager loading.
150+
*
151+
* @param string $relation
152+
* @return bool
153+
*/
154+
protected function isNotEagerLoaded($relation)
155+
{
156+
return ! $relation
157+
|| ! array_key_exists($relation, $this->query->getEagerLoads())
158+
|| $relation === $this->query->getModel()->getTable();
159+
}
160+
161+
/**
162+
* Join eager loaded relation and get the related column name.
163+
*
164+
* @param string $relation
165+
* @param string $relationColumn
166+
* @return string
167+
* @throws \Yajra\DataTables\Exceptions\Exception
168+
*/
169+
protected function joinEagerLoadedColumn($relation, $relationColumn)
170+
{
171+
$table = '';
172+
$lastQuery = $this->query;
173+
foreach (explode('.', $relation) as $eachRelation) {
174+
$model = $lastQuery->getRelation($eachRelation);
175+
switch (true) {
176+
case $model instanceof BelongsToMany:
177+
$pivot = $model->getTable();
178+
$pivotPK = $model->getExistenceCompareKey();
179+
$pivotFK = $model->getQualifiedParentKeyName();
180+
$this->performJoin($pivot, $pivotPK, $pivotFK);
181+
182+
$related = $model->getRelated();
183+
$table = $related->getTable();
184+
$tablePK = $related->getForeignKey();
185+
$foreign = $pivot . '.' . $tablePK;
186+
$other = $related->getQualifiedKeyName();
187+
188+
$lastQuery->addSelect($table . '.' . $relationColumn);
189+
$this->performJoin($table, $foreign, $other);
190+
191+
break;
192+
193+
case $model instanceof HasOneThrough:
194+
$pivot = explode('.', $model->getQualifiedParentKeyName())[0]; // extract pivot table from key
195+
$pivotPK = $pivot . '.' . $model->getLocalKeyName();
196+
$pivotFK = $model->getQualifiedLocalKeyName();
197+
$this->performJoin($pivot, $pivotPK, $pivotFK);
198+
199+
$related = $model->getRelated();
200+
$table = $related->getTable();
201+
$tablePK = $related->getForeignKey();
202+
$foreign = $pivot . '.' . $tablePK;
203+
$other = $related->getQualifiedKeyName();
204+
205+
break;
206+
207+
case $model instanceof HasOneOrMany:
208+
$table = $model->getRelated()->getTable();
209+
$foreign = $model->getQualifiedForeignKeyName();
210+
$other = $model->getQualifiedParentKeyName();
211+
break;
212+
213+
case $model instanceof BelongsTo:
214+
$table = $model->getRelated()->getTable();
215+
$foreign = $model->getQualifiedForeignKeyName();
216+
$other = $model->getQualifiedOwnerKeyName();
217+
break;
218+
219+
default:
220+
throw new Exception('Relation ' . get_class($model) . ' is not yet supported.');
221+
}
222+
$this->performJoin($table, $foreign, $other);
223+
$lastQuery = $model->getQuery();
224+
}
225+
226+
return $table . '.' . $relationColumn;
227+
}
228+
229+
/**
230+
* Perform join query.
231+
*
232+
* @param string $table
233+
* @param string $foreign
234+
* @param string $other
235+
* @param string $type
236+
*/
237+
protected function performJoin($table, $foreign, $other, $type = 'left')
238+
{
239+
$joins = [];
240+
foreach ((array) $this->getBaseQueryBuilder()->joins as $key => $join) {
241+
$joins[] = $join->table;
242+
}
243+
244+
if (! in_array($table, $joins)) {
245+
$this->getBaseQueryBuilder()->join($table, $foreign, '=', $other, $type);
246+
}
247+
}
248+
}

0 commit comments

Comments
 (0)