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

BaseRepository::orHaving()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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