Completed
Push — master ( ca6a20...2dd424 )
by Orkhan
02:23
created

EloquentRepository::getWhereIn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Orkhanahmadov\EloquentRepository;
4
5
use BadMethodCallException;
6
use Exception;
7
use Illuminate\Contracts\Cache\Factory as Cache;
8
use Illuminate\Contracts\Container\BindingResolutionException;
9
use Illuminate\Database\Eloquent\Builder;
10
use Illuminate\Database\Eloquent\Collection;
11
use Illuminate\Database\Eloquent\Model;
12
use Illuminate\Database\Eloquent\ModelNotFoundException;
13
use Illuminate\Support\Arr;
14
use Orkhanahmadov\EloquentRepository\Repository\Contracts\Cachable;
15
use Orkhanahmadov\EloquentRepository\Repository\Contracts\Repository;
16
use Orkhanahmadov\EloquentRepository\Repository\Criteria;
17
18
abstract class EloquentRepository implements Repository
19
{
20
    /**
21
     * @var Cache
22
     */
23
    protected $cache;
24
    /**
25
     * @var Builder
26
     */
27
    protected $entity;
28
29
    /**
30
     * EloquentRepository constructor.
31
     *
32
     * @param Cache $cache
33
     * @throws BindingResolutionException
34
     */
35
    public function __construct(Cache $cache)
36
    {
37
        $this->cache = $cache;
38
        $this->entity = $this->resolveEntity();
39
    }
40
41
    /**
42
     * Resolves entity.
43
     *
44
     * @return mixed
45
     * @throws BindingResolutionException
46
     */
47
    protected function resolveEntity()
48
    {
49
        return app()->make($this->entity());
50
    }
51
52
    /**
53
     * Defines entity.
54
     *
55
     * @return mixed
56
     */
57
    abstract protected function entity();
58
59
    /**
60
     * Creates model.
61
     *
62
     * @param mixed $properties
63
     *
64
     * @return Builder|Model
65
     */
66
    public function create($properties)
67
    {
68
        return $this->entity->create($properties);
69
    }
70
71
    /**
72
     * Returns all models.
73
     *
74
     * @return Builder[]|Collection
75
     * @throws BindingResolutionException
76
     */
77
    public function all()
78
    {
79
        return $this->get();
80
    }
81
82
    /**
83
     * Returns all models with selected columns.
84
     *
85
     * @param array $columns
86
     *
87
     * @return Builder[]|Collection
88
     * @throws BindingResolutionException
89
     */
90
    public function get(array $columns = ['*'])
91
    {
92
        if ($this instanceof Cachable) {
93
            return $this->cache->remember(
94
                $this->cacheKey().'.'.implode(',', $columns),
95
                $this->cacheTTL(),
96
                function () use ($columns) {
97
                    return $this->entity->get($columns);
98
                }
99
            );
100
        }
101
102
        return $this->entity->get($columns);
103
    }
104
105
    /**
106
     * Paginates models.
107
     *
108
     * @param int $perPage
109
     *
110
     * @return Builder[]|Collection|mixed
111
     */
112
    public function paginate(int $perPage)
113
    {
114
        return $this->entity->paginate($perPage);
115
    }
116
117
    /**
118
     * Finds models with "where" condition.
119
     *
120
     * @param string|array $column
121
     * @param mixed $value
122
     *
123
     * @return Builder[]|Collection
124
     */
125
    public function getWhere($column, $value = null)
126
    {
127
        if (is_array($column)) {
128
            return $this->entity->where($column)->get();
129
        }
130
131
        return $this->entity->where($column, $value)->get();
132
    }
133
134
    /**
135
     * Finds models with "whereIn" condition.
136
     *
137
     * @param string $column
138
     * @param array $values
139
     *
140
     * @return Builder[]|Collection
141
     */
142
    public function getWhereIn(string $column, array $values)
143
    {
144
        return $this->entity->whereIn($column, $values)->get();
145
    }
146
147
    /**
148
     * Finds first model with "where" condition.
149
     *
150
     * @param string|array $column
151
     * @param mixed $value
152
     *
153
     * @return Builder|Model|object|null
154
     */
155
    public function getWhereFirst($column, $value = null)
156
    {
157
        if (is_array($column)) {
158
            $model = $this->entity->where($column)->first();
159
        } else {
160
            $model = $this->entity->where($column, $value)->first();
161
        }
162
163
        if (! $model) {
164
            throw (new ModelNotFoundException)->setModel(
165
                get_class($this->entity->getModel())
166
            );
167
        }
168
169
        return $model;
170
    }
171
172
    /**
173
     * Finds first model with "whereIn" condition.
174
     *
175
     * @param string $column
176
     * @param array $values
177
     *
178
     * @return Builder|Model|object|null
179
     */
180
    public function getWhereInFirst(string $column, array $values)
181
    {
182
        $model = $this->entity->whereIn($column, $values)->first();
183
184
        if (! $model) {
185
            throw (new ModelNotFoundException)->setModel(
186
                get_class($this->entity->getModel())
187
            );
188
        }
189
190
        return $model;
191
    }
192
193
    /**
194
     * Finds a model with ID and updates it with given properties.
195
     *
196
     * @param int|string $modelId
197
     * @param array $properties
198
     *
199
     * @return Builder|Model
200
     * @throws BindingResolutionException
201
     */
202
    public function findAndUpdate($modelId, array $properties)
203
    {
204
        $model = $this->find($modelId);
205
206
        return $this->update($model, $properties);
207
    }
208
209
    /**
210
     * Finds a model with ID.
211
     *
212
     * @param int|string $modelId
213
     *
214
     * @return Builder|Builder[]|Collection|Model|null
215
     * @throws BindingResolutionException
216
     */
217
    public function find($modelId)
218
    {
219
        if ($this instanceof Cachable) {
220
            $model = $this->cache->remember(
221
                $this->cacheKey().'.'.$modelId,
222
                $this->cacheTTL(),
223
                function () use ($modelId) {
224
                    return $this->entity->find($modelId);
225
                }
226
            );
227
        } else {
228
            $model = $this->entity->find($modelId);
229
        }
230
231
        if (! $model) {
232
            throw (new ModelNotFoundException)->setModel(
233
                get_class($this->entity->getModel()),
234
                $modelId
0 ignored issues
show
Bug introduced by
It seems like $modelId can also be of type string; however, parameter $ids of Illuminate\Database\Eloq...ndException::setModel() does only seem to accept array|integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

234
                /** @scrutinizer ignore-type */ $modelId
Loading history...
235
            );
236
        }
237
238
        return $model;
239
    }
240
241
    /**
242
     * Updates a model given properties.
243
     *
244
     * @param Model $model
245
     * @param mixed $properties
246
     *
247
     * @return Builder|Model
248
     * @throws BindingResolutionException
249
     */
250
    public function update($model, $properties)
251
    {
252
        if ($this instanceof Cachable) {
253
            $this->invalidateCache($model);
254
        }
255
256
        $model->fill($properties)->save();
257
258
        return $model->refresh();
259
    }
260
261
    /**
262
     * Finds a model with ID and deletes it.
263
     *
264
     * @param int|string $modelId
265
     *
266
     * @return bool|mixed|null
267
     * @throws Exception
268
     */
269
    public function findAndDelete($modelId)
270
    {
271
        $model = $this->find($modelId);
272
273
        return $this->delete($model);
274
    }
275
276
    /**
277
     * Deletes a model.
278
     *
279
     * @param Model $model
280
     *
281
     * @return bool|mixed|null
282
     * @throws Exception
283
     */
284
    public function delete($model)
285
    {
286
        if ($this instanceof Cachable) {
287
            $this->invalidateCache($model);
288
        }
289
290
        return $model->delete();
291
    }
292
293
    /**
294
     * Finds a soft deleted model with given ID and restores it.
295
     *
296
     * @param int|string $modelId
297
     *
298
     * @return bool|null
299
     */
300
    public function findAndRestore($modelId)
301
    {
302
        $model = $this->findFromTrashed($modelId);
303
304
        return $this->restore($model);
305
    }
306
307
    /**
308
     * Finds a soft deleted model with given ID.
309
     *
310
     * @param int|string $modelId
311
     *
312
     * @return Builder|Builder[]|Collection|Model|null
313
     */
314
    public function findFromTrashed($modelId)
315
    {
316
        if (! method_exists($this->entity, 'restore')) {
317
            throw new BadMethodCallException('Model is not using "soft delete" feature.');
318
        }
319
320
        $model = $this->entity->onlyTrashed()->find($modelId);
321
322
        if (! $model) {
323
            throw (new ModelNotFoundException)->setModel(
324
                get_class($this->entity->getModel()),
325
                $modelId
0 ignored issues
show
Bug introduced by
It seems like $modelId can also be of type string; however, parameter $ids of Illuminate\Database\Eloq...ndException::setModel() does only seem to accept array|integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

325
                /** @scrutinizer ignore-type */ $modelId
Loading history...
326
            );
327
        }
328
329
        return $model;
330
    }
331
332
    /**
333
     * Restores soft deleted model.
334
     *
335
     * @param Model $model
336
     *
337
     * @return bool|null
338
     */
339
    public function restore($model)
340
    {
341
        if (! method_exists($this->entity, 'restore')) {
342
            throw new BadMethodCallException('Model is not using "soft delete" feature.');
343
        }
344
345
        return $model->restore();
346
    }
347
348
    /**
349
     * Sets listed criteria for entity.
350
     *
351
     * @param mixed ...$criteria
352
     *
353
     * @return self
354
     */
355
    public function withCriteria(...$criteria)
356
    {
357
        $criteria = Arr::flatten($criteria);
358
359
        foreach ($criteria as $criterion) {
360
            /* @var Criteria\Criteria $criterion */
361
            $this->entity = $criterion->apply($this->entity);
0 ignored issues
show
Bug introduced by
The method apply() does not exist on Orkhanahmadov\EloquentRe...itory\Criteria\Criteria. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

361
            /** @scrutinizer ignore-call */ 
362
            $this->entity = $criterion->apply($this->entity);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
362
        }
363
364
        return $this;
365
    }
366
367
    /**
368
     * Defines cache time-to-live seconds.
369
     *
370
     * @return int
371
     */
372
    public function cacheTTL(): int
373
    {
374
        return 3600;
375
    }
376
377
    /**
378
     * Removes cache for model.
379
     *
380
     * @param Model $model
381
     * @throws BindingResolutionException
382
     */
383
    public function invalidateCache($model): void
384
    {
385
        $this->cache->forget(
386
            $this->cacheKey().'.*'
387
        );
388
        $this->cache->forget(
389
            $this->cacheKey().'.'.$model->id
390
        );
391
    }
392
393
    /**
394
     * Defines cache key.
395
     *
396
     * @return string
397
     * @throws BindingResolutionException
398
     */
399
    public function cacheKey(): string
400
    {
401
        return $this->resolveEntity()->getTable();
402
    }
403
}
404