Completed
Push — develop ( d7f07d...880ad5 )
by Abdelrahman
03:03
created

EloquentRepository::syncRelations()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 3
nop 3
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 = [])
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
        // Fill instance with data
212
        $entity->fill($attributes);
213
214
        // Save the instance
215
        $created = $entity->save();
216
217
        // Extract and sync relationships
218
        $relations = $this->extractRelations($entity, $attributes);
219
        $this->syncRelations($entity, $relations);
220
221
        // Fire the created event
222
        $this->getContainer('events')->fire($this->getRepositoryId().'.entity.created', [$this, $entity]);
223
224
        // Return instance
225
        return $created ? $entity : $created;
226
    }
227
228
    /**
229
     * {@inheritdoc}
230
     */
231
    public function update($id, array $attributes = [])
232
    {
233
        $updated = false;
234
235
        // Find the given instance
236
        $entity = $id instanceof Model ? $id : $this->find($id);
237
238
        if ($entity) {
239
            // Fire the updated event
240
            $this->getContainer('events')->fire($this->getRepositoryId().'.entity.updating', [$this, $entity]);
241
242
            // Fill instance with data
243
            $entity->fill($attributes);
244
245
            // Update the instance
246
            $updated = $entity->save();
247
248
            // Extract and sync relationships
249
            $relations = $this->extractRelations($entity, $attributes);
250
            $this->syncRelations($entity, $relations);
251
252
            // Fire the updated event
253
            $this->getContainer('events')->fire($this->getRepositoryId().'.entity.updated', [$this, $entity]);
254
        }
255
256
        return $updated ? $entity : $updated;
257
    }
258
259
    /**
260
     * {@inheritdoc}
261
     */
262
    public function delete($id)
263
    {
264
        $deleted  = false;
265
266
        // Find the given instance
267
        $entity = $id instanceof Model ? $id : $this->find($id);
268
269
        if ($entity) {
270
            // Fire the deleted event
271
            $this->getContainer('events')->fire($this->getRepositoryId().'.entity.deleting', [$this, $entity]);
272
273
            // Delete the instance
274
            $deleted = $entity->delete();
275
276
            // Fire the deleted event
277
            $this->getContainer('events')->fire($this->getRepositoryId().'.entity.deleted', [$this, $entity]);
278
        }
279
280
        return $deleted ? $entity : $deleted;
281
    }
282
283
    /**
284
     * {@inheritdoc}
285
     */
286
    public function beginTransaction()
287
    {
288
        $this->getContainer('db')->beginTransaction();
289
    }
290
291
    /**
292
     * {@inheritdoc}
293
     */
294
    public function commit()
295
    {
296
        $this->getContainer('db')->commit();
297
    }
298
299
    /**
300
     * {@inheritdoc}
301
     */
302
    public function rollBack()
303
    {
304
        $this->getContainer('db')->rollBack();
305
    }
306
307
    /**
308
     * {@inheritdoc}
309
     */
310
    public function count($columns = '*')
311
    {
312
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($columns) {
313
            return $this->prepareQuery($this->createModel())->count($columns);
314
        });
315
    }
316
317
    /**
318
     * {@inheritdoc}
319
     */
320
    public function min($column)
321
    {
322
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($column) {
323
            return $this->prepareQuery($this->createModel())->min($column);
324
        });
325
    }
326
327
    /**
328
     * {@inheritdoc}
329
     */
330
    public function max($column)
331
    {
332
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($column) {
333
            return $this->prepareQuery($this->createModel())->max($column);
334
        });
335
    }
336
337
    /**
338
     * {@inheritdoc}
339
     */
340
    public function avg($column)
341
    {
342
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($column) {
343
            return $this->prepareQuery($this->createModel())->avg($column);
344
        });
345
    }
346
347
    /**
348
     * {@inheritdoc}
349
     */
350
    public function sum($column)
351
    {
352
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($column) {
353
            return $this->prepareQuery($this->createModel())->sum($column);
354
        });
355
    }
356
357
    /**
358
     * Extract relationships.
359
     *
360
     * @param mixed $entity
361
     * @param array $attributes
362
     *
363
     * @return array
364
     */
365
    protected function extractRelations($entity, array $attributes)
366
    {
367
        $relations = [];
368
        $potential = array_diff(array_keys($attributes), $entity->getFillable());
369
370
        array_walk($potential, function ($item) use ($entity, $attributes, &$relations) {
371
            if (method_exists($entity, $item)) {
372
                $relations[$item] = [
373
                    'values' => $attributes[$item],
374
                    'class'  => get_class($entity->$item()),
375
                ];
376
            }
377
        });
378
379
        return $relations;
380
    }
381
382
    /**
383
     * Sync relationships.
384
     *
385
     * @param mixed $entity
386
     * @param array $relations
387
     * @param bool  $detaching
388
     *
389
     * @return void
390
     */
391
    protected function syncRelations($entity, array $relations, $detaching = true)
392
    {
393
        foreach ($relations as $method => $relation) {
394
            switch ($relation['class']) {
395
                case 'Illuminate\Database\Eloquent\Relations\BelongsToMany':
396
                default:
397
                    $entity->$method()->sync($relation['values'], $detaching);
398
                    break;
399
            }
400
        }
401
    }
402
}
403