Passed
Push — master ( ac21bd...36df2b )
by noitran
03:42
created

AbstractRepository::update()   A

Complexity

Conditions 2
Paths 2

Size

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