Passed
Push — master ( 36df2b...89c2b4 )
by noitran
03:13
created

AbstractRepository::update()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 13
ccs 8
cts 8
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2
1
<?php
2
3
namespace Noitran\Repositories\Repositories;
4
5
use Illuminate\Container\Container;
6
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
7
use Illuminate\Database\Eloquent\Model;
8
use Noitran\Repositories\Contracts\Repository\Criticizable;
9
use Noitran\Repositories\Contracts\Repository\RepositoryInterface;
10
use Noitran\Repositories\Contracts\Schema\SchemaInterface;
11
use Noitran\Repositories\Events\EntityCreated;
12
use Noitran\Repositories\Events\EntityDeleted;
13
use Noitran\Repositories\Events\EntityUpdated;
14
use Noitran\Repositories\Exceptions\RepositoryException;
15
use Illuminate\Support\Collection;
16
use Closure;
17
18
/**
19
 * Class AbstractRepository
20
 */
21
abstract class AbstractRepository implements RepositoryInterface, SchemaInterface, Criticizable
22
{
23
    use Concerns\InteractsWithSchema,
0 ignored issues
show
Bug introduced by
The trait Noitran\Repositories\Rep...rns\InteractsWithSchema requires the property $from which is not provided by Noitran\Repositories\Rep...ries\AbstractRepository.
Loading history...
24
        Concerns\HasCriteria,
25
        Concerns\BuildsQueries;
26
27
    /**
28
     * @var Container
29
     */
30
    protected $app;
31
32
    /**
33
     * @var Model
34
     */
35
    protected $model;
36
37
    /**
38
     * @var Closure
39
     */
40
    protected $scope;
41
42
    /**
43
     * AbstractRepository constructor.
44
     *
45
     * @param Container $app
46
     *
47
     * @throws RepositoryException
48
     */
49 13
    public function __construct(Container $app)
50
    {
51 13
        $this->app = $app;
52
53 13
        $this->init();
54 13
    }
55
56
    /**
57
     * @throws RepositoryException
58
     *
59
     * @return AbstractRepository
60
     */
61 13
    public function init(): self
62
    {
63 13
        $this->criteria = new Collection();
64 13
        $this->setModel();
65 13
        $this->boot();
66
67 13
        return $this;
68
    }
69
70
    /**
71
     * Returns model's fully qualified class name
72
     *
73
     * @return string
74
     */
75
    abstract public function getModelClassName(): string;
76
77
    /**
78
     * Fires when repository is created
79
     */
80
    abstract public function boot(): void;
81
82
    /**
83
     * @throws RepositoryException
84
     *
85
     * @return Model
86
     */
87 13
    public function setModel(): Model
88
    {
89 13
        $model = $this->app->make($this->getModelClassName());
90
91 13
        if (! $model instanceof Model) {
92
            throw new RepositoryException(
93
                "Class {$this->getModelClassName()} must be an instance of " . Model::class
94
            );
95
        }
96
97 13
        return $this->model = $model;
98
    }
99
100
    /**
101
     * Clears model
102
     *
103
     * @throws RepositoryException
104
     */
105 13
    public function clearModel(): self
106
    {
107 13
        $this->setModel();
108
109 13
        return $this;
110
    }
111
112
    /**
113
     * @param Closure $scope
114
     *
115
     * @return $this
116
     */
117
    public function setScope(Closure $scope): self
118
    {
119
        $this->scope = $scope;
120
121
        return $this;
122
    }
123
124
    /**
125
     * Clears query scope
126
     *
127
     * @return $this
128
     */
129 3
    public function clearScope(): self
130
    {
131 3
        $this->scope = null;
132
133 3
        return $this;
134
    }
135
136
    /**
137
     * Apply scope in current Query
138
     *
139
     * @return $this
140
     */
141 13
    protected function applyScope(): self
142
    {
143 13
        if (isset($this->scope) && is_callable($this->scope)) {
144
            $callback = $this->scope;
145
            $this->model = $callback($this->model);
146
        }
147
148 13
        return $this;
149
    }
150
151
    /**
152
     * Get list of records
153
     *
154
     * @param array $columns
155
     *
156
     * @throws RepositoryException
157
     *
158
     * @return EloquentBuilder[]|\Illuminate\Database\Eloquent\Collection|Model[]|mixed
159
     */
160 3
    public function all($columns = ['*'])
161
    {
162 3
        $this->applyCriteria()
163 3
            ->applyScope();
164
165 3
        if ($this->model instanceof EloquentBuilder) {
0 ignored issues
show
introduced by
$this->model is never a sub-type of Illuminate\Database\Eloquent\Builder.
Loading history...
166 2
            $output = $this->model->get($columns);
167
        } else {
168 1
            $output = $this->model::all($columns);
169
        }
170
171 3
        $this->clearModel()
172 3
            ->clearScope();
173
174 3
        return $output;
175
    }
176
177
    /**
178
     * Alias of all()
179
     *
180
     * @param array $columns
181
     *
182
     * @throws RepositoryException
183
     *
184
     * @return EloquentBuilder[]|\Illuminate\Database\Eloquent\Collection|Model[]|mixed
185
     */
186
    public function get($columns = ['*'])
187
    {
188
        return $this->all($columns);
189
    }
190
191
    /**
192
     * Get collection of paginated records
193
     *
194
     * @param int|null $perPage
195
     * @param array $columns
196
     *
197
     * @throws RepositoryException
198
     *
199
     * @return mixed
200
     */
201 1
    public function paginate(int $perPage = null, $columns = ['*'])
202
    {
203
        return $this->getPaginator($perPage, $columns, function ($perPage, $columns) {
204 1
            return $this->model
205 1
                ->paginate($perPage, $columns)
206 1
                ->appends(app('request')->query());
207 1
        });
208
    }
209
210
    /**
211
     * @param int|null $perPage
212
     * @param array $columns
213
     *
214
     * @throws RepositoryException
215
     *
216
     * @return mixed
217
     */
218 1
    public function simplePaginate(int $perPage = null, $columns = ['*'])
219
    {
220
        return $this->getPaginator($perPage, $columns, function ($perPage, $columns) {
221 1
            return $this->model
222 1
                ->simplePaginate($perPage, $columns)
223 1
                ->appends(app('request')->query());
224 1
        });
225
    }
226
227
    /**
228
     * @param int|null $perPage
229
     * @param array $columns
230
     * @param callable|null $callback
231
     *
232
     * @throws RepositoryException
233
     *
234
     * @return mixed
235
     */
236 2
    protected function getPaginator(int $perPage = null, $columns = ['*'], callable $callback = null)
237
    {
238 2
        $this->applyCriteria()
239 2
            ->applyScope();
240
241 2
        $perPage = $perPage ?? config('repositories.pagination.per_page', $this->model->getPerPage());
242
243 2
        $results = $callback($perPage, $columns);
244 2
        $this->clearModel();
245
246 2
        return $results;
247
    }
248
249
    /**
250
     * Get single or multiple records by their primary ids
251
     *
252
     * @param mixed $id
253
     * @param array $columns
254
     *
255
     * @throws RepositoryException
256
     *
257
     * @return mixed
258
     */
259 3
    public function find($id, $columns = ['*'])
260
    {
261 3
        $this->applyCriteria()
262 3
            ->applyScope();
263
264 3
        $model = $this->model->find($id, $columns);
265
266 3
        $this->clearModel();
267
268 3
        return $model;
269
    }
270
271
    /**
272
     * @param $field
273
     * @param null $value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
274
     * @param array $columns
275
     *
276
     * @throws RepositoryException
277
     *
278
     * @return mixed
279
     */
280
    public function findByField($field, $value = null, $columns = ['*'])
281
    {
282
        $this->applyCriteria()
283
            ->applyScope();
284
285
        $results = $this->model
286
            ->where($field, '=', $value)
287
            ->get($columns);
288
289
        $this->clearModel();
290
291
        return $results;
292
    }
293
294
    /**
295
     * Count results of repository
296
     *
297
     * @param array $columns
298
     *
299
     * @throws RepositoryException
300
     *
301
     * @return int
302
     */
303 1
    public function count($columns = ['*']): int
304
    {
305 1
        $this->applyCriteria()
306 1
            ->applyScope();
307
308 1
        $count = $this->model->count($columns);
309
310 1
        $this->clearModel();
311
312 1
        return $count;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $count could return the type Illuminate\Database\Eloquent\Builder which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
313
    }
314
315
    /**
316
     * Execute the query and get the first result.
317
     *
318
     * @param array $columns
319
     *
320
     * @throws RepositoryException
321
     *
322
     * @return mixed
323
     */
324 1
    public function first($columns = ['*']): ?Model
325
    {
326 1
        $this->applyCriteria()
327 1
            ->applyScope();
328
329 1
        $model = $this->model->first($columns);
330
331 1
        $this->clearModel();
332
333 1
        return $model;
334
    }
335
336
    /**
337
     * @param array $attributes
338
     *
339
     * @throws RepositoryException
340
     *
341
     * @return Model|null
342
     */
343 1
    public function create(array $attributes = []): ?Model
344
    {
345 1
        $model = $this->model->create($attributes);
346 1
        $this->clearModel();
347 1
        event(new EntityCreated($this, $model));
348
349 1
        return $model;
350
    }
351
352
    /**
353
     * @param mixed $model
354
     * @param array $attributes
355
     *
356
     * @throws RepositoryException
357
     *
358
     * @return Model
359
     */
360 2
    public function update($model, array $attributes): Model
361
    {
362 2
        $this->applyScope();
363
364 2
        if (! $model instanceof Model) {
365 1
            $model = $this->model->findOrFail($model);
366
        }
367
368 2
        $model->update($attributes);
369 2
        $this->clearModel();
370 2
        event(new EntityUpdated($this, $model));
371
372 2
        return $model;
373
    }
374
375
    /**
376
     * @param $model
377
     *
378
     * @throws RepositoryException
379
     *
380
     * @return bool|null
381
     */
382 2
    public function delete($model): ?bool
383
    {
384 2
        $this->applyScope();
385
386 2
        if (! $model instanceof Model) {
387 1
            $model = $this->find($model);
388
        }
389
390 2
        $clonedModel = clone $model;
391 2
        $this->clearModel();
392 2
        $deleted = $model->delete();
393
394 2
        event(new EntityDeleted($this, $clonedModel));
395
396 2
        return $deleted;
397
    }
398
}
399