Completed
Pull Request — master (#193)
by
unknown
02:18 queued 51s
created

BaseRepository::where()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $operator does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $value does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $boolean does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
206
207
            $model = $model->where($attribute, $operator, $value, $boolean);
208
        }
209
210
        // Add a "where in" clause to the query
211
        foreach ($this->whereIn as $whereIn) {
212
            [$attribute, $values, $boolean, $not] = array_pad($whereIn, 4, null);
0 ignored issues
show
Bug introduced by
The variable $values does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $not does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
213
214
            $model = $model->whereIn($attribute, $values, $boolean, $not);
215
        }
216
217
        // Add a "where not in" clause to the query
218
        foreach ($this->whereNotIn as $whereNotIn) {
219
            [$attribute, $values, $boolean] = array_pad($whereNotIn, 3, null);
220
221
            $model = $model->whereNotIn($attribute, $values, $boolean);
222
        }
223
224
        // Add a "where has" clause to the query
225
        foreach ($this->whereHas as $whereHas) {
226
            [$relation, $callback, $operator, $count] = array_pad($whereHas, 4, null);
0 ignored issues
show
Bug introduced by
The variable $relation does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $callback does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $count does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
227
228
            $model = $model->whereHas($relation, $callback, $operator, $count);
229
        }
230
231
        // Add a "scope" to the query
232
        foreach ($this->scopes as $scope => $parameters) {
233
            $model = $model->{$scope}(...$parameters);
234
        }
235
236
        // Set the "offset" value of the query
237
        if ($this->offset > 0) {
238
            $model = $model->offset($this->offset);
239
        }
240
241
        // Set the "limit" value of the query
242
        if ($this->limit > 0) {
243
            $model = $model->limit($this->limit);
244
        }
245
246
        // Add an "order by" clause to the query.
247
        foreach ($this->orderBy as $orderBy) {
248
            [$attribute, $direction] = $orderBy;
0 ignored issues
show
Bug introduced by
The variable $direction does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
249
250
            $model = $model->orderBy($attribute, $direction);
251
        }
252
253
        // Add an "group by" clause to the query.
254
        if (! empty($this->groupBy)) {
255
            foreach ($this->groupBy as $group) {
256
                $model = $model->groupBy($group);
257
            }
258
        }
259
260
        // Add a "having" clause to the query
261
        foreach ($this->having as $having) {
262
            [$column, $operator, $value, $boolean] = array_pad($having, 4, null);
0 ignored issues
show
Bug introduced by
The variable $column does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
263
264
            $model = $model->having($column, $operator, $value, $boolean);
265
        }
266
267
        // Apply all criteria to the query
268
        if (method_exists($this, 'applyCriteria')) {
269
            $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...
270
        }
271
272
        return $model;
273
    }
274
275
    /**
276
     * {@inheritdoc}
277
     */
278
    public function setContainer(Container $container)
279
    {
280
        $this->container = $container;
281
282
        return $this;
283
    }
284
285
    /**
286
     * {@inheritdoc}
287
     */
288
    public function getContainer($service = null)
289
    {
290
        return is_null($service) ? ($this->container ?: app()) : ($this->container[$service] ?: app($service));
291
    }
292
293
    /**
294
     * {@inheritdoc}
295
     */
296
    public function setConnection($name)
297
    {
298
        $this->connection = $name;
299
300
        return $this;
301
    }
302
303
    /**
304
     * {@inheritdoc}
305
     */
306
    public function getConnection(): string
307
    {
308
        return $this->connection;
309
    }
310
311
    /**
312
     * {@inheritdoc}
313
     */
314
    public function setRepositoryId($repositoryId)
315
    {
316
        $this->repositoryId = $repositoryId;
317
318
        return $this;
319
    }
320
321
    /**
322
     * {@inheritdoc}
323
     */
324
    public function getRepositoryId(): string
325
    {
326
        return $this->repositoryId ?: static::class;
327
    }
328
329
    /**
330
     * {@inheritdoc}
331
     */
332
    public function setModel($model)
333
    {
334
        $this->model = $model;
335
336
        return $this;
337
    }
338
339
    /**
340
     * {@inheritdoc}
341
     */
342
    public function getModel(): string
343
    {
344
        $model = $this->getContainer('config')->get('rinvex.repository.models');
345
346
        return $this->model ?: str_replace(['Repositories', 'Repository'], [$model, ''], static::class);
347
    }
348
349
    /**
350
     * {@inheritdoc}
351
     */
352
    public function with($relations)
353
    {
354
        if (is_string($relations)) {
355
            $relations = func_get_args();
356
        }
357
358
        $this->relations = $relations;
359
360
        return $this;
361
    }
362
363
    /**
364
     * {@inheritdoc}
365
     */
366
    public function withCount($countRelations)
367
    {
368
        if (is_string($countRelations)) {
369
            $countRelations = func_get_args();
370
        }
371
372
        $this->countRelations = $countRelations;
373
374
        return $this;
375
    }
376
377
    /**
378
     * {@inheritdoc}
379
     */
380
    public function where($attribute, $operator = null, $value = null, $boolean = 'and')
381
    {
382
        // The last `$boolean` expression is intentional to fix list() & array_pad() results
383
        $this->where[] = [$attribute, $operator, $value, $boolean ?: 'and'];
384
385
        return $this;
386
    }
387
388
    /**
389
     * {@inheritdoc}
390
     */
391
    public function whereIn($attribute, $values, $boolean = 'and', $not = false)
392
    {
393
        // The last `$boolean` & `$not` expressions are intentional to fix list() & array_pad() results
394
        $this->whereIn[] = [$attribute, $values, $boolean ?: 'and', (bool) $not];
395
396
        return $this;
397
    }
398
399
    /**
400
     * {@inheritdoc}
401
     */
402
    public function whereNotIn($attribute, $values, $boolean = 'and')
403
    {
404
        // The last `$boolean` expression is intentional to fix list() & array_pad() results
405
        $this->whereNotIn[] = [$attribute, $values, $boolean ?: 'and'];
406
407
        return $this;
408
    }
409
410
    /**
411
     * {@inheritdoc}
412
     */
413
    public function whereHas($relation, Closure $callback = null, $operator = '>=', $count = 1)
414
    {
415
        // 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...
416
        $this->whereHas[] = [$relation, $callback, $operator ?: '>=', $count ?: 1];
417
418
        return $this;
419
    }
420
421
    /**
422
     * {@inheritdoc}
423
     */
424
    public function scope($name, array $parameters = [])
425
    {
426
        $this->scopes[$name] = $parameters;
427
428
        return $this;
429
    }
430
431
    /**
432
     * {@inheritdoc}
433
     */
434
    public function offset($offset)
435
    {
436
        $this->offset = $offset;
437
438
        return $this;
439
    }
440
441
    /**
442
     * {@inheritdoc}
443
     */
444
    public function limit($limit)
445
    {
446
        $this->limit = $limit;
447
448
        return $this;
449
    }
450
451
    /**
452
     * {@inheritdoc}
453
     */
454
    public function orderBy($attribute, $direction = 'asc')
455
    {
456
        $this->orderBy[] = [$attribute, $direction ?: 'asc'];
457
458
        return $this;
459
    }
460
461
    /**
462
     * {@inheritdoc}
463
     */
464
    public function groupBy($column)
465
    {
466
        $this->groupBy = array_merge((array) $this->groupBy, is_array($column) ? $column : [$column]);
467
468
        return $this;
469
    }
470
471
    /**
472
     * {@inheritdoc}
473
     */
474
    public function having($column, $operator = null, $value = null, $boolean = 'and')
475
    {
476
        $this->having[] = [$column, $operator, $value, $boolean ?: 'and'];
477
478
        return $this;
479
    }
480
481
    /**
482
     * {@inheritdoc}
483
     */
484
    public function orHaving($column, $operator = null, $value = null, $boolean = 'and')
485
    {
486
        return $this->having($column, $operator, $value, 'or');
487
    }
488
489
    /**
490
     * {@inheritdoc}
491
     */
492
    public function store($id, array $attributes = [], bool $syncRelations = false)
493
    {
494
        return ! $id ? $this->create($attributes, $syncRelations) : $this->update($id, $attributes, $syncRelations);
495
    }
496
497
    /**
498
     * {@inheritdoc}
499
     */
500
    public static function __callStatic($method, $parameters)
501
    {
502
        return call_user_func_array([new static(), $method], $parameters);
503
    }
504
505
    /**
506
     * {@inheritdoc}
507
     */
508
    public function __call($method, $parameters)
509
    {
510
        if (method_exists($model = $this->createModel(), $scope = 'scope'.ucfirst($method))) {
511
            $this->scope($method, $parameters);
512
513
            return $this;
514
        }
515
516
        return call_user_func_array([$this->createModel(), $method], $parameters);
517
    }
518
}
519