Completed
Pull Request — develop (#89)
by Ionut
02:42
created

BaseRepository::prepareQuery()   F

Complexity

Conditions 11
Paths 1024

Size

Total Lines 66
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 66
c 0
b 0
f 0
rs 3.8028
cc 11
eloc 28
nc 1024
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 "offset" value of the query.
93
     *
94
     * @var int
95
     */
96
    protected $offset;
97
98
    /**
99
     * The "limit" value of the query.
100
     *
101
     * @var int
102
     */
103
    protected $limit;
104
105
    /**
106
     * The column to order results by.
107
     *
108
     * @var array
109
     */
110
    protected $orderBy = [];
111
112
    /**
113
     * The query having clauses.
114
     *
115
     * @var array
116
     */
117
    protected $having = [];
118
119
    /**
120
     * Execute given callback and return the result.
121
     *
122
     * @param string   $class
123
     * @param string   $method
124
     * @param array    $args
125
     * @param \Closure $closure
126
     *
127
     * @return mixed
128
     */
129
    protected function executeCallback($class, $method, $args, Closure $closure)
130
    {
131
        $skipUri = $this->getContainer('config')->get('rinvex.repository.cache.skip_uri');
132
133
        // Check if cache is enabled
134
        if ($this->getCacheLifetime() && ! $this->getContainer('request')->has($skipUri)) {
135
            return $this->cacheCallback($class, $method, $args, $closure);
136
        }
137
138
        // Cache disabled, just execute query & return result
139
        $result = call_user_func($closure);
140
141
        // We're done, let's clean up!
142
        $this->resetRepository();
143
144
        return $result;
145
    }
146
147
    /**
148
     * Reset repository to it's defaults.
149
     *
150
     * @return $this
151
     */
152
    protected function resetRepository()
153
    {
154
        $this->relations  = [];
155
        $this->where      = [];
156
        $this->whereIn    = [];
157
        $this->whereNotIn = [];
158
        $this->whereHas   = [];
159
        $this->offset     = null;
160
        $this->limit      = null;
161
        $this->orderBy    = [];
162
        $this->having     = [];
163
164
        if (method_exists($this, 'flushCriteria')) {
165
            $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...
166
        }
167
168
        return $this;
169
    }
170
171
    /**
172
     * Prepare query.
173
     *
174
     * @param object $model
175
     *
176
     * @return object
177
     */
178
    protected function prepareQuery($model)
179
    {
180
        // Set the relationships that should be eager loaded
181
        if (! empty($this->relations)) {
182
            $model = $model->with($this->relations);
183
        }
184
185
        // Add a basic where clause to the query
186
        foreach ($this->where as $where) {
187
            list($attribute, $operator, $value, $boolean) = array_pad($where, 4, null);
188
189
            $model = $model->where($attribute, $operator, $value, $boolean);
190
        }
191
192
        // Add a "where in" clause to the query
193
        foreach ($this->whereIn as $whereIn) {
194
            list($attribute, $values, $boolean, $not) = array_pad($whereIn, 4, null);
195
196
            $model = $model->whereIn($attribute, $values, $boolean, $not);
197
        }
198
199
        // Add a "where not in" clause to the query
200
        foreach ($this->whereNotIn as $whereNotIn) {
201
            list($attribute, $values, $boolean) = array_pad($whereNotIn, 3, null);
202
203
            $model = $model->whereNotIn($attribute, $values, $boolean);
204
        }
205
206
        // Add a "where has" clause to the query
207
        foreach ($this->whereHas as $whereHas) {
208
            list($relation, $callback, $operator, $count) = array_pad($whereHas, 4, null);
209
210
            $model = $model->whereHas($relation, $callback, $operator, $count);
211
        }
212
213
        // Set the "offset" value of the query
214
        if ($this->offset > 0) {
215
            $model = $model->offset($this->offset);
216
        }
217
218
        // Set the "limit" value of the query
219
        if ($this->limit > 0) {
220
            $model = $model->limit($this->limit);
221
        }
222
223
        // Add an "order by" clause to the query.
224
        if (! empty($this->orderBy)) {
225
            list($attribute, $direction) = $this->orderBy;
226
227
            $model = $model->orderBy($attribute, $direction);
228
        }
229
230
        // Add a "having" clause to the query
231
        foreach ($this->having as $having) {
232
            list($column, $operator, $value, $boolean) = array_pad($having, 4, null);
233
234
            $model = $model->having($column, $operator, $value, $boolean);
235
        }
236
237
        // Apply all criteria to the query
238
        if (method_exists($this, 'applyCriteria')) {
239
            $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...
240
        }
241
242
        return $model;
243
    }
244
245
    /**
246
     * {@inheritdoc}
247
     */
248
    public function setContainer(Container $container)
249
    {
250
        $this->container = $container;
251
252
        return $this;
253
    }
254
255
    /**
256
     * {@inheritdoc}
257
     */
258
    public function getContainer($service = null)
259
    {
260
        return is_null($service) ? ($this->container ?: app()) : ($this->container[$service] ?: app($service));
261
    }
262
263
    /**
264
     * {@inheritdoc}
265
     */
266
    public function setConnection($name)
267
    {
268
        $this->connection = $name;
269
270
        return $this;
271
    }
272
273
    /**
274
     * {@inheritdoc}
275
     */
276
    public function getConnection()
277
    {
278
        return $this->connection;
279
    }
280
281
    /**
282
     * {@inheritdoc}
283
     */
284
    public function setRepositoryId($repositoryId)
285
    {
286
        $this->repositoryId = $repositoryId;
287
288
        return $this;
289
    }
290
291
    /**
292
     * {@inheritdoc}
293
     */
294
    public function getRepositoryId()
295
    {
296
        return $this->repositoryId ?: get_called_class();
297
    }
298
299
    /**
300
     * {@inheritdoc}
301
     */
302
    public function setModel($model)
303
    {
304
        $this->model = $model;
305
306
        return $this;
307
    }
308
309
    /**
310
     * {@inheritdoc}
311
     */
312
    public function getModel()
313
    {
314
        $model = $this->getContainer('config')->get('rinvex.repository.models');
315
316
        return $this->model ?: str_replace(['Repositories', 'Repository'], [$model, ''], get_called_class());
317
    }
318
319
    /**
320
     * {@inheritdoc}
321
     */
322
    public function getModelInstance($id)
323
    {
324
        return $id ? $this->find($id) : $this->createModel();
325
    }
326
327
    /**
328
     * {@inheritdoc}
329
     */
330
    public function with($relations)
331
    {
332
        if (is_string($relations)) {
333
            $relations = func_get_args();
334
        }
335
336
        $this->relations = $relations;
337
338
        return $this;
339
    }
340
341
    /**
342
     * {@inheritdoc}
343
     */
344
    public function where($attribute, $operator = null, $value = null, $boolean = 'and')
345
    {
346
        // The last `$boolean` expression is intentional to fix list() & array_pad() results
347
        $this->where[] = [$attribute, $operator, $value, $boolean ?: 'and'];
348
349
        return $this;
350
    }
351
352
    /**
353
     * {@inheritdoc}
354
     */
355
    public function whereIn($attribute, $values, $boolean = 'and', $not = false)
356
    {
357
        // The last `$boolean` & `$not` expressions are intentional to fix list() & array_pad() results
358
        $this->whereIn[] = [$attribute, $values, $boolean ?: 'and', (bool) $not];
359
360
        return $this;
361
    }
362
363
    /**
364
     * {@inheritdoc}
365
     */
366
    public function whereNotIn($attribute, $values, $boolean = 'and')
367
    {
368
        // The last `$boolean` expression is intentional to fix list() & array_pad() results
369
        $this->whereNotIn[] = [$attribute, $values, $boolean ?: 'and'];
370
371
        return $this;
372
    }
373
374
    /**
375
     * {@inheritdoc}
376
     */
377
    public function whereHas($relation, Closure $callback, $operator = '>=', $count = 1)
378
    {
379
        // 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...
380
        $this->whereHas[] = [$relation, $callback, $operator ?: '>=', $count ?: 1];
381
382
        return $this;
383
    }
384
385
    /**
386
     * {@inheritdoc}
387
     */
388
    public function offset($offset)
389
    {
390
        $this->offset = $offset;
391
392
        return $this;
393
    }
394
395
    /**
396
     * {@inheritdoc}
397
     */
398
    public function limit($limit)
399
    {
400
        $this->limit = $limit;
401
402
        return $this;
403
    }
404
405
    /**
406
     * {@inheritdoc}
407
     */
408
    public function orderBy($attribute, $direction = 'asc')
409
    {
410
        $this->orderBy = [$attribute, $direction];
411
412
        return $this;
413
    }
414
415
    /**
416
     * {@inheritdoc}
417
     */
418
    public function having($column, $operator = null, $value = null, $boolean = 'and')
419
    {
420
        $this->having[] = [$column, $operator, $value, $boolean ?: 'and'];
421
422
        return $this;
423
    }
424
425
    /**
426
     * {@inheritdoc}
427
     */
428
    public function orHaving($column, $operator = null, $value = null, $boolean = 'and')
429
    {
430
        return $this->having($column, $operator, $value, 'or');
431
    }
432
433
    /**
434
     * {@inheritdoc}
435
     */
436
    public function store($id, array $attributes = [])
437
    {
438
        return ! $id ? $this->create($attributes) : $this->update($id, $attributes);
439
    }
440
441
    /**
442
     * {@inheritdoc}
443
     */
444
    public static function __callStatic($method, $parameters)
445
    {
446
        return call_user_func_array([new static(), $method], $parameters);
447
    }
448
449
    /**
450
     * {@inheritdoc}
451
     */
452
    public function __call($method, $parameters)
453
    {
454
        return call_user_func_array([$this->createModel(), $method], $parameters);
455
    }
456
}
457