Completed
Push — develop ( 16c0cd...e690ae )
by Abdelrahman
01:31
created

BaseRepository::scope()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
rs 9.4285
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
3
/*
4
 * NOTICE OF LICENSE
5
 *
6
 * Part of the Rinvex Repository Package.
7
 *
8
 * This source file is subject to The MIT License (MIT)
9
 * that is bundled with this package in the LICENSE file.
10
 *
11
 * Package: Rinvex Repository Package
12
 * License: The MIT License (MIT)
13
 * Link:    https://rinvex.com
14
 */
15
16
namespace Rinvex\Repository\Repositories;
17
18
use Closure;
19
use Rinvex\Repository\Traits\Cacheable;
20
use Illuminate\Contracts\Container\Container;
21
use Rinvex\Repository\Contracts\CacheableContract;
22
use Rinvex\Repository\Contracts\RepositoryContract;
23
24
abstract class BaseRepository implements RepositoryContract, CacheableContract
25
{
26
    use Cacheable;
27
28
    /**
29
     * The IoC container instance.
30
     *
31
     * @var \Illuminate\Contracts\Container\Container
32
     */
33
    protected $container;
34
35
    /**
36
     * The connection name for the repository.
37
     *
38
     * @var string
39
     */
40
    protected $connection;
41
42
    /**
43
     * The repository identifier.
44
     *
45
     * @var string
46
     */
47
    protected $repositoryId;
48
49
    /**
50
     * The repository model.
51
     *
52
     * @var string
53
     */
54
    protected $model;
55
56
    /**
57
     * The relations to eager load on query execution.
58
     *
59
     * @var array
60
     */
61
    protected $relations = [];
62
63
    /**
64
     * The query where clauses.
65
     *
66
     * @var array
67
     */
68
    protected $where = [];
69
70
    /**
71
     * The query whereIn clauses.
72
     *
73
     * @var array
74
     */
75
    protected $whereIn = [];
76
77
    /**
78
     * The query whereNotIn clauses.
79
     *
80
     * @var array
81
     */
82
    protected $whereNotIn = [];
83
84
    /**
85
     * The query whereHas clauses.
86
     *
87
     * @var array
88
     */
89
    protected $whereHas = [];
90
91
    /**
92
     * The query scopes.
93
     *
94
     * @var array
95
     */
96
    protected $scopes = [];
97
98
    /**
99
     * The "offset" value of the query.
100
     *
101
     * @var int
102
     */
103
    protected $offset;
104
105
    /**
106
     * The "limit" value of the query.
107
     *
108
     * @var int
109
     */
110
    protected $limit;
111
112
    /**
113
     * The column to order results by.
114
     *
115
     * @var array
116
     */
117
    protected $orderBy = [];
118
119
    /**
120
     * The column to order results by.
121
     *
122
     * @var array
123
     */
124
    protected $groupBy = [];
125
126
    /**
127
     * The query having clauses.
128
     *
129
     * @var array
130
     */
131
    protected $having = [];
132
133
    /**
134
     * Execute given callback and return the result.
135
     *
136
     * @param string   $class
137
     * @param string   $method
138
     * @param array    $args
139
     * @param \Closure $closure
140
     *
141
     * @return mixed
142
     */
143
    protected function executeCallback($class, $method, $args, Closure $closure)
144
    {
145
        $skipUri = $this->getContainer('config')->get('rinvex.repository.cache.skip_uri');
146
147
        // Check if cache is enabled
148
        if ($this->getCacheLifetime() && ! $this->getContainer('request')->has($skipUri)) {
149
            return $this->cacheCallback($class, $method, $args, $closure);
150
        }
151
152
        // Cache disabled, just execute query & return result
153
        $result = call_user_func($closure);
154
155
        // We're done, let's clean up!
156
        $this->resetRepository();
157
158
        return $result;
159
    }
160
161
    /**
162
     * Reset repository to its defaults.
163
     *
164
     * @return $this
165
     */
166
    protected function resetRepository()
167
    {
168
        $this->relations = [];
169
        $this->where = [];
170
        $this->whereIn = [];
171
        $this->whereNotIn = [];
172
        $this->whereHas = [];
173
        $this->scopes = [];
174
        $this->offset = null;
175
        $this->limit = null;
176
        $this->orderBy = [];
177
        $this->groupBy = [];
178
        $this->having = [];
179
180
        if (method_exists($this, 'flushCriteria')) {
181
            $this->flushCriteria();
0 ignored issues
show
Documentation Bug introduced by
The method flushCriteria does not exist on object<Rinvex\Repository...itories\BaseRepository>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
182
        }
183
184
        return $this;
185
    }
186
187
    /**
188
     * Prepare query.
189
     *
190
     * @param object $model
191
     *
192
     * @return mixed
193
     */
194
    protected function prepareQuery($model)
195
    {
196
        // Set the relationships that should be eager loaded
197
        if (! empty($this->relations)) {
198
            $model = $model->with($this->relations);
199
        }
200
201
        // Add a basic where clause to the query
202
        foreach ($this->where as $where) {
203
            list($attribute, $operator, $value, $boolean) = array_pad($where, 4, null);
204
205
            $model = $model->where($attribute, $operator, $value, $boolean);
206
        }
207
208
        // Add a "where in" clause to the query
209
        foreach ($this->whereIn as $whereIn) {
210
            list($attribute, $values, $boolean, $not) = array_pad($whereIn, 4, null);
211
212
            $model = $model->whereIn($attribute, $values, $boolean, $not);
213
        }
214
215
        // Add a "where not in" clause to the query
216
        foreach ($this->whereNotIn as $whereNotIn) {
217
            list($attribute, $values, $boolean) = array_pad($whereNotIn, 3, null);
218
219
            $model = $model->whereNotIn($attribute, $values, $boolean);
220
        }
221
222
        // Add a "where has" clause to the query
223
        foreach ($this->whereHas as $whereHas) {
224
            list($relation, $callback, $operator, $count) = array_pad($whereHas, 4, null);
225
226
            $model = $model->whereHas($relation, $callback, $operator, $count);
227
        }
228
229
        // Add a "scope" to the query
230
        foreach ($this->scopes as $scope => $parameters) {
231
            $model = $model->$scope(...$parameters);
232
        }
233
234
        // Set the "offset" value of the query
235
        if ($this->offset > 0) {
236
            $model = $model->offset($this->offset);
237
        }
238
239
        // Set the "limit" value of the query
240
        if ($this->limit > 0) {
241
            $model = $model->limit($this->limit);
242
        }
243
244
        // Add an "order by" clause to the query.
245
        foreach ($this->orderBy as $orderBy) {
246
            list($attribute, $direction) = $orderBy;
247
248
            $model = $model->orderBy($attribute, $direction);
249
        }
250
251
        // Add an "group by" clause to the query.
252
        if (! empty($this->groupBy)) {
253
            foreach ($this->groupBy as $group) {
254
                $model = $model->groupBy($group);
255
            }
256
        }
257
258
        // Add a "having" clause to the query
259
        foreach ($this->having as $having) {
260
            list($column, $operator, $value, $boolean) = array_pad($having, 4, null);
261
262
            $model = $model->having($column, $operator, $value, $boolean);
263
        }
264
265
        // Apply all criteria to the query
266
        if (method_exists($this, 'applyCriteria')) {
267
            $model = $this->applyCriteria($model, $this);
0 ignored issues
show
Documentation Bug introduced by
The method applyCriteria does not exist on object<Rinvex\Repository...itories\BaseRepository>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
268
        }
269
270
        return $model;
271
    }
272
273
    /**
274
     * {@inheritdoc}
275
     */
276
    public function setContainer(Container $container)
277
    {
278
        $this->container = $container;
279
280
        return $this;
281
    }
282
283
    /**
284
     * {@inheritdoc}
285
     */
286
    public function getContainer($service = null)
287
    {
288
        return is_null($service) ? ($this->container ?: app()) : ($this->container[$service] ?: app($service));
289
    }
290
291
    /**
292
     * {@inheritdoc}
293
     */
294
    public function setConnection($name)
295
    {
296
        $this->connection = $name;
297
298
        return $this;
299
    }
300
301
    /**
302
     * {@inheritdoc}
303
     */
304
    public function getConnection()
305
    {
306
        return $this->connection;
307
    }
308
309
    /**
310
     * {@inheritdoc}
311
     */
312
    public function setRepositoryId($repositoryId)
313
    {
314
        $this->repositoryId = $repositoryId;
315
316
        return $this;
317
    }
318
319
    /**
320
     * {@inheritdoc}
321
     */
322
    public function getRepositoryId()
323
    {
324
        return $this->repositoryId ?: get_called_class();
325
    }
326
327
    /**
328
     * {@inheritdoc}
329
     */
330
    public function setModel($model)
331
    {
332
        $this->model = $model;
333
334
        return $this;
335
    }
336
337
    /**
338
     * {@inheritdoc}
339
     */
340
    public function getModel()
341
    {
342
        $model = $this->getContainer('config')->get('rinvex.repository.models');
343
344
        return $this->model ?: str_replace(['Repositories', 'Repository'], [$model, ''], get_called_class());
345
    }
346
347
    /**
348
     * {@inheritdoc}
349
     */
350
    public function with($relations)
351
    {
352
        if (is_string($relations)) {
353
            $relations = func_get_args();
354
        }
355
356
        $this->relations = $relations;
357
358
        return $this;
359
    }
360
361
    /**
362
     * {@inheritdoc}
363
     */
364
    public function where($attribute, $operator = null, $value = null, $boolean = 'and')
365
    {
366
        // The last `$boolean` expression is intentional to fix list() & array_pad() results
367
        $this->where[] = [$attribute, $operator, $value, $boolean ?: 'and'];
368
369
        return $this;
370
    }
371
372
    /**
373
     * {@inheritdoc}
374
     */
375
    public function whereIn($attribute, $values, $boolean = 'and', $not = false)
376
    {
377
        // The last `$boolean` & `$not` expressions are intentional to fix list() & array_pad() results
378
        $this->whereIn[] = [$attribute, $values, $boolean ?: 'and', (bool) $not];
379
380
        return $this;
381
    }
382
383
    /**
384
     * {@inheritdoc}
385
     */
386
    public function whereNotIn($attribute, $values, $boolean = 'and')
387
    {
388
        // The last `$boolean` expression is intentional to fix list() & array_pad() results
389
        $this->whereNotIn[] = [$attribute, $values, $boolean ?: 'and'];
390
391
        return $this;
392
    }
393
394
    /**
395
     * {@inheritdoc}
396
     */
397
    public function whereHas($relation, Closure $callback = null, $operator = '>=', $count = 1)
398
    {
399
        // The last `$operator` & `$count` expressions are intentional to fix list() & array_pad() results
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
400
        $this->whereHas[] = [$relation, $callback, $operator ?: '>=', $count ?: 1];
401
402
        return $this;
403
    }
404
405
    /**
406
     * {@inheritdoc}
407
     */
408
    public function scope($name, array $parameters = [])
409
    {
410
        $this->scopes[$name] = $parameters;
411
412
        return $this;
413
    }
414
415
    /**
416
     * {@inheritdoc}
417
     */
418
    public function offset($offset)
419
    {
420
        $this->offset = $offset;
421
422
        return $this;
423
    }
424
425
    /**
426
     * {@inheritdoc}
427
     */
428
    public function limit($limit)
429
    {
430
        $this->limit = $limit;
431
432
        return $this;
433
    }
434
435
    /**
436
     * {@inheritdoc}
437
     */
438
    public function orderBy($attribute, $direction = 'asc')
439
    {
440
        $this->orderBy[] = [$attribute, $direction ?: 'asc'];
441
442
        return $this;
443
    }
444
445
    /**
446
     * {@inheritdoc}
447
     */
448
    public function groupBy($column)
449
    {
450
        $this->groupBy = array_merge((array) $this->groupBy, is_array($column) ? $column : [$column]);
451
452
        return $this;
453
    }
454
455
    /**
456
     * {@inheritdoc}
457
     */
458
    public function having($column, $operator = null, $value = null, $boolean = 'and')
459
    {
460
        $this->having[] = [$column, $operator, $value, $boolean ?: 'and'];
461
462
        return $this;
463
    }
464
465
    /**
466
     * {@inheritdoc}
467
     */
468
    public function orHaving($column, $operator = null, $value = null, $boolean = 'and')
469
    {
470
        return $this->having($column, $operator, $value, 'or');
471
    }
472
473
    /**
474
     * {@inheritdoc}
475
     */
476
    public function store($id, array $attributes = [])
477
    {
478
        return ! $id ? $this->create($attributes) : $this->update($id, $attributes);
479
    }
480
481
    /**
482
     * {@inheritdoc}
483
     */
484
    public static function __callStatic($method, $parameters)
485
    {
486
        return call_user_func_array([new static(), $method], $parameters);
487
    }
488
489
    /**
490
     * {@inheritdoc}
491
     */
492
    public function __call($method, $parameters)
493
    {
494
        if (method_exists($model = $this->createModel(), $scope = 'scope'.ucfirst($method))) {
495
            $this->scope($method, $parameters);
496
497
            return $this;
498
        }
499
500
        return call_user_func_array([$this->createModel(), $method], $parameters);
501
    }
502
}
503