Passed
Push — master ( 46b04d...939fb0 )
by Orkhan
02:33
created

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

245
                /** @scrutinizer ignore-type */ $modelId
Loading history...
246
            );
247
        }
248
249
        return $model;
250
    }
251
252
    /**
253
     * Updates a model given properties.
254
     *
255
     * @param Model $model
256
     * @param mixed $properties
257
     *
258
     * @return Builder|Model
259
     * @throws BindingResolutionException
260
     */
261
    public function update($model, $properties)
262
    {
263
        if ($this instanceof Cacheable) {
264
            $this->invalidateCache($model);
265
        }
266
267
        $model->fill($properties)->save();
268
269
        return $model->refresh();
270
    }
271
272
    /**
273
     * Finds a model with ID and deletes it.
274
     *
275
     * @param int|string $modelId
276
     *
277
     * @return bool|mixed|null
278
     * @throws Exception
279
     */
280
    public function findAndDelete($modelId)
281
    {
282
        $model = $this->find($modelId);
283
284
        return $this->delete($model);
285
    }
286
287
    /**
288
     * Deletes a model.
289
     *
290
     * @param Model $model
291
     *
292
     * @return bool|mixed|null
293
     * @throws Exception
294
     */
295
    public function delete($model)
296
    {
297
        if ($this instanceof Cacheable) {
298
            $this->invalidateCache($model);
299
        }
300
301
        return $model->delete();
302
    }
303
304
    /**
305
     * Finds a soft deleted model with given ID and restores it.
306
     *
307
     * @param int|string $modelId
308
     *
309
     * @return bool|null
310
     */
311
    public function findAndRestore($modelId)
312
    {
313
        $model = $this->findFromTrashed($modelId);
314
315
        return $this->restore($model);
316
    }
317
318
    /**
319
     * Finds a soft deleted model with given ID.
320
     *
321
     * @param int|string $modelId
322
     *
323
     * @return Builder|Builder[]|Collection|Model|null
324
     */
325
    public function findFromTrashed($modelId)
326
    {
327
        if (! method_exists($this->entity, 'restore')) {
328
            throw new BadMethodCallException('Model is not using "soft delete" feature.');
329
        }
330
331
        $model = $this->entity->onlyTrashed()->find($modelId);
332
333
        if (! $model) {
334
            throw (new ModelNotFoundException)->setModel(
335
                get_class($this->entity->getModel()),
336
                $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

336
                /** @scrutinizer ignore-type */ $modelId
Loading history...
337
            );
338
        }
339
340
        return $model;
341
    }
342
343
    /**
344
     * Restores soft deleted model.
345
     *
346
     * @param Model $model
347
     *
348
     * @return bool|null
349
     */
350
    public function restore($model)
351
    {
352
        if (! method_exists($this->entity, 'restore')) {
353
            throw new BadMethodCallException('Model is not using "soft delete" feature.');
354
        }
355
356
        return $model->restore();
357
    }
358
359
    /**
360
     * Sets listed criteria for entity.
361
     *
362
     * @param mixed ...$criteria
363
     *
364
     * @return self
365
     */
366
    public function withCriteria(...$criteria)
367
    {
368
        $criteria = Arr::flatten($criteria);
369
370
        foreach ($criteria as $criterion) {
371
            /* @var Criteria\Criteria $criterion */
372
            $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

372
            /** @scrutinizer ignore-call */ 
373
            $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...
373
        }
374
375
        return $this;
376
    }
377
378
    /**
379
     * Removes cache for model.
380
     *
381
     * @param Model $model
382
     * @throws BindingResolutionException
383
     */
384
    public function invalidateCache($model): void
385
    {
386
        $this->cache->forget(
387
            $this->cacheKey().'.*'
388
        );
389
        $this->cache->forget(
390
            $this->cacheKey().'.'.$model->id
391
        );
392
    }
393
394
    /**
395
     * Defines cache key.
396
     *
397
     * @return string
398
     * @throws BindingResolutionException
399
     */
400
    public function cacheKey(): string
401
    {
402
        return $this->resolveEntity()->getTable();
403
    }
404
405
    /**
406
     * Get cache time-to-live value from property or method if available.
407
     *
408
     * @return int
409
     */
410
    private function cacheTTLValue(): int
411
    {
412
        if (method_exists($this, 'cacheTTL')) {
413
            return $this->cacheTTL();
414
        }
415
416
        return $this->cacheTTL;
417
    }
418
}
419