Completed
Pull Request — develop (#125)
by Talip
01:48
created

EloquentRepository   B

Complexity

Total Complexity 54

Size/Duplication

Total Lines 411
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 54
lcom 1
cbo 4
dl 0
loc 411
rs 7.0642
c 0
b 0
f 0

27 Methods

Rating   Name   Duplication   Size   Complexity  
B createModel() 0 21 5
A find() 0 6 1
A findOrFail() 0 14 4
A findOrNew() 0 8 2
A findBy() 0 6 1
A findFirst() 0 6 1
A findAll() 0 6 1
A paginate() 0 8 2
A simplePaginate() 0 8 2
A findWhere() 0 10 1
A findWhereIn() 0 10 1
A findWhereNotIn() 0 10 1
A findWhereHas() 0 10 1
B create() 0 31 5
C update() 0 35 7
A delete() 0 16 3
A restore() 0 16 3
A beginTransaction() 0 4 1
A commit() 0 4 1
A rollBack() 0 4 1
A count() 0 6 1
A min() 0 6 1
A max() 0 6 1
A avg() 0 6 1
A sum() 0 6 1
A extractRelations() 0 16 2
A syncRelations() 0 11 3

How to fix   Complexity   

Complex Class

Complex classes like EloquentRepository often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EloquentRepository, and based on these observations, apply Extract Interface, too.

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 Illuminate\Pagination\Paginator;
19
use Illuminate\Database\Eloquent\Model;
20
use Rinvex\Repository\Exceptions\RepositoryException;
21
use Rinvex\Repository\Exceptions\EntityNotFoundException;
22
23
class EloquentRepository extends BaseRepository
24
{
25
    /**
26
     * {@inheritdoc}
27
     */
28
    public function createModel()
29
    {
30
        if (is_string($model = $this->getModel())) {
31
            if (! class_exists($class = '\\'.ltrim($model, '\\'))) {
32
                throw new RepositoryException("Class {$model} does NOT exist!");
33
            }
34
35
            $model = $this->getContainer()->make($class);
36
        }
37
38
        // Set the connection used by the model
39
        if (! empty($this->connection)) {
40
            $model = $model->setConnection($this->connection);
41
        }
42
43
        if (! $model instanceof Model) {
44
            throw new RepositoryException("Class {$model} must be an instance of \\Illuminate\\Database\\Eloquent\\Model");
45
        }
46
47
        return $model;
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function find($id, $attributes = ['*'])
54
    {
55
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($id, $attributes) {
56
            return $this->prepareQuery($this->createModel())->find($id, $attributes);
57
        });
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function findOrFail($id, $attributes = ['*'])
64
    {
65
        $result = $this->find($id, $attributes);
66
67
        if (is_array($id)) {
68
            if (count($result) == count(array_unique($id))) {
69
                return $result;
70
            }
71
        } elseif (! is_null($result)) {
72
            return $result;
73
        }
74
75
        throw new EntityNotFoundException($this->getModel(), $id);
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81
    public function findOrNew($id, $attributes = ['*'])
82
    {
83
        if (! is_null($entity = $this->find($id, $attributes))) {
84
            return $entity;
85
        }
86
87
        return $this->createModel();
88
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93
    public function findBy($attribute, $value, $attributes = ['*'])
94
    {
95
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($attribute, $value, $attributes) {
96
            return $this->prepareQuery($this->createModel())->where($attribute, '=', $value)->first($attributes);
97
        });
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103
    public function findFirst($attributes = ['*'])
104
    {
105
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($attributes) {
106
            return $this->prepareQuery($this->createModel())->first($attributes);
107
        });
108
    }
109
110
    /**
111
     * {@inheritdoc}
112
     */
113
    public function findAll($attributes = ['*'])
114
    {
115
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($attributes) {
116
            return $this->prepareQuery($this->createModel())->get($attributes);
117
        });
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123
    public function paginate($perPage = null, $attributes = ['*'], $pageName = 'page', $page = null)
124
    {
125
        $page = $page ?: Paginator::resolveCurrentPage($pageName);
126
127
        return $this->executeCallback(get_called_class(), __FUNCTION__, array_merge(func_get_args(), compact('page')), function () use ($perPage, $attributes, $pageName, $page) {
128
            return $this->prepareQuery($this->createModel())->paginate($perPage, $attributes, $pageName, $page);
129
        });
130
    }
131
132
    /**
133
     * {@inheritdoc}
134
     */
135
    public function simplePaginate($perPage = null, $attributes = ['*'], $pageName = 'page', $page = null)
136
    {
137
        $page = $page ?: Paginator::resolveCurrentPage($pageName);
138
139
        return $this->executeCallback(get_called_class(), __FUNCTION__, array_merge(func_get_args(), compact('page')), function () use ($perPage, $attributes, $pageName, $page) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 178 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
140
            return $this->prepareQuery($this->createModel())->simplePaginate($perPage, $attributes, $pageName, $page);
141
        });
142
    }
143
144
    /**
145
     * {@inheritdoc}
146
     */
147
    public function findWhere(array $where, $attributes = ['*'])
148
    {
149
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($where, $attributes) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 128 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
150
            list($attribute, $operator, $value, $boolean) = array_pad($where, 4, null);
151
152
            $this->where($attribute, $operator, $value, $boolean);
153
154
            return $this->prepareQuery($this->createModel())->get($attributes);
155
        });
156
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161
    public function findWhereIn(array $where, $attributes = ['*'])
162
    {
163
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($where, $attributes) {
164
            list($attribute, $values, $boolean, $not) = array_pad($where, 4, null);
165
166
            $this->whereIn($attribute, $values, $boolean, $not);
167
168
            return $this->prepareQuery($this->createModel())->get($attributes);
169
        });
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175
    public function findWhereNotIn(array $where, $attributes = ['*'])
176
    {
177
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($where, $attributes) {
178
            list($attribute, $values, $boolean) = array_pad($where, 3, null);
179
180
            $this->whereNotIn($attribute, $values, $boolean);
181
182
            return $this->prepareQuery($this->createModel())->get($attributes);
183
        });
184
    }
185
186
    /**
187
     * {@inheritdoc}
188
     */
189
    public function findWhereHas(array $where, $attributes = ['*'])
190
    {
191
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($where, $attributes) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 128 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
192
            list($relation, $callback, $operator, $count) = array_pad($where, 4, null);
193
194
            $this->whereHas($relation, $callback, $operator, $count);
195
196
            return $this->prepareQuery($this->createModel())->get($attributes);
197
        });
198
    }
199
200
    /**
201
     * {@inheritdoc}
202
     */
203
    public function create(array $attributes = [], bool $syncRelations = false)
204
    {
205
        // Create a new instance
206
        $entity = $this->createModel();
207
208
        // Fire the created event
209
        $this->getContainer('events')->fire($this->getRepositoryId().'.entity.creating', [$this, $entity]);
210
211
        // Extract relationships
212
        if ($syncRelations) {
213
            $relations = $this->extractRelations($entity, $attributes);
214
            array_forget($attributes, array_keys($relations));
215
        }
216
217
        // Fill instance with data
218
        $entity->fill($attributes);
219
220
        // Save the instance
221
        $created = $entity->save();
222
223
        // Sync relationships
224
        if ($syncRelations && isset($relations)) {
225
            $this->syncRelations($entity, $relations);
226
        }
227
228
        // Fire the created event
229
        $this->getContainer('events')->fire($this->getRepositoryId().'.entity.created', [$this, $entity]);
230
231
        // Return instance
232
        return $created ? $entity : $created;
233
    }
234
235
    /**
236
     * {@inheritdoc}
237
     */
238
    public function update($id, array $attributes = [], bool $syncRelations = false)
239
    {
240
        // Find the given instance
241
        $entity = $id instanceof Model ? $id : $this->findOrFail($id);
242
243
        // Fire the updated event
244
        $this->getContainer('events')->fire($this->getRepositoryId().'.entity.updating', [$this, $entity]);
245
246
        // Extract relationships
247
        if ($syncRelations) {
248
            $relations = $this->extractRelations($entity, $attributes);
249
            array_forget($attributes, array_keys($relations));
250
        }
251
252
        // Fill instance with data
253
        $entity->fill($attributes);
254
255
        //Check if we are updating attributes values
256
        $dirty = $entity->getDirty();
257
258
        // Update the instance
259
        $updated = $entity->save();
260
261
        // Sync relationships
262
        if ($syncRelations && isset($relations)) {
263
            $this->syncRelations($entity, $relations);
264
        }
265
266
        if (count($dirty) > 0) {
267
            // Fire the updated event
268
            $this->getContainer('events')->fire($this->getRepositoryId().'.entity.updated', [$this, $entity]);
269
        }
270
271
        return $updated ? $entity : $updated;
272
    }
273
274
    /**
275
     * {@inheritdoc}
276
     */
277
    public function delete($id)
278
    {
279
        // Find the given instance
280
        $entity = $id instanceof Model ? $id : $this->findOrFail($id);
281
282
        // Fire the deleted event
283
        $this->getContainer('events')->fire($this->getRepositoryId().'.entity.deleting', [$this, $entity]);
284
285
        // Delete the instance
286
        $deleted = $entity->delete();
287
288
        // Fire the deleted event
289
        $this->getContainer('events')->fire($this->getRepositoryId().'.entity.deleted', [$this, $entity]);
290
291
        return $deleted ? $entity : $deleted;
292
    }
293
294
    /**
295
     * {@inheritdoc}
296
     */
297
    public function restore($id)
298
    {
299
        // Find the given instance
300
        $entity = $id instanceof Model ? $id : $this->findOrFail($id);
301
302
        // Fire the restoring event
303
        $this->getContainer('events')->fire($this->getRepositoryId().'.entity.restoring', [$this, $entity]);
304
305
        // Restore the instance
306
        $restored = $entity->restore();
307
308
        // Fire the restored event
309
        $this->getContainer('events')->fire($this->getRepositoryId().'.entity.restored', [$this, $entity]);
310
311
        return $restored ? $entity : $restored;
312
    }
313
314
    /**
315
     * {@inheritdoc}
316
     */
317
    public function beginTransaction()
318
    {
319
        $this->getContainer('db')->beginTransaction();
320
    }
321
322
    /**
323
     * {@inheritdoc}
324
     */
325
    public function commit()
326
    {
327
        $this->getContainer('db')->commit();
328
    }
329
330
    /**
331
     * {@inheritdoc}
332
     */
333
    public function rollBack()
334
    {
335
        $this->getContainer('db')->rollBack();
336
    }
337
338
    /**
339
     * {@inheritdoc}
340
     */
341
    public function count($columns = '*')
342
    {
343
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($columns) {
344
            return $this->prepareQuery($this->createModel())->count($columns);
345
        });
346
    }
347
348
    /**
349
     * {@inheritdoc}
350
     */
351
    public function min($column)
352
    {
353
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($column) {
354
            return $this->prepareQuery($this->createModel())->min($column);
355
        });
356
    }
357
358
    /**
359
     * {@inheritdoc}
360
     */
361
    public function max($column)
362
    {
363
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($column) {
364
            return $this->prepareQuery($this->createModel())->max($column);
365
        });
366
    }
367
368
    /**
369
     * {@inheritdoc}
370
     */
371
    public function avg($column)
372
    {
373
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($column) {
374
            return $this->prepareQuery($this->createModel())->avg($column);
375
        });
376
    }
377
378
    /**
379
     * {@inheritdoc}
380
     */
381
    public function sum($column)
382
    {
383
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($column) {
384
            return $this->prepareQuery($this->createModel())->sum($column);
385
        });
386
    }
387
388
    /**
389
     * Extract relationships.
390
     *
391
     * @param mixed $entity
392
     * @param array $attributes
393
     *
394
     * @return array
395
     */
396
    protected function extractRelations($entity, array $attributes)
397
    {
398
        $relations = [];
399
        $potential = array_diff(array_keys($attributes), $entity->getFillable());
400
401
        array_walk($potential, function ($relation) use ($entity, $attributes, &$relations) {
402
            if (method_exists($entity, $relation)) {
403
                $relations[$relation] = [
404
                    'values' => $attributes[$relation],
405
                    'class'  => get_class($entity->$relation()),
406
                ];
407
            }
408
        });
409
410
        return $relations;
411
    }
412
413
    /**
414
     * Sync relationships.
415
     *
416
     * @param mixed $entity
417
     * @param array $relations
418
     * @param bool  $detaching
419
     *
420
     * @return void
421
     */
422
    protected function syncRelations($entity, array $relations, $detaching = true)
423
    {
424
        foreach ($relations as $method => $relation) {
425
            switch ($relation['class']) {
426
                case 'Illuminate\Database\Eloquent\Relations\BelongsToMany':
427
                default:
428
                    $entity->$method()->sync((array) $relation['values'], $detaching);
429
                    break;
430
            }
431
        }
432
    }
433
}
434