|
1
|
|
|
<?php namespace App\Modules\V1\Core\AbstractRepositories; |
|
2
|
|
|
|
|
3
|
|
|
use App\Modules\V1\Core\Interfaces\RepositoryInterface; |
|
4
|
|
|
|
|
5
|
|
|
abstract class AbstractRepository implements RepositoryInterface |
|
6
|
|
|
{ |
|
7
|
|
|
/** |
|
8
|
|
|
* The model implementation. |
|
9
|
|
|
* |
|
10
|
|
|
* @var model |
|
11
|
|
|
*/ |
|
12
|
|
|
public $model; |
|
13
|
|
|
|
|
14
|
|
|
/** |
|
15
|
|
|
* The config implementation. |
|
16
|
|
|
* |
|
17
|
|
|
* @var config |
|
18
|
|
|
*/ |
|
19
|
|
|
protected $config; |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* Create new AbstractRepository instance. |
|
23
|
|
|
*/ |
|
24
|
|
|
public function __construct() |
|
25
|
|
|
{ |
|
26
|
|
|
$this->config = \CoreConfig::getConfig(); |
|
27
|
|
|
$this->model = \App::make($this->getModel()); |
|
28
|
|
|
} |
|
29
|
|
|
|
|
30
|
|
|
/** |
|
31
|
|
|
* Fetch all records with relations from the storage. |
|
32
|
|
|
* |
|
33
|
|
|
* @param array $relations |
|
34
|
|
|
* @param string $sortBy |
|
35
|
|
|
* @param boolean $desc |
|
36
|
|
|
* @param array $columns |
|
37
|
|
|
* @return collection |
|
38
|
|
|
*/ |
|
39
|
|
|
public function all($relations = [], $sortBy = 'created_at', $desc = 1, $columns = array('*')) |
|
40
|
|
|
{ |
|
41
|
|
|
$sort = $desc ? 'desc' : 'asc'; |
|
42
|
|
|
return call_user_func_array("{$this->getModel()}::with", array($relations))->orderBy($sortBy, $sort)->get($columns); |
|
43
|
|
|
} |
|
44
|
|
|
|
|
45
|
|
|
/** |
|
46
|
|
|
* Fetch all records with relations from storage in pages |
|
47
|
|
|
* that matche the given query. |
|
48
|
|
|
* |
|
49
|
|
|
* @param string $query |
|
50
|
|
|
* @param integer $perPage |
|
51
|
|
|
* @param array $relations |
|
52
|
|
|
* @param string $sortBy |
|
53
|
|
|
* @param boolean $desc |
|
54
|
|
|
* @param array $columns |
|
55
|
|
|
* @return collection |
|
56
|
|
|
*/ |
|
57
|
|
|
public function search($query, $perPage = 15, $relations = [], $sortBy = 'created_at', $desc = 1, $columns = array('*')) |
|
58
|
|
|
{ |
|
59
|
|
|
$model = call_user_func_array("{$this->getModel()}::with", array($relations)); |
|
60
|
|
|
$conditionColumns = $this->model->searchable; |
|
61
|
|
|
$sort = $desc ? 'desc' : 'asc'; |
|
62
|
|
|
|
|
63
|
|
|
/** |
|
64
|
|
|
* Construct the select conditions for the model. |
|
65
|
|
|
*/ |
|
66
|
|
|
$model->where(function ($q) use ($query, $conditionColumns, $relations){ |
|
67
|
|
|
|
|
68
|
|
View Code Duplication |
if (count($conditionColumns)) |
|
|
|
|
|
|
69
|
|
|
{ |
|
70
|
|
|
$column = 'LOWER(' . array_shift($conditionColumns) . ')'; |
|
71
|
|
|
if (str_contains($column, '->')) |
|
72
|
|
|
{ |
|
73
|
|
|
$column = $this->wrapJsonSelector($column); |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
|
|
/** |
|
77
|
|
|
* Use the first element in the model columns to construct the first condition. |
|
78
|
|
|
*/ |
|
79
|
|
|
$q->where(\DB::raw($column), 'LIKE', '%' . strtolower($query) . '%'); |
|
80
|
|
|
} |
|
81
|
|
|
|
|
82
|
|
|
/** |
|
83
|
|
|
* Loop through the rest of the columns to construct or where conditions. |
|
84
|
|
|
*/ |
|
85
|
|
View Code Duplication |
foreach ($conditionColumns as $column) |
|
|
|
|
|
|
86
|
|
|
{ |
|
87
|
|
|
$column = 'LOWER(' . $column . ')'; |
|
88
|
|
|
if (str_contains($column, '->')) |
|
89
|
|
|
{ |
|
90
|
|
|
$column = $this->wrapJsonSelector($column); |
|
91
|
|
|
} |
|
92
|
|
|
|
|
93
|
|
|
$q->orWhere(\DB::raw($column), 'LIKE', '%' . strtolower($query) . '%'); |
|
94
|
|
|
} |
|
95
|
|
|
|
|
96
|
|
|
/** |
|
97
|
|
|
* Loop through the model relations. |
|
98
|
|
|
*/ |
|
99
|
|
|
foreach ($relations as $relation) |
|
100
|
|
|
{ |
|
101
|
|
|
/** |
|
102
|
|
|
* Remove the sub relation if exists. |
|
103
|
|
|
*/ |
|
104
|
|
|
$relation = explode('.', $relation)[0]; |
|
105
|
|
|
|
|
106
|
|
|
/** |
|
107
|
|
|
* Try to fetch the relation repository from the core. |
|
108
|
|
|
*/ |
|
109
|
|
|
if (\Core::$relation()) |
|
110
|
|
|
{ |
|
111
|
|
|
/** |
|
112
|
|
|
* Construct the relation condition. |
|
113
|
|
|
*/ |
|
114
|
|
|
$q->orWhereHas($relation, function ($subModel) use ($query, $relation){ |
|
115
|
|
|
|
|
116
|
|
|
$subModel->where(function ($q) use ($query, $relation){ |
|
117
|
|
|
|
|
118
|
|
|
/** |
|
119
|
|
|
* Get columns of the relation. |
|
120
|
|
|
*/ |
|
121
|
|
|
$subConditionColumns = \Core::$relation()->model->searchable; |
|
122
|
|
|
|
|
123
|
|
View Code Duplication |
if (count($subConditionColumns)) |
|
|
|
|
|
|
124
|
|
|
{ |
|
125
|
|
|
|
|
126
|
|
|
$column = 'LOWER(' . array_shift($subConditionColumns) . ')'; |
|
127
|
|
|
if (str_contains($column, '->')) |
|
128
|
|
|
{ |
|
129
|
|
|
$column = $this->wrapJsonSelector($column); |
|
130
|
|
|
} |
|
131
|
|
|
|
|
132
|
|
|
/** |
|
133
|
|
|
* Use the first element in the relation model columns to construct the first condition. |
|
134
|
|
|
*/ |
|
135
|
|
|
$q->where(\DB::raw($column), 'LIKE', '%' . strtolower($query) . '%'); |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
|
|
/** |
|
139
|
|
|
* Loop through the rest of the columns to construct or where conditions. |
|
140
|
|
|
*/ |
|
141
|
|
View Code Duplication |
foreach ($subConditionColumns as $subConditionColumn) |
|
|
|
|
|
|
142
|
|
|
{ |
|
143
|
|
|
$column = 'LOWER(' . $subConditionColumn . ')'; |
|
144
|
|
|
if (str_contains($column, '->')) |
|
145
|
|
|
{ |
|
146
|
|
|
$column = $this->wrapJsonSelector($column); |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
$q->orWhere(\DB::raw($column), 'LIKE', '%' . strtolower($query) . '%'); |
|
150
|
|
|
} |
|
151
|
|
|
}); |
|
152
|
|
|
|
|
153
|
|
|
}); |
|
154
|
|
|
} |
|
155
|
|
|
} |
|
156
|
|
|
}); |
|
157
|
|
|
|
|
158
|
|
|
return $model->orderBy($sortBy, $sort)->paginate($perPage, $columns); |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
|
|
/** |
|
162
|
|
|
* Fetch all records with relations from storage in pages. |
|
163
|
|
|
* |
|
164
|
|
|
* @param integer $perPage |
|
165
|
|
|
* @param array $relations |
|
166
|
|
|
* @param string $sortBy |
|
167
|
|
|
* @param boolean $desc |
|
168
|
|
|
* @param array $columns |
|
169
|
|
|
* @return collection |
|
170
|
|
|
*/ |
|
171
|
|
|
public function paginate($perPage = 15, $relations = [], $sortBy = 'created_at', $desc = 1, $columns = array('*')) |
|
172
|
|
|
{ |
|
173
|
|
|
$sort = $desc ? 'desc' : 'asc'; |
|
174
|
|
|
return call_user_func_array("{$this->getModel()}::with", array($relations))->orderBy($sortBy, $sort)->paginate($perPage, $columns); |
|
175
|
|
|
} |
|
176
|
|
|
|
|
177
|
|
|
/** |
|
178
|
|
|
* Fetch all records with relations based on |
|
179
|
|
|
* the given condition from storage in pages. |
|
180
|
|
|
* |
|
181
|
|
|
* @param array $conditions array of conditions |
|
182
|
|
|
* @param integer $perPage |
|
183
|
|
|
* @param array $relations |
|
184
|
|
|
* @param string $sortBy |
|
185
|
|
|
* @param boolean $desc |
|
186
|
|
|
* @param array $columns |
|
187
|
|
|
* @return collection |
|
188
|
|
|
*/ |
|
189
|
|
|
public function paginateBy($conditions, $perPage = 15, $relations = [], $sortBy = 'created_at', $desc = 1, $columns = array('*')) |
|
190
|
|
|
{ |
|
191
|
|
|
unset($conditions['page']); |
|
192
|
|
|
$conditions = $this->constructConditions($conditions, $this->model); |
|
193
|
|
|
$sort = $desc ? 'desc' : 'asc'; |
|
194
|
|
|
return call_user_func_array("{$this->getModel()}::with", array($relations))->whereRaw($conditions['conditionString'], $conditions['conditionValues'])->orderBy($sortBy, $sort)->paginate($perPage, $columns); |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
/** |
|
198
|
|
|
* Save the given model to the storage. |
|
199
|
|
|
* |
|
200
|
|
|
* @param array $data |
|
201
|
|
|
* @return void |
|
202
|
|
|
*/ |
|
203
|
|
|
public function save(array $data) |
|
204
|
|
|
{ |
|
205
|
|
|
$model = false; |
|
206
|
|
|
$modelClass = $this->model; |
|
207
|
|
|
$relations = []; |
|
208
|
|
|
|
|
209
|
|
|
\DB::transaction(function () use (&$model, &$relations, $data, $modelClass) { |
|
210
|
|
|
/** |
|
211
|
|
|
* If the id is present in the data then select the model for updating, |
|
212
|
|
|
* else create new model. |
|
213
|
|
|
* @var array |
|
214
|
|
|
*/ |
|
215
|
|
|
$model = array_key_exists('id', $data) ? $modelClass->lockForUpdate()->find($data['id']) : new $modelClass; |
|
216
|
|
|
if ( ! $model) |
|
217
|
|
|
{ |
|
218
|
|
|
\ErrorHandler::notFound(class_basename($modelClass) . ' with id : ' . $data['id']); |
|
219
|
|
|
} |
|
220
|
|
|
|
|
221
|
|
|
/** |
|
222
|
|
|
* Construct the model object with the given data, |
|
223
|
|
|
* and if there is a relation add it to relations array, |
|
224
|
|
|
* then save the model. |
|
225
|
|
|
*/ |
|
226
|
|
|
foreach ($data as $key => $value) |
|
227
|
|
|
{ |
|
228
|
|
|
/** |
|
229
|
|
|
* If the attribute is a relation. |
|
230
|
|
|
*/ |
|
231
|
|
|
$relation = camel_case($key); |
|
232
|
|
|
if (method_exists($model, $relation) && \Core::$relation()) |
|
233
|
|
|
{ |
|
234
|
|
|
/** |
|
235
|
|
|
* Check if the relation is a collection. |
|
236
|
|
|
*/ |
|
237
|
|
|
if (class_basename($model->$relation) == 'Collection') |
|
238
|
|
|
{ |
|
239
|
|
|
/** |
|
240
|
|
|
* If the relation has no value then marke the relation data |
|
241
|
|
|
* related to the model to be deleted. |
|
242
|
|
|
*/ |
|
243
|
|
|
if ( ! $value || ! count($value)) |
|
244
|
|
|
{ |
|
245
|
|
|
$relations[$relation] = 'delete'; |
|
246
|
|
|
} |
|
247
|
|
|
} |
|
248
|
|
|
if (is_array($value)) |
|
249
|
|
|
{ |
|
250
|
|
|
/** |
|
251
|
|
|
* Loop through the relation data. |
|
252
|
|
|
*/ |
|
253
|
|
|
foreach ($value as $attr => $val) |
|
254
|
|
|
{ |
|
255
|
|
|
/** |
|
256
|
|
|
* Get the relation model. |
|
257
|
|
|
*/ |
|
258
|
|
|
$relationBaseModel = \Core::$relation()->model; |
|
259
|
|
|
|
|
260
|
|
|
/** |
|
261
|
|
|
* Check if the relation is a collection. |
|
262
|
|
|
*/ |
|
263
|
|
|
if (class_basename($model->$relation) == 'Collection') |
|
264
|
|
|
{ |
|
265
|
|
|
/** |
|
266
|
|
|
* If the id is present in the data then select the relation model for updating, |
|
267
|
|
|
* else create new model. |
|
268
|
|
|
*/ |
|
269
|
|
|
$relationModel = array_key_exists('id', $val) ? $relationBaseModel->lockForUpdate()->find($val['id']) : new $relationBaseModel; |
|
270
|
|
|
|
|
271
|
|
|
/** |
|
272
|
|
|
* If model doesn't exists. |
|
273
|
|
|
*/ |
|
274
|
|
|
if ( ! $relationModel) |
|
275
|
|
|
{ |
|
276
|
|
|
\ErrorHandler::notFound(class_basename($relationBaseModel) . ' with id : ' . $val['id']); |
|
277
|
|
|
} |
|
278
|
|
|
|
|
279
|
|
|
/** |
|
280
|
|
|
* Loop through the relation attributes. |
|
281
|
|
|
*/ |
|
282
|
|
|
foreach ($val as $attr => $val) |
|
283
|
|
|
{ |
|
284
|
|
|
/** |
|
285
|
|
|
* Prevent the sub relations or attributes not in the fillable. |
|
286
|
|
|
*/ |
|
287
|
|
|
if (gettype($val) !== 'object' && gettype($val) !== 'array' && array_search($attr, $relationModel->getFillable(), true) !== false) |
|
288
|
|
|
{ |
|
289
|
|
|
$relationModel->$attr = $val; |
|
290
|
|
|
} |
|
291
|
|
|
} |
|
292
|
|
|
|
|
293
|
|
|
$relations[$relation][] = $relationModel; |
|
294
|
|
|
} |
|
295
|
|
|
/** |
|
296
|
|
|
* If not collection. |
|
297
|
|
|
*/ |
|
298
|
|
|
else |
|
299
|
|
|
{ |
|
300
|
|
|
/** |
|
301
|
|
|
* Prevent the sub relations. |
|
302
|
|
|
*/ |
|
303
|
|
|
if (gettype($val) !== 'object' && gettype($val) !== 'array') |
|
304
|
|
|
{ |
|
305
|
|
|
|
|
306
|
|
|
/** |
|
307
|
|
|
* If the id is present in the data then select the relation model for updating, |
|
308
|
|
|
* else create new model. |
|
309
|
|
|
*/ |
|
310
|
|
|
$relationModel = array_key_exists('id', $value) ? $relationBaseModel->lockForUpdate()->find($value['id']) : new $relationBaseModel; |
|
311
|
|
|
|
|
312
|
|
|
/** |
|
313
|
|
|
* If model doesn't exists. |
|
314
|
|
|
*/ |
|
315
|
|
|
if ( ! $relationModel) |
|
316
|
|
|
{ |
|
317
|
|
|
\ErrorHandler::notFound(class_basename($relationBaseModel) . ' with id : ' . $value['id']); |
|
318
|
|
|
} |
|
319
|
|
|
|
|
320
|
|
|
foreach ($value as $relationAttribute => $relationValue) |
|
321
|
|
|
{ |
|
322
|
|
|
/** |
|
323
|
|
|
* Prevent attributes not in the fillable. |
|
324
|
|
|
*/ |
|
325
|
|
|
if (array_search($relationAttribute, $relationModel->getFillable(), true) !== false) |
|
326
|
|
|
{ |
|
327
|
|
|
$relationModel->$relationAttribute = $relationValue; |
|
328
|
|
|
} |
|
329
|
|
|
} |
|
330
|
|
|
|
|
331
|
|
|
$relations[$relation] = $relationModel; |
|
332
|
|
|
} |
|
333
|
|
|
} |
|
334
|
|
|
} |
|
335
|
|
|
} |
|
336
|
|
|
} |
|
337
|
|
|
/** |
|
338
|
|
|
* If the attribute isn't a relation and prevent attributes not in the fillable. |
|
339
|
|
|
*/ |
|
340
|
|
|
else if (array_search($key, $model->getFillable(), true) !== false) |
|
341
|
|
|
{ |
|
342
|
|
|
$model->$key = $value; |
|
343
|
|
|
} |
|
344
|
|
|
} |
|
345
|
|
|
/** |
|
346
|
|
|
* Save the model. |
|
347
|
|
|
*/ |
|
348
|
|
|
$model->save(); |
|
349
|
|
|
|
|
350
|
|
|
/** |
|
351
|
|
|
* Loop through the relations array. |
|
352
|
|
|
*/ |
|
353
|
|
|
foreach ($relations as $key => $value) |
|
354
|
|
|
{ |
|
355
|
|
|
/** |
|
356
|
|
|
* If the relation is marked for delete then delete it. |
|
357
|
|
|
*/ |
|
358
|
|
|
if ($value == 'delete' && $model->$key()->count()) |
|
359
|
|
|
{ |
|
360
|
|
|
$model->$key()->delete(); |
|
361
|
|
|
} |
|
362
|
|
|
/** |
|
363
|
|
|
* If the relation is an array. |
|
364
|
|
|
*/ |
|
365
|
|
|
else if (gettype($value) == 'array') |
|
366
|
|
|
{ |
|
367
|
|
|
$ids = []; |
|
368
|
|
|
/** |
|
369
|
|
|
* Loop through the relations. |
|
370
|
|
|
*/ |
|
371
|
|
|
foreach ($value as $val) |
|
372
|
|
|
{ |
|
373
|
|
|
switch (class_basename($model->$key())) |
|
374
|
|
|
{ |
|
375
|
|
|
/** |
|
376
|
|
|
* If the relation is one to many then update it's foreign key with |
|
377
|
|
|
* the model id and save it then add its id to ids array to delete all |
|
378
|
|
|
* relations who's id isn't in the ids array. |
|
379
|
|
|
*/ |
|
380
|
|
|
case 'HasMany': |
|
381
|
|
|
$foreignKeyName = $model->$key()->getForeignKeyName(); |
|
382
|
|
|
$val->$foreignKeyName = $model->id; |
|
383
|
|
|
$val->save(); |
|
384
|
|
|
$ids[] = $val->id; |
|
385
|
|
|
break; |
|
386
|
|
|
|
|
387
|
|
|
/** |
|
388
|
|
|
* If the relation is many to many then add it's id to the ids array to |
|
389
|
|
|
* attache these ids to the model. |
|
390
|
|
|
*/ |
|
391
|
|
|
case 'BelongsToMany': |
|
392
|
|
|
$val->save(); |
|
393
|
|
|
$ids[] = $val->id; |
|
394
|
|
|
break; |
|
395
|
|
|
} |
|
396
|
|
|
} |
|
397
|
|
|
switch (class_basename($model->$key())) |
|
398
|
|
|
{ |
|
399
|
|
|
/** |
|
400
|
|
|
* If the relation is one to many then delete all |
|
401
|
|
|
* relations who's id isn't in the ids array. |
|
402
|
|
|
*/ |
|
403
|
|
|
case 'HasMany': |
|
404
|
|
|
$model->$key()->whereNotIn('id', $ids)->delete(); |
|
405
|
|
|
break; |
|
406
|
|
|
|
|
407
|
|
|
/** |
|
408
|
|
|
* If the relation is many to many then |
|
409
|
|
|
* detach the previous data and attach |
|
410
|
|
|
* the ids array to the model. |
|
411
|
|
|
*/ |
|
412
|
|
|
case 'BelongsToMany': |
|
413
|
|
|
$model->$key()->detach(); |
|
414
|
|
|
$model->$key()->attach($ids); |
|
415
|
|
|
break; |
|
416
|
|
|
} |
|
417
|
|
|
} |
|
418
|
|
|
/** |
|
419
|
|
|
* If the relation isn't array. |
|
420
|
|
|
*/ |
|
421
|
|
|
else |
|
422
|
|
|
{ |
|
423
|
|
|
switch (class_basename($model->$key())) |
|
424
|
|
|
{ |
|
425
|
|
|
/** |
|
426
|
|
|
* If the relation is one to many or one to one. |
|
427
|
|
|
*/ |
|
428
|
|
|
case 'HasOne': |
|
429
|
|
|
$foreignKeyName = $model->$key()->getForeignKeyName(); |
|
430
|
|
|
$value->$foreignKeyName = $model->id; |
|
431
|
|
|
$value->save(); |
|
432
|
|
|
break; |
|
433
|
|
|
} |
|
434
|
|
|
} |
|
435
|
|
|
} |
|
436
|
|
|
}); |
|
437
|
|
|
|
|
438
|
|
|
return $model->id; |
|
439
|
|
|
} |
|
440
|
|
|
|
|
441
|
|
|
/** |
|
442
|
|
|
* Update record in the storage based on the given |
|
443
|
|
|
* condition. |
|
444
|
|
|
* |
|
445
|
|
|
* @param var $value condition value |
|
446
|
|
|
* @param array $data |
|
447
|
|
|
* @param string $attribute condition column name |
|
448
|
|
|
* @return void |
|
449
|
|
|
*/ |
|
450
|
|
|
public function update($value, array $data, $attribute = 'id') |
|
451
|
|
|
{ |
|
452
|
|
|
if ($attribute == 'id') |
|
453
|
|
|
{ |
|
454
|
|
|
$model = $this->model->lockForUpdate()->find($value); |
|
455
|
|
|
$model ? $model->update($data) : 0; |
|
456
|
|
|
} |
|
457
|
|
|
else |
|
458
|
|
|
{ |
|
459
|
|
|
call_user_func_array("{$this->getModel()}::where", array($attribute, '=', $value))->lockForUpdate()->get()->each(function ($model) use ($data){ |
|
460
|
|
|
$model->update($data); |
|
461
|
|
|
}); |
|
462
|
|
|
} |
|
463
|
|
|
} |
|
464
|
|
|
|
|
465
|
|
|
/** |
|
466
|
|
|
* Delete record from the storage based on the given |
|
467
|
|
|
* condition. |
|
468
|
|
|
* |
|
469
|
|
|
* @param var $value condition value |
|
470
|
|
|
* @param string $attribute condition column name |
|
471
|
|
|
* @return void |
|
472
|
|
|
*/ |
|
473
|
|
|
public function delete($value, $attribute = 'id') |
|
474
|
|
|
{ |
|
475
|
|
|
if ($attribute == 'id') |
|
476
|
|
|
{ |
|
477
|
|
|
\DB::transaction(function () use ($value, $attribute, &$result) { |
|
478
|
|
|
$model = $this->model->lockForUpdate()->find($value); |
|
479
|
|
|
if ( ! $model) |
|
480
|
|
|
{ |
|
481
|
|
|
\ErrorHandler::notFound(class_basename($this->model) . ' with id : ' . $value); |
|
482
|
|
|
} |
|
483
|
|
|
|
|
484
|
|
|
$model->delete(); |
|
485
|
|
|
}); |
|
486
|
|
|
} |
|
487
|
|
|
else |
|
488
|
|
|
{ |
|
489
|
|
|
\DB::transaction(function () use ($value, $attribute, &$result) { |
|
490
|
|
|
call_user_func_array("{$this->getModel()}::where", array($attribute, '=', $value))->lockForUpdate()->get()->each(function ($model){ |
|
491
|
|
|
$model->delete(); |
|
492
|
|
|
}); |
|
493
|
|
|
}); |
|
494
|
|
|
} |
|
495
|
|
|
} |
|
496
|
|
|
|
|
497
|
|
|
/** |
|
498
|
|
|
* Fetch records from the storage based on the given |
|
499
|
|
|
* id. |
|
500
|
|
|
* |
|
501
|
|
|
* @param integer $id |
|
502
|
|
|
* @param array $relations |
|
503
|
|
|
* @param array $columns |
|
504
|
|
|
* @return object |
|
505
|
|
|
*/ |
|
506
|
|
|
public function find($id, $relations = [], $columns = array('*')) |
|
507
|
|
|
{ |
|
508
|
|
|
return call_user_func_array("{$this->getModel()}::with", array($relations))->find($id, $columns); |
|
509
|
|
|
} |
|
510
|
|
|
|
|
511
|
|
|
/** |
|
512
|
|
|
* Fetch records from the storage based on the given |
|
513
|
|
|
* condition. |
|
514
|
|
|
* |
|
515
|
|
|
* @param array $conditions array of conditions |
|
516
|
|
|
* @param array $relations |
|
517
|
|
|
* @param string $sortBy |
|
518
|
|
|
* @param boolean $desc |
|
519
|
|
|
* @param array $columns |
|
520
|
|
|
* @return collection |
|
521
|
|
|
*/ |
|
522
|
|
|
public function findBy($conditions, $relations = [], $sortBy = 'created_at', $desc = 1, $columns = array('*')) |
|
523
|
|
|
{ |
|
524
|
|
|
$conditions = $this->constructConditions($conditions, $this->model); |
|
525
|
|
|
$sort = $desc ? 'desc' : 'asc'; |
|
526
|
|
|
return call_user_func_array("{$this->getModel()}::with", array($relations))->whereRaw($conditions['conditionString'], $conditions['conditionValues'])->orderBy($sortBy, $sort)->get($columns); |
|
527
|
|
|
} |
|
528
|
|
|
|
|
529
|
|
|
/** |
|
530
|
|
|
* Fetch the first record from the storage based on the given |
|
531
|
|
|
* condition. |
|
532
|
|
|
* |
|
533
|
|
|
* @param array $conditions array of conditions |
|
534
|
|
|
* @param array $relations |
|
535
|
|
|
* @param array $columns |
|
536
|
|
|
* @return object |
|
537
|
|
|
*/ |
|
538
|
|
|
public function first($conditions, $relations = [], $columns = array('*')) |
|
539
|
|
|
{ |
|
540
|
|
|
$conditions = $this->constructConditions($conditions, $this->model); |
|
541
|
|
|
return call_user_func_array("{$this->getModel()}::with", array($relations))->whereRaw($conditions['conditionString'], $conditions['conditionValues'])->first($columns); |
|
542
|
|
|
} |
|
543
|
|
|
|
|
544
|
|
|
/** |
|
545
|
|
|
* Return the deleted models in pages based on the given conditions. |
|
546
|
|
|
* |
|
547
|
|
|
* @param array $conditions array of conditions |
|
548
|
|
|
* @param integer $perPage |
|
549
|
|
|
* @param string $sortBy |
|
550
|
|
|
* @param boolean $desc |
|
551
|
|
|
* @param array $columns |
|
552
|
|
|
* @return collection |
|
553
|
|
|
*/ |
|
554
|
|
|
public function deleted($conditions, $perPage = 15, $sortBy = 'created_at', $desc = 1, $columns = array('*')) |
|
555
|
|
|
{ |
|
556
|
|
|
unset($conditions['page']); |
|
557
|
|
|
$conditions = $this->constructConditions($conditions, $this->model); |
|
558
|
|
|
$sort = $desc ? 'desc' : 'asc'; |
|
559
|
|
|
$model = $this->model->onlyTrashed(); |
|
560
|
|
|
|
|
561
|
|
|
if (count($conditions['conditionValues'])) |
|
562
|
|
|
{ |
|
563
|
|
|
$model->whereRaw($conditions['conditionString'], $conditions['conditionValues']); |
|
564
|
|
|
} |
|
565
|
|
|
|
|
566
|
|
|
return $model->orderBy($sortBy, $sort)->paginate($perPage, $columns);; |
|
567
|
|
|
} |
|
568
|
|
|
|
|
569
|
|
|
/** |
|
570
|
|
|
* Restore the deleted model. |
|
571
|
|
|
* |
|
572
|
|
|
* @param integer $id |
|
573
|
|
|
* @return void |
|
574
|
|
|
*/ |
|
575
|
|
|
public function restore($id) |
|
576
|
|
|
{ |
|
577
|
|
|
$model = $this->model->onlyTrashed()->find($id); |
|
578
|
|
|
|
|
579
|
|
|
if ( ! $model) |
|
580
|
|
|
{ |
|
581
|
|
|
\ErrorHandler::notFound(class_basename($this->model) . ' with id : ' . $id); |
|
582
|
|
|
} |
|
583
|
|
|
|
|
584
|
|
|
$model->restore(); |
|
585
|
|
|
} |
|
586
|
|
|
|
|
587
|
|
|
/** |
|
588
|
|
|
* Build the conditions recursively for the retrieving methods. |
|
589
|
|
|
* @param array $conditions |
|
590
|
|
|
* @return array |
|
591
|
|
|
*/ |
|
592
|
|
|
protected function constructConditions($conditions, $model) |
|
593
|
|
|
{ |
|
594
|
|
|
$conditionString = ''; |
|
595
|
|
|
$conditionValues = []; |
|
596
|
|
|
foreach ($conditions as $key => $value) |
|
597
|
|
|
{ |
|
598
|
|
|
if (str_contains($key, '->')) |
|
599
|
|
|
{ |
|
600
|
|
|
$key = $this->wrapJsonSelector($key); |
|
601
|
|
|
} |
|
602
|
|
|
|
|
603
|
|
|
if ($key == 'and') |
|
604
|
|
|
{ |
|
605
|
|
|
$conditions = $this->constructConditions($value, $model); |
|
606
|
|
|
$conditionString .= str_replace('{op}', 'and', $conditions['conditionString']) . ' {op} '; |
|
607
|
|
|
$conditionValues = array_merge($conditionValues, $conditions['conditionValues']); |
|
608
|
|
|
} |
|
609
|
|
|
else if ($key == 'or') |
|
610
|
|
|
{ |
|
611
|
|
|
$conditions = $this->constructConditions($value, $model); |
|
612
|
|
|
$conditionString .= str_replace('{op}', 'or', $conditions['conditionString']) . ' {op} '; |
|
613
|
|
|
$conditionValues = array_merge($conditionValues, $conditions['conditionValues']); |
|
614
|
|
|
} |
|
615
|
|
|
else |
|
616
|
|
|
{ |
|
617
|
|
|
if (is_array($value)) |
|
618
|
|
|
{ |
|
619
|
|
|
$operator = $value['op']; |
|
620
|
|
|
if (strtolower($operator) == 'between') |
|
621
|
|
|
{ |
|
622
|
|
|
$value1 = $value['val1']; |
|
623
|
|
|
$value2 = $value['val2']; |
|
624
|
|
|
} |
|
625
|
|
|
else |
|
626
|
|
|
{ |
|
627
|
|
|
$value = array_key_exists('val', $value) ? $value['val'] : ''; |
|
628
|
|
|
} |
|
629
|
|
|
} |
|
630
|
|
|
else |
|
631
|
|
|
{ |
|
632
|
|
|
$operator = '='; |
|
633
|
|
|
} |
|
634
|
|
|
|
|
635
|
|
|
if (strtolower($operator) == 'between') |
|
636
|
|
|
{ |
|
637
|
|
|
$conditionString .= $key . ' >= ? and '; |
|
638
|
|
|
$conditionValues[] = $value1; |
|
|
|
|
|
|
639
|
|
|
|
|
640
|
|
|
$conditionString .= $key . ' <= ? {op} '; |
|
641
|
|
|
$conditionValues[] = $value2; |
|
|
|
|
|
|
642
|
|
|
} |
|
643
|
|
|
elseif (strtolower($operator) == 'in') |
|
644
|
|
|
{ |
|
645
|
|
|
$conditionValues = array_merge($conditionValues, $value); |
|
646
|
|
|
$inBindingsString = rtrim(str_repeat('?,', count($value)), ','); |
|
647
|
|
|
$conditionString .= $key . ' in (' . rtrim($inBindingsString, ',') . ') {op} '; |
|
648
|
|
|
} |
|
649
|
|
|
elseif (strtolower($operator) == 'null') |
|
650
|
|
|
{ |
|
651
|
|
|
$conditionString .= $key . ' is null {op} '; |
|
652
|
|
|
} |
|
653
|
|
|
elseif (strtolower($operator) == 'not null') |
|
654
|
|
|
{ |
|
655
|
|
|
$conditionString .= $key . ' is not null {op} '; |
|
656
|
|
|
} |
|
657
|
|
|
elseif (strtolower($operator) == 'has') |
|
658
|
|
|
{ |
|
659
|
|
|
$sql = $model->withTrashed()->has($key)->toSql(); |
|
660
|
|
|
$conditions = $this->constructConditions($value, $model->$key()->getRelated()); |
|
661
|
|
|
$conditionString .= rtrim(substr($sql, strpos($sql, 'exists')), ')') . ' and ' . $conditions['conditionString'] . ') {op} '; |
|
662
|
|
|
$conditionValues = array_merge($conditionValues, $conditions['conditionValues']); |
|
663
|
|
|
} |
|
664
|
|
|
else |
|
665
|
|
|
{ |
|
666
|
|
|
$conditionString .= $key . ' ' . $operator . ' ? {op} '; |
|
667
|
|
|
$conditionValues[] = $value; |
|
668
|
|
|
} |
|
669
|
|
|
} |
|
670
|
|
|
} |
|
671
|
|
|
$conditionString = '(' . rtrim($conditionString, '{op} ') . ')'; |
|
672
|
|
|
return ['conditionString' => $conditionString, 'conditionValues' => $conditionValues]; |
|
673
|
|
|
} |
|
674
|
|
|
|
|
675
|
|
|
/** |
|
676
|
|
|
* Wrap the given JSON selector. |
|
677
|
|
|
* |
|
678
|
|
|
* @param string $value |
|
679
|
|
|
* @return string |
|
680
|
|
|
*/ |
|
681
|
|
|
protected function wrapJsonSelector($value) |
|
682
|
|
|
{ |
|
683
|
|
|
$removeLast = strpos($value, ')'); |
|
684
|
|
|
$value = $removeLast === false ? $value : substr($value, 0, $removeLast); |
|
685
|
|
|
$path = explode('->', $value); |
|
686
|
|
|
$field = array_shift($path); |
|
687
|
|
|
$result = sprintf('%s->\'$.%s\'', $field, collect($path)->map(function ($part) { |
|
688
|
|
|
return '"'.$part.'"'; |
|
689
|
|
|
})->implode('.')); |
|
690
|
|
|
|
|
691
|
|
|
return $removeLast === false ? $result : $result . ')'; |
|
692
|
|
|
} |
|
693
|
|
|
|
|
694
|
|
|
/** |
|
695
|
|
|
* Abstract method that return the necessary |
|
696
|
|
|
* information (full model namespace) |
|
697
|
|
|
* needed to preform the previous actions. |
|
698
|
|
|
* |
|
699
|
|
|
* @return string |
|
700
|
|
|
*/ |
|
701
|
|
|
abstract protected function getModel(); |
|
702
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.