Total Complexity | 133 |
Total Lines | 1194 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like BaseRepository often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use BaseRepository, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
34 | abstract class BaseRepository implements RepositoryInterface, RepositoryCriteriaInterface |
||
35 | { |
||
36 | use ComparesVersionsTrait; |
||
37 | |||
38 | /** |
||
39 | * @var Application |
||
40 | */ |
||
41 | protected $app; |
||
42 | |||
43 | /** |
||
44 | * @var Model |
||
45 | */ |
||
46 | protected $model; |
||
47 | |||
48 | /** |
||
49 | * @var array |
||
50 | */ |
||
51 | protected $fieldSearchable = []; |
||
52 | |||
53 | /** |
||
54 | * @var PresenterInterface |
||
55 | */ |
||
56 | protected $presenter; |
||
57 | |||
58 | /** |
||
59 | * @var ValidatorInterface |
||
60 | */ |
||
61 | protected $validator; |
||
62 | |||
63 | /** |
||
64 | * Validation Rules |
||
65 | * |
||
66 | * @var array |
||
67 | */ |
||
68 | protected $rules = null; |
||
69 | |||
70 | /** |
||
71 | * Collection of Criteria |
||
72 | * |
||
73 | * @var Collection |
||
74 | */ |
||
75 | protected $criteria; |
||
76 | |||
77 | /** |
||
78 | * @var bool |
||
79 | */ |
||
80 | protected $skipCriteria = false; |
||
81 | |||
82 | /** |
||
83 | * @var bool |
||
84 | */ |
||
85 | protected $skipPresenter = false; |
||
86 | |||
87 | /** |
||
88 | * @var \Closure |
||
89 | */ |
||
90 | protected $scopeQuery = null; |
||
91 | |||
92 | /** |
||
93 | * @param Application $app |
||
94 | */ |
||
95 | public function __construct(Application $app) |
||
96 | { |
||
97 | $this->app = $app; |
||
98 | $this->criteria = new Collection(); |
||
99 | $this->makeModel(); |
||
100 | $this->makePresenter(); |
||
101 | $this->makeValidator(); |
||
102 | $this->boot(); |
||
103 | } |
||
104 | |||
105 | /** |
||
106 | * |
||
107 | */ |
||
108 | public function boot() |
||
109 | { |
||
110 | // |
||
111 | } |
||
112 | |||
113 | /** |
||
114 | * Returns the current Model instance |
||
115 | * |
||
116 | * @return Model |
||
117 | */ |
||
118 | public function getModel() |
||
119 | { |
||
120 | return $this->model; |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * @throws RepositoryException |
||
125 | */ |
||
126 | public function resetModel() |
||
127 | { |
||
128 | $this->makeModel(); |
||
129 | } |
||
130 | |||
131 | /** |
||
132 | * Specify Model class name |
||
133 | * |
||
134 | * @return string |
||
135 | */ |
||
136 | abstract public function model(); |
||
137 | |||
138 | /** |
||
139 | * Specify Presenter class name |
||
140 | * |
||
141 | * @return string |
||
142 | */ |
||
143 | public function presenter() |
||
144 | { |
||
145 | return null; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Specify Validator class name of Salah3id\Domains\Validator\Contracts\ValidatorInterface |
||
150 | * |
||
151 | * @return null |
||
152 | * @throws Exception |
||
153 | */ |
||
154 | public function validator() |
||
155 | { |
||
156 | if (isset($this->rules) && !is_null($this->rules) && is_array($this->rules) && !empty($this->rules)) { |
||
157 | if (class_exists('Salah3id\Domains\Validator\LaravelValidator')) { |
||
158 | $validator = app('Salah3id\Domains\Validator\LaravelValidator'); |
||
159 | if ($validator instanceof ValidatorInterface) { |
||
|
|||
160 | $validator->setRules($this->rules); |
||
161 | |||
162 | return $validator; |
||
163 | } |
||
164 | } else { |
||
165 | throw new Exception(trans('repository::packages.prettus_laravel_validation_required')); |
||
166 | } |
||
167 | } |
||
168 | |||
169 | return null; |
||
170 | } |
||
171 | |||
172 | /** |
||
173 | * Set Presenter |
||
174 | * |
||
175 | * @param $presenter |
||
176 | * |
||
177 | * @return $this |
||
178 | */ |
||
179 | public function setPresenter($presenter) |
||
180 | { |
||
181 | $this->makePresenter($presenter); |
||
182 | |||
183 | return $this; |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * @return Model |
||
188 | * @throws RepositoryException |
||
189 | */ |
||
190 | public function makeModel() |
||
191 | { |
||
192 | $model = $this->app->make($this->model()); |
||
193 | |||
194 | if (!$model instanceof Model) { |
||
195 | throw new RepositoryException("Class {$this->model()} must be an instance of Illuminate\\Database\\Eloquent\\Model"); |
||
196 | } |
||
197 | |||
198 | return $this->model = $model; |
||
199 | } |
||
200 | |||
201 | /** |
||
202 | * @param null $presenter |
||
203 | * |
||
204 | * @return PresenterInterface |
||
205 | * @throws RepositoryException |
||
206 | */ |
||
207 | public function makePresenter($presenter = null) |
||
208 | { |
||
209 | $presenter = !is_null($presenter) ? $presenter : $this->presenter(); |
||
210 | |||
211 | if (!is_null($presenter)) { |
||
212 | $this->presenter = is_string($presenter) ? $this->app->make($presenter) : $presenter; |
||
213 | |||
214 | if (!$this->presenter instanceof PresenterInterface) { |
||
215 | throw new RepositoryException("Class {$presenter} must be an instance of Salah3id\Domains\\Repository\\Contracts\\PresenterInterface"); |
||
216 | } |
||
217 | |||
218 | return $this->presenter; |
||
219 | } |
||
220 | |||
221 | return null; |
||
222 | } |
||
223 | |||
224 | /** |
||
225 | * @param null $validator |
||
226 | * |
||
227 | * @return null|ValidatorInterface |
||
228 | * @throws RepositoryException |
||
229 | */ |
||
230 | public function makeValidator($validator = null) |
||
231 | { |
||
232 | $validator = !is_null($validator) ? $validator : $this->validator(); |
||
233 | |||
234 | if (!is_null($validator)) { |
||
235 | $this->validator = is_string($validator) ? $this->app->make($validator) : $validator; |
||
236 | |||
237 | if (!$this->validator instanceof ValidatorInterface) { |
||
238 | throw new RepositoryException("Class {$validator} must be an instance of Salah3id\Domains\\Validator\\Contracts\\ValidatorInterface"); |
||
239 | } |
||
240 | |||
241 | return $this->validator; |
||
242 | } |
||
243 | |||
244 | return null; |
||
245 | } |
||
246 | |||
247 | /** |
||
248 | * Get Searchable Fields |
||
249 | * |
||
250 | * @return array |
||
251 | */ |
||
252 | public function getFieldsSearchable() |
||
253 | { |
||
254 | return $this->fieldSearchable; |
||
255 | } |
||
256 | |||
257 | /** |
||
258 | * Query Scope |
||
259 | * |
||
260 | * @param \Closure $scope |
||
261 | * |
||
262 | * @return $this |
||
263 | */ |
||
264 | public function scopeQuery(\Closure $scope) |
||
265 | { |
||
266 | $this->scopeQuery = $scope; |
||
267 | |||
268 | return $this; |
||
269 | } |
||
270 | |||
271 | /** |
||
272 | * Retrieve data array for populate field select |
||
273 | * |
||
274 | * @param string $column |
||
275 | * @param string|null $key |
||
276 | * |
||
277 | * @return \Illuminate\Support\Collection|array |
||
278 | */ |
||
279 | public function lists($column, $key = null) |
||
280 | { |
||
281 | $this->applyCriteria(); |
||
282 | |||
283 | return $this->model->lists($column, $key); |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * Retrieve data array for populate field select |
||
288 | * Compatible with Laravel 5.3 |
||
289 | * |
||
290 | * @param string $column |
||
291 | * @param string|null $key |
||
292 | * |
||
293 | * @return \Illuminate\Support\Collection|array |
||
294 | */ |
||
295 | public function pluck($column, $key = null) |
||
296 | { |
||
297 | $this->applyCriteria(); |
||
298 | |||
299 | return $this->model->pluck($column, $key); |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * Sync relations |
||
304 | * |
||
305 | * @param $id |
||
306 | * @param $relation |
||
307 | * @param $attributes |
||
308 | * @param bool $detaching |
||
309 | * |
||
310 | * @return mixed |
||
311 | */ |
||
312 | public function sync($id, $relation, $attributes, $detaching = true) |
||
313 | { |
||
314 | return $this->find($id)->{$relation}()->sync($attributes, $detaching); |
||
315 | } |
||
316 | |||
317 | /** |
||
318 | * SyncWithoutDetaching |
||
319 | * |
||
320 | * @param $id |
||
321 | * @param $relation |
||
322 | * @param $attributes |
||
323 | * |
||
324 | * @return mixed |
||
325 | */ |
||
326 | public function syncWithoutDetaching($id, $relation, $attributes) |
||
327 | { |
||
328 | return $this->sync($id, $relation, $attributes, false); |
||
329 | } |
||
330 | |||
331 | /** |
||
332 | * Retrieve all data of repository |
||
333 | * |
||
334 | * @param array $columns |
||
335 | * |
||
336 | * @return mixed |
||
337 | */ |
||
338 | public function all($columns = ['*']) |
||
339 | { |
||
340 | $this->applyCriteria(); |
||
341 | $this->applyScope(); |
||
342 | |||
343 | if ($this->model instanceof Builder) { |
||
344 | $results = $this->model->get($columns); |
||
345 | } else { |
||
346 | $results = $this->model->all($columns); |
||
347 | } |
||
348 | |||
349 | $this->resetModel(); |
||
350 | $this->resetScope(); |
||
351 | |||
352 | return $this->parserResult($results); |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * Count results of repository |
||
357 | * |
||
358 | * @param array $where |
||
359 | * @param string $columns |
||
360 | * |
||
361 | * @return int |
||
362 | */ |
||
363 | public function count(array $where = [], $columns = '*') |
||
364 | { |
||
365 | $this->applyCriteria(); |
||
366 | $this->applyScope(); |
||
367 | |||
368 | if ($where) { |
||
369 | $this->applyConditions($where); |
||
370 | } |
||
371 | |||
372 | $result = $this->model->count($columns); |
||
373 | |||
374 | $this->resetModel(); |
||
375 | $this->resetScope(); |
||
376 | |||
377 | return $result; |
||
378 | } |
||
379 | |||
380 | /** |
||
381 | * Alias of All method |
||
382 | * |
||
383 | * @param array $columns |
||
384 | * |
||
385 | * @return mixed |
||
386 | */ |
||
387 | public function get($columns = ['*']) |
||
388 | { |
||
389 | return $this->all($columns); |
||
390 | } |
||
391 | |||
392 | /** |
||
393 | * Retrieve first data of repository |
||
394 | * |
||
395 | * @param array $columns |
||
396 | * |
||
397 | * @return mixed |
||
398 | */ |
||
399 | public function first($columns = ['*']) |
||
400 | { |
||
401 | $this->applyCriteria(); |
||
402 | $this->applyScope(); |
||
403 | |||
404 | $results = $this->model->first($columns); |
||
405 | |||
406 | $this->resetModel(); |
||
407 | |||
408 | return $this->parserResult($results); |
||
409 | } |
||
410 | |||
411 | /** |
||
412 | * Retrieve first data of repository, or return new Entity |
||
413 | * |
||
414 | * @param array $attributes |
||
415 | * |
||
416 | * @return mixed |
||
417 | */ |
||
418 | public function firstOrNew(array $attributes = []) |
||
419 | { |
||
420 | $this->applyCriteria(); |
||
421 | $this->applyScope(); |
||
422 | |||
423 | $temporarySkipPresenter = $this->skipPresenter; |
||
424 | $this->skipPresenter(true); |
||
425 | |||
426 | $model = $this->model->firstOrNew($attributes); |
||
427 | $this->skipPresenter($temporarySkipPresenter); |
||
428 | |||
429 | $this->resetModel(); |
||
430 | |||
431 | return $this->parserResult($model); |
||
432 | } |
||
433 | |||
434 | /** |
||
435 | * Retrieve first data of repository, or create new Entity |
||
436 | * |
||
437 | * @param array $attributes |
||
438 | * |
||
439 | * @return mixed |
||
440 | */ |
||
441 | public function firstOrCreate(array $attributes = []) |
||
442 | { |
||
443 | $this->applyCriteria(); |
||
444 | $this->applyScope(); |
||
445 | |||
446 | $temporarySkipPresenter = $this->skipPresenter; |
||
447 | $this->skipPresenter(true); |
||
448 | |||
449 | $model = $this->model->firstOrCreate($attributes); |
||
450 | $this->skipPresenter($temporarySkipPresenter); |
||
451 | |||
452 | $this->resetModel(); |
||
453 | |||
454 | return $this->parserResult($model); |
||
455 | } |
||
456 | |||
457 | /** |
||
458 | * Retrieve data of repository with limit applied |
||
459 | * |
||
460 | * @param int $limit |
||
461 | * @param array $columns |
||
462 | * |
||
463 | * @return mixed |
||
464 | */ |
||
465 | public function limit($limit, $columns = ['*']) |
||
466 | { |
||
467 | // Shortcut to all with `limit` applied on query via `take` |
||
468 | $this->take($limit); |
||
469 | |||
470 | return $this->all($columns); |
||
471 | } |
||
472 | |||
473 | /** |
||
474 | * Retrieve all data of repository, paginated |
||
475 | * |
||
476 | * @param null|int $limit |
||
477 | * @param array $columns |
||
478 | * @param string $method |
||
479 | * |
||
480 | * @return mixed |
||
481 | */ |
||
482 | public function paginate($limit = null, $columns = ['*'], $method = "paginate") |
||
483 | { |
||
484 | $this->applyCriteria(); |
||
485 | $this->applyScope(); |
||
486 | $limit = is_null($limit) ? config('domains.pagination.limit', 15) : $limit; |
||
487 | $results = $this->model->{$method}($limit, $columns); |
||
488 | $results->appends(app('request')->query()); |
||
489 | $this->resetModel(); |
||
490 | |||
491 | return $this->parserResult($results); |
||
492 | } |
||
493 | |||
494 | /** |
||
495 | * Retrieve all data of repository, simple paginated |
||
496 | * |
||
497 | * @param null|int $limit |
||
498 | * @param array $columns |
||
499 | * |
||
500 | * @return mixed |
||
501 | */ |
||
502 | public function simplePaginate($limit = null, $columns = ['*']) |
||
503 | { |
||
504 | return $this->paginate($limit, $columns, "simplePaginate"); |
||
505 | } |
||
506 | |||
507 | /** |
||
508 | * Find data by id |
||
509 | * |
||
510 | * @param $id |
||
511 | * @param array $columns |
||
512 | * |
||
513 | * @return mixed |
||
514 | */ |
||
515 | public function find($id, $columns = ['*']) |
||
516 | { |
||
517 | $this->applyCriteria(); |
||
518 | $this->applyScope(); |
||
519 | $model = $this->model->findOrFail($id, $columns); |
||
520 | $this->resetModel(); |
||
521 | |||
522 | return $this->parserResult($model); |
||
523 | } |
||
524 | |||
525 | /** |
||
526 | * Find data by field and value |
||
527 | * |
||
528 | * @param $field |
||
529 | * @param $value |
||
530 | * @param array $columns |
||
531 | * |
||
532 | * @return mixed |
||
533 | */ |
||
534 | public function findByField($field, $value = null, $columns = ['*']) |
||
535 | { |
||
536 | $this->applyCriteria(); |
||
537 | $this->applyScope(); |
||
538 | $model = $this->model->where($field, '=', $value)->get($columns); |
||
539 | $this->resetModel(); |
||
540 | |||
541 | return $this->parserResult($model); |
||
542 | } |
||
543 | |||
544 | /** |
||
545 | * Find data by multiple fields |
||
546 | * |
||
547 | * @param array $where |
||
548 | * @param array $columns |
||
549 | * |
||
550 | * @return mixed |
||
551 | */ |
||
552 | public function findWhere(array $where, $columns = ['*']) |
||
553 | { |
||
554 | $this->applyCriteria(); |
||
555 | $this->applyScope(); |
||
556 | |||
557 | $this->applyConditions($where); |
||
558 | |||
559 | $model = $this->model->get($columns); |
||
560 | $this->resetModel(); |
||
561 | |||
562 | return $this->parserResult($model); |
||
563 | } |
||
564 | |||
565 | /** |
||
566 | * Find data by multiple values in one field |
||
567 | * |
||
568 | * @param $field |
||
569 | * @param array $values |
||
570 | * @param array $columns |
||
571 | * |
||
572 | * @return mixed |
||
573 | */ |
||
574 | public function findWhereIn($field, array $values, $columns = ['*']) |
||
575 | { |
||
576 | $this->applyCriteria(); |
||
577 | $this->applyScope(); |
||
578 | $model = $this->model->whereIn($field, $values)->get($columns); |
||
579 | $this->resetModel(); |
||
580 | |||
581 | return $this->parserResult($model); |
||
582 | } |
||
583 | |||
584 | /** |
||
585 | * Find data by excluding multiple values in one field |
||
586 | * |
||
587 | * @param $field |
||
588 | * @param array $values |
||
589 | * @param array $columns |
||
590 | * |
||
591 | * @return mixed |
||
592 | */ |
||
593 | public function findWhereNotIn($field, array $values, $columns = ['*']) |
||
594 | { |
||
595 | $this->applyCriteria(); |
||
596 | $this->applyScope(); |
||
597 | $model = $this->model->whereNotIn($field, $values)->get($columns); |
||
598 | $this->resetModel(); |
||
599 | |||
600 | return $this->parserResult($model); |
||
601 | } |
||
602 | |||
603 | /** |
||
604 | * Find data by between values in one field |
||
605 | * |
||
606 | * @param $field |
||
607 | * @param array $values |
||
608 | * @param array $columns |
||
609 | * |
||
610 | * @return mixed |
||
611 | */ |
||
612 | public function findWhereBetween($field, array $values, $columns = ['*']) |
||
613 | { |
||
614 | $this->applyCriteria(); |
||
615 | $this->applyScope(); |
||
616 | $model = $this->model->whereBetween($field, $values)->get($columns); |
||
617 | $this->resetModel(); |
||
618 | |||
619 | return $this->parserResult($model); |
||
620 | } |
||
621 | |||
622 | /** |
||
623 | * Save a new entity in repository |
||
624 | * |
||
625 | * @param array $attributes |
||
626 | * |
||
627 | * @return mixed |
||
628 | * @throws ValidatorException |
||
629 | * |
||
630 | */ |
||
631 | public function create(array $attributes) |
||
632 | { |
||
633 | if (!is_null($this->validator)) { |
||
634 | // we should pass data that has been casts by the model |
||
635 | // to make sure data type are same because validator may need to use |
||
636 | // this data to compare with data that fetch from database. |
||
637 | if ($this->versionCompare($this->app->version(), "5.2.*", ">")) { |
||
638 | $attributes = $this->model->newInstance()->forceFill($attributes)->makeVisible($this->model->getHidden())->toArray(); |
||
639 | } else { |
||
640 | $model = $this->model->newInstance()->forceFill($attributes); |
||
641 | $model->makeVisible($this->model->getHidden()); |
||
642 | $attributes = $model->toArray(); |
||
643 | } |
||
644 | |||
645 | $this->validator->with($attributes)->passesOrFail(ValidatorInterface::RULE_CREATE); |
||
646 | } |
||
647 | |||
648 | event(new RepositoryEntityCreating($this, $attributes)); |
||
649 | |||
650 | $model = $this->model->newInstance($attributes); |
||
651 | $model->save(); |
||
652 | $this->resetModel(); |
||
653 | |||
654 | event(new RepositoryEntityCreated($this, $model)); |
||
655 | |||
656 | return $this->parserResult($model); |
||
657 | } |
||
658 | |||
659 | /** |
||
660 | * Update a entity in repository by id |
||
661 | * |
||
662 | * @param array $attributes |
||
663 | * @param $id |
||
664 | * |
||
665 | * @return mixed |
||
666 | * @throws ValidatorException |
||
667 | * |
||
668 | */ |
||
669 | public function update(array $attributes, $id) |
||
670 | { |
||
671 | $this->applyScope(); |
||
672 | |||
673 | if (!is_null($this->validator)) { |
||
674 | // we should pass data that has been casts by the model |
||
675 | // to make sure data type are same because validator may need to use |
||
676 | // this data to compare with data that fetch from database. |
||
677 | $model = $this->model->newInstance(); |
||
678 | $model->setRawAttributes([]); |
||
679 | $model->setAppends([]); |
||
680 | if ($this->versionCompare($this->app->version(), "5.2.*", ">")) { |
||
681 | $attributes = $model->forceFill($attributes)->makeVisible($this->model->getHidden())->toArray(); |
||
682 | } else { |
||
683 | $model->forceFill($attributes); |
||
684 | $model->makeVisible($this->model->getHidden()); |
||
685 | $attributes = $model->toArray(); |
||
686 | } |
||
687 | |||
688 | $this->validator->with($attributes)->setId($id)->passesOrFail(ValidatorInterface::RULE_UPDATE); |
||
689 | } |
||
690 | |||
691 | $temporarySkipPresenter = $this->skipPresenter; |
||
692 | |||
693 | $this->skipPresenter(true); |
||
694 | |||
695 | $model = $this->model->findOrFail($id); |
||
696 | |||
697 | event(new RepositoryEntityUpdating($this, $model)); |
||
698 | |||
699 | $model->fill($attributes); |
||
700 | $model->save(); |
||
701 | |||
702 | $this->skipPresenter($temporarySkipPresenter); |
||
703 | $this->resetModel(); |
||
704 | |||
705 | event(new RepositoryEntityUpdated($this, $model)); |
||
706 | |||
707 | return $this->parserResult($model); |
||
708 | } |
||
709 | |||
710 | /** |
||
711 | * Update or Create an entity in repository |
||
712 | * |
||
713 | * @param array $attributes |
||
714 | * @param array $values |
||
715 | * |
||
716 | * @return mixed |
||
717 | * @throws ValidatorException |
||
718 | * |
||
719 | */ |
||
720 | public function updateOrCreate(array $attributes, array $values = []) |
||
721 | { |
||
722 | $this->applyScope(); |
||
723 | |||
724 | if (!is_null($this->validator)) { |
||
725 | $this->validator->with(array_merge($attributes, $values))->passesOrFail(ValidatorInterface::RULE_CREATE); |
||
726 | } |
||
727 | |||
728 | $temporarySkipPresenter = $this->skipPresenter; |
||
729 | |||
730 | $this->skipPresenter(true); |
||
731 | |||
732 | event(new RepositoryEntityCreating($this, $attributes)); |
||
733 | |||
734 | $model = $this->model->updateOrCreate($attributes, $values); |
||
735 | |||
736 | $this->skipPresenter($temporarySkipPresenter); |
||
737 | $this->resetModel(); |
||
738 | |||
739 | event(new RepositoryEntityUpdated($this, $model)); |
||
740 | |||
741 | return $this->parserResult($model); |
||
742 | } |
||
743 | |||
744 | /** |
||
745 | * Delete a entity in repository by id |
||
746 | * |
||
747 | * @param $id |
||
748 | * |
||
749 | * @return int |
||
750 | */ |
||
751 | public function delete($id) |
||
752 | { |
||
753 | $this->applyScope(); |
||
754 | |||
755 | $temporarySkipPresenter = $this->skipPresenter; |
||
756 | $this->skipPresenter(true); |
||
757 | |||
758 | $model = $this->find($id); |
||
759 | $originalModel = clone $model; |
||
760 | |||
761 | $this->skipPresenter($temporarySkipPresenter); |
||
762 | $this->resetModel(); |
||
763 | |||
764 | event(new RepositoryEntityDeleting($this, $model)); |
||
765 | |||
766 | $deleted = $model->delete(); |
||
767 | |||
768 | event(new RepositoryEntityDeleted($this, $originalModel)); |
||
769 | |||
770 | return $deleted; |
||
771 | } |
||
772 | |||
773 | /** |
||
774 | * Delete multiple entities by given criteria. |
||
775 | * |
||
776 | * @param array $where |
||
777 | * |
||
778 | * @return int |
||
779 | */ |
||
780 | public function deleteWhere(array $where) |
||
781 | { |
||
782 | $this->applyScope(); |
||
783 | |||
784 | $temporarySkipPresenter = $this->skipPresenter; |
||
785 | $this->skipPresenter(true); |
||
786 | |||
787 | $this->applyConditions($where); |
||
788 | |||
789 | event(new RepositoryEntityDeleting($this, $this->model->getModel())); |
||
790 | |||
791 | $deleted = $this->model->delete(); |
||
792 | |||
793 | event(new RepositoryEntityDeleted($this, $this->model->getModel())); |
||
794 | |||
795 | $this->skipPresenter($temporarySkipPresenter); |
||
796 | $this->resetModel(); |
||
797 | |||
798 | return $deleted; |
||
799 | } |
||
800 | |||
801 | /** |
||
802 | * Check if entity has relation |
||
803 | * |
||
804 | * @param string $relation |
||
805 | * |
||
806 | * @return $this |
||
807 | */ |
||
808 | public function has($relation) |
||
809 | { |
||
810 | $this->model = $this->model->has($relation); |
||
811 | |||
812 | return $this; |
||
813 | } |
||
814 | |||
815 | /** |
||
816 | * Load relations |
||
817 | * |
||
818 | * @param array|string $relations |
||
819 | * |
||
820 | * @return $this |
||
821 | */ |
||
822 | public function with($relations) |
||
823 | { |
||
824 | $this->model = $this->model->with($relations); |
||
825 | |||
826 | return $this; |
||
827 | } |
||
828 | |||
829 | /** |
||
830 | * Add subselect queries to count the relations. |
||
831 | * |
||
832 | * @param mixed $relations |
||
833 | * |
||
834 | * @return $this |
||
835 | */ |
||
836 | public function withCount($relations) |
||
837 | { |
||
838 | $this->model = $this->model->withCount($relations); |
||
839 | return $this; |
||
840 | } |
||
841 | |||
842 | /** |
||
843 | * Load relation with closure |
||
844 | * |
||
845 | * @param string $relation |
||
846 | * @param closure $closure |
||
847 | * |
||
848 | * @return $this |
||
849 | */ |
||
850 | public function whereHas($relation, $closure) |
||
851 | { |
||
852 | $this->model = $this->model->whereHas($relation, $closure); |
||
853 | |||
854 | return $this; |
||
855 | } |
||
856 | |||
857 | /** |
||
858 | * Set hidden fields |
||
859 | * |
||
860 | * @param array $fields |
||
861 | * |
||
862 | * @return $this |
||
863 | */ |
||
864 | public function hidden(array $fields) |
||
865 | { |
||
866 | $this->model->setHidden($fields); |
||
867 | |||
868 | return $this; |
||
869 | } |
||
870 | |||
871 | /** |
||
872 | * Set the "orderBy" value of the query. |
||
873 | * |
||
874 | * @param mixed $column |
||
875 | * @param string $direction |
||
876 | * |
||
877 | * @return $this |
||
878 | */ |
||
879 | public function orderBy($column, $direction = 'asc') |
||
880 | { |
||
881 | $this->model = $this->model->orderBy($column, $direction); |
||
882 | |||
883 | return $this; |
||
884 | } |
||
885 | |||
886 | /** |
||
887 | * Set the "limit" value of the query. |
||
888 | * |
||
889 | * @param int $limit |
||
890 | * |
||
891 | * @return $this |
||
892 | */ |
||
893 | public function take($limit) |
||
894 | { |
||
895 | // Internally `take` is an alias to `limit` |
||
896 | $this->model = $this->model->limit($limit); |
||
897 | |||
898 | return $this; |
||
899 | } |
||
900 | |||
901 | /** |
||
902 | * Set visible fields |
||
903 | * |
||
904 | * @param array $fields |
||
905 | * |
||
906 | * @return $this |
||
907 | */ |
||
908 | public function visible(array $fields) |
||
909 | { |
||
910 | $this->model->setVisible($fields); |
||
911 | |||
912 | return $this; |
||
913 | } |
||
914 | |||
915 | /** |
||
916 | * Push Criteria for filter the query |
||
917 | * |
||
918 | * @param $criteria |
||
919 | * |
||
920 | * @return $this |
||
921 | * @throws \Salah3id\Domains\Repository\Exceptions\RepositoryException |
||
922 | */ |
||
923 | public function pushCriteria($criteria) |
||
924 | { |
||
925 | if (is_string($criteria)) { |
||
926 | $criteria = new $criteria; |
||
927 | } |
||
928 | if (!$criteria instanceof CriteriaInterface) { |
||
929 | throw new RepositoryException("Class " . get_class($criteria) . " must be an instance of Salah3id\Domains\\Repository\\Contracts\\CriteriaInterface"); |
||
930 | } |
||
931 | $this->criteria->push($criteria); |
||
932 | |||
933 | return $this; |
||
934 | } |
||
935 | |||
936 | /** |
||
937 | * Pop Criteria |
||
938 | * |
||
939 | * @param $criteria |
||
940 | * |
||
941 | * @return $this |
||
942 | */ |
||
943 | public function popCriteria($criteria) |
||
944 | { |
||
945 | $this->criteria = $this->criteria->reject(function ($item) use ($criteria) { |
||
946 | if (is_object($item) && is_string($criteria)) { |
||
947 | return get_class($item) === $criteria; |
||
948 | } |
||
949 | |||
950 | if (is_string($item) && is_object($criteria)) { |
||
951 | return $item === get_class($criteria); |
||
952 | } |
||
953 | |||
954 | return get_class($item) === get_class($criteria); |
||
955 | }); |
||
956 | |||
957 | return $this; |
||
958 | } |
||
959 | |||
960 | /** |
||
961 | * Get Collection of Criteria |
||
962 | * |
||
963 | * @return Collection |
||
964 | */ |
||
965 | public function getCriteria() |
||
968 | } |
||
969 | |||
970 | /** |
||
971 | * Find data by Criteria |
||
972 | * |
||
973 | * @param CriteriaInterface $criteria |
||
974 | * |
||
975 | * @return mixed |
||
976 | */ |
||
977 | public function getByCriteria(CriteriaInterface $criteria) |
||
978 | { |
||
979 | $this->model = $criteria->apply($this->model, $this); |
||
980 | $results = $this->model->get(); |
||
981 | $this->resetModel(); |
||
982 | |||
983 | return $this->parserResult($results); |
||
984 | } |
||
985 | |||
986 | /** |
||
987 | * Skip Criteria |
||
988 | * |
||
989 | * @param bool $status |
||
990 | * |
||
991 | * @return $this |
||
992 | */ |
||
993 | public function skipCriteria($status = true) |
||
994 | { |
||
995 | $this->skipCriteria = $status; |
||
996 | |||
997 | return $this; |
||
998 | } |
||
999 | |||
1000 | /** |
||
1001 | * Reset all Criterias |
||
1002 | * |
||
1003 | * @return $this |
||
1004 | */ |
||
1005 | public function resetCriteria() |
||
1006 | { |
||
1007 | $this->criteria = new Collection(); |
||
1008 | |||
1009 | return $this; |
||
1010 | } |
||
1011 | |||
1012 | /** |
||
1013 | * Reset Query Scope |
||
1014 | * |
||
1015 | * @return $this |
||
1016 | */ |
||
1017 | public function resetScope() |
||
1018 | { |
||
1019 | $this->scopeQuery = null; |
||
1020 | |||
1021 | return $this; |
||
1022 | } |
||
1023 | |||
1024 | /** |
||
1025 | * Apply scope in current Query |
||
1026 | * |
||
1027 | * @return $this |
||
1028 | */ |
||
1029 | protected function applyScope() |
||
1030 | { |
||
1031 | if (isset($this->scopeQuery) && is_callable($this->scopeQuery)) { |
||
1032 | $callback = $this->scopeQuery; |
||
1033 | $this->model = $callback($this->model); |
||
1034 | } |
||
1035 | |||
1036 | return $this; |
||
1037 | } |
||
1038 | |||
1039 | /** |
||
1040 | * Apply criteria in current Query |
||
1041 | * |
||
1042 | * @return $this |
||
1043 | */ |
||
1044 | protected function applyCriteria() |
||
1045 | { |
||
1046 | if ($this->skipCriteria === true) { |
||
1047 | return $this; |
||
1048 | } |
||
1049 | |||
1050 | $criteria = $this->getCriteria(); |
||
1051 | |||
1052 | if ($criteria) { |
||
1053 | foreach ($criteria as $c) { |
||
1054 | if ($c instanceof CriteriaInterface) { |
||
1055 | $this->model = $c->apply($this->model, $this); |
||
1056 | } |
||
1057 | } |
||
1058 | } |
||
1059 | |||
1060 | return $this; |
||
1061 | } |
||
1062 | |||
1063 | /** |
||
1064 | * Applies the given where conditions to the model. |
||
1065 | * |
||
1066 | * @param array $where |
||
1067 | * |
||
1068 | * @return void |
||
1069 | */ |
||
1070 | protected function applyConditions(array $where) |
||
1071 | { |
||
1072 | foreach ($where as $field => $value) { |
||
1073 | if (is_array($value)) { |
||
1074 | list($field, $condition, $val) = $value; |
||
1075 | //smooth input |
||
1076 | $condition = preg_replace('/\s\s+/', ' ', trim($condition)); |
||
1077 | |||
1078 | //split to get operator, syntax: "DATE >", "DATE =", "DAY <" |
||
1079 | $operator = explode(' ', $condition); |
||
1080 | if (count($operator) > 1) { |
||
1081 | $condition = $operator[0]; |
||
1082 | $operator = $operator[1]; |
||
1083 | } else $operator = null; |
||
1084 | switch (strtoupper($condition)) { |
||
1085 | case 'IN': |
||
1086 | if (!is_array($val)) throw new RepositoryException("Input {$val} mus be an array"); |
||
1087 | $this->model = $this->model->whereIn($field, $val); |
||
1088 | break; |
||
1089 | case 'NOTIN': |
||
1090 | if (!is_array($val)) throw new RepositoryException("Input {$val} mus be an array"); |
||
1091 | $this->model = $this->model->whereNotIn($field, $val); |
||
1092 | break; |
||
1093 | case 'DATE': |
||
1094 | if (!$operator) $operator = '='; |
||
1095 | $this->model = $this->model->whereDate($field, $operator, $val); |
||
1096 | break; |
||
1097 | case 'DAY': |
||
1098 | if (!$operator) $operator = '='; |
||
1099 | $this->model = $this->model->whereDay($field, $operator, $val); |
||
1100 | break; |
||
1101 | case 'MONTH': |
||
1102 | if (!$operator) $operator = '='; |
||
1103 | $this->model = $this->model->whereMonth($field, $operator, $val); |
||
1104 | break; |
||
1105 | case 'YEAR': |
||
1106 | if (!$operator) $operator = '='; |
||
1107 | $this->model = $this->model->whereYear($field, $operator, $val); |
||
1108 | break; |
||
1109 | case 'EXISTS': |
||
1110 | if (!($val instanceof Closure)) throw new RepositoryException("Input {$val} must be closure function"); |
||
1111 | $this->model = $this->model->whereExists($val); |
||
1112 | break; |
||
1113 | case 'HAS': |
||
1114 | if (!($val instanceof Closure)) throw new RepositoryException("Input {$val} must be closure function"); |
||
1115 | $this->model = $this->model->whereHas($field, $val); |
||
1116 | break; |
||
1117 | case 'HASMORPH': |
||
1118 | if (!($val instanceof Closure)) throw new RepositoryException("Input {$val} must be closure function"); |
||
1119 | $this->model = $this->model->whereHasMorph($field, $val); |
||
1120 | break; |
||
1121 | case 'DOESNTHAVE': |
||
1122 | if (!($val instanceof Closure)) throw new RepositoryException("Input {$val} must be closure function"); |
||
1123 | $this->model = $this->model->whereDoesntHave($field, $val); |
||
1124 | break; |
||
1125 | case 'DOESNTHAVEMORPH': |
||
1126 | if (!($val instanceof Closure)) throw new RepositoryException("Input {$val} must be closure function"); |
||
1127 | $this->model = $this->model->whereDoesntHaveMorph($field, $val); |
||
1128 | break; |
||
1129 | case 'BETWEEN': |
||
1130 | if (!is_array($val)) throw new RepositoryException("Input {$val} mus be an array"); |
||
1131 | $this->model = $this->model->whereBetween($field, $val); |
||
1132 | break; |
||
1133 | case 'BETWEENCOLUMNS': |
||
1134 | if (!is_array($val)) throw new RepositoryException("Input {$val} mus be an array"); |
||
1135 | $this->model = $this->model->whereBetweenColumns($field, $val); |
||
1136 | break; |
||
1137 | case 'NOTBETWEEN': |
||
1138 | if (!is_array($val)) throw new RepositoryException("Input {$val} mus be an array"); |
||
1139 | $this->model = $this->model->whereNotBetween($field, $val); |
||
1140 | break; |
||
1141 | case 'NOTBETWEENCOLUMNS': |
||
1142 | if (!is_array($val)) throw new RepositoryException("Input {$val} mus be an array"); |
||
1143 | $this->model = $this->model->whereNotBetweenColumns($field, $val); |
||
1144 | break; |
||
1145 | case 'RAW': |
||
1146 | $this->model = $this->model->whereRaw($val); |
||
1147 | break; |
||
1148 | default: |
||
1149 | $this->model = $this->model->where($field, $condition, $val); |
||
1150 | } |
||
1151 | } else { |
||
1152 | $this->model = $this->model->where($field, '=', $value); |
||
1153 | } |
||
1154 | } |
||
1155 | } |
||
1156 | |||
1157 | /** |
||
1158 | * Skip Presenter Wrapper |
||
1159 | * |
||
1160 | * @param bool $status |
||
1161 | * |
||
1162 | * @return $this |
||
1163 | */ |
||
1164 | public function skipPresenter($status = true) |
||
1165 | { |
||
1166 | $this->skipPresenter = $status; |
||
1167 | |||
1168 | return $this; |
||
1169 | } |
||
1170 | |||
1171 | /** |
||
1172 | * Wrapper result data |
||
1173 | * |
||
1174 | * @param mixed $result |
||
1175 | * |
||
1176 | * @return mixed |
||
1177 | */ |
||
1178 | public function parserResult($result) |
||
1179 | { |
||
1180 | if ($this->presenter instanceof PresenterInterface) { |
||
1181 | if ($result instanceof Collection || $result instanceof LengthAwarePaginator) { |
||
1182 | $result->each(function ($model) { |
||
1183 | if ($model instanceof Presentable) { |
||
1184 | $model->setPresenter($this->presenter); |
||
1185 | } |
||
1186 | |||
1187 | return $model; |
||
1188 | }); |
||
1189 | } else if ($result instanceof Presentable) { |
||
1190 | $result = $result->setPresenter($this->presenter); |
||
1191 | } |
||
1192 | |||
1193 | if (!$this->skipPresenter) { |
||
1194 | return $this->presenter->present($result); |
||
1195 | } |
||
1196 | } |
||
1197 | |||
1198 | return $result; |
||
1199 | } |
||
1200 | |||
1201 | /** |
||
1202 | * Trigger static method calls to the model |
||
1203 | * |
||
1204 | * @param $method |
||
1205 | * @param $arguments |
||
1206 | * |
||
1207 | * @return mixed |
||
1208 | */ |
||
1209 | public static function __callStatic($method, $arguments) |
||
1210 | { |
||
1211 | return call_user_func_array([new static(), $method], $arguments); |
||
1212 | } |
||
1213 | |||
1214 | /** |
||
1215 | * Trigger method calls to the model |
||
1216 | * |
||
1217 | * @param string $method |
||
1218 | * @param array $arguments |
||
1219 | * |
||
1220 | * @return mixed |
||
1221 | */ |
||
1222 | public function __call($method, $arguments) |
||
1228 | } |
||
1229 | } |
||
1230 |