Completed
Push — develop ( beaec1...bd8098 )
by Abdelrahman
01:49
created

BaseRepository::whereHas()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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