Completed
Pull Request — master (#138)
by
unknown
04:06
created

EloquentRepository::update()   C

Complexity

Conditions 7
Paths 18

Size

Total Lines 34
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 34
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 18
nc 18
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\Database\Eloquent\Model;
19
use Illuminate\Pagination\Paginator;
20
use Rinvex\Repository\Exceptions\RepositoryException;
21
22
class EloquentRepository extends BaseRepository
23
{
24
    /**
25
     * Create a new repository model instance.
26
     *
27
     * @throws \Rinvex\Repository\Exceptions\RepositoryException
28
     *
29
     * @return \Illuminate\Database\Eloquent\Model
30
     */
31
    public function createModel()
32
    {
33
        if (is_string($model = $this->getModel())) {
34
            if (! class_exists($class = '\\'.ltrim($model, '\\'))) {
35
                throw new RepositoryException("Class {$model} does NOT exist!");
36
            }
37
38
            $model = $this->getContainer()->make($class);
39
        }
40
41
        if (! $model instanceof Model) {
42
            throw new RepositoryException("Class {$model} must be an instance of \\Illuminate\\Database\\Eloquent\\Model");
43
        }
44
45
        return $model;
46
    }
47
48
    /**
49
     * Find an entity by it's primary key.
50
     *
51
     * @param int   $id
52
     * @param array $attributes
53
     *
54
     * @return \Illuminate\Database\Eloquent\Model
55
     */
56
    public function find($id, $attributes = ['*'])
57
    {
58
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($id, $attributes) {
59
            return $this->prepareQuery($this->createModel())->find($id, $attributes);
60
        });
61
    }
62
63
    /**
64
     * Find an entity by one of it's attributes.
65
     *
66
     * @param string $attribute
67
     * @param string $value
68
     * @param array  $attributes
69
     *
70
     * @return \Illuminate\Database\Eloquent\Model
71
     */
72
    public function findBy($attribute, $value, $attributes = ['*'])
73
    {
74
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($attribute, $value, $attributes) {
75
            return $this->prepareQuery($this->createModel())->where($attribute, '=', $value)->first($attributes);
76
        });
77
    }
78
79
    /**
80
     * Find all entities.
81
     *
82
     * @param array $attributes
83
     *
84
     * @return \Illuminate\Support\Collection
85
     */
86
    public function findAll($attributes = ['*'])
87
    {
88
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($attributes) {
89
            return $this->prepareQuery($this->createModel())->get($attributes);
90
        });
91
    }
92
93
    /**
94
     * Paginate all entities.
95
     *
96
     * @param int|null $perPage
97
     * @param array    $attributes
98
     * @param string   $pageName
99
     * @param int|null $page
100
     *
101
     * @throws \InvalidArgumentException
102
     *
103
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
104
     */
105
    public function paginate($perPage = null, $attributes = ['*'], $pageName = 'page', $page = null)
106
    {
107
        $page = $page ?: Paginator::resolveCurrentPage($pageName);
108
109
        return $this->executeCallback(get_called_class(), __FUNCTION__, array_merge(func_get_args(), compact('page')), function () use ($perPage, $attributes, $pageName, $page) {
110
            return $this->prepareQuery($this->createModel())->paginate($perPage, $attributes, $pageName, $page);
111
        });
112
    }
113
114
    /**
115
     * Paginate all entities into a simple paginator.
116
     *
117
     * @param int|null $perPage
118
     * @param array    $attributes
119
     * @param string   $pageName
120
     * @param int|null $page
121
     *
122
     * @return \Illuminate\Contracts\Pagination\Paginator
123
     */
124
    public function simplePaginate($perPage = null, $attributes = ['*'], $pageName = 'page', $page = null)
125
    {
126
        $page = $page ?: Paginator::resolveCurrentPage($pageName);
127
128
        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...
129
            return $this->prepareQuery($this->createModel())->simplePaginate($perPage, $attributes, $pageName, $page);
130
        });
131
    }
132
133
    /**
134
     * Find all entities matching where conditions.
135
     *
136
     * @param array $where
137
     * @param array $attributes
138
     *
139
     * @return \Illuminate\Support\Collection
140
     */
141
    public function findWhere(array $where, $attributes = ['*'])
142
    {
143
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($where, $attributes) {
144
            list($attribute, $operator, $value, $boolean) = array_pad($where, 4, null);
145
146
            $this->where($attribute, $operator, $value, $boolean);
147
148
            return $this->prepareQuery($this->createModel())->get($attributes);
149
        });
150
    }
151
152
    /**
153
     * Find all entities matching whereIn conditions.
154
     *
155
     * @param array $where
156
     * @param array $attributes
157
     *
158
     * @return \Illuminate\Support\Collection
159
     */
160
    public function findWhereIn(array $where, $attributes = ['*'])
161
    {
162
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($where, $attributes) {
163
            list($attribute, $values, $boolean, $not) = array_pad($where, 4, null);
164
165
            $this->whereIn($attribute, $values, $boolean, $not);
166
167
            return $this->prepareQuery($this->createModel())->get($attributes);
168
        });
169
    }
170
171
    /**
172
     * Find all entities matching whereNotIn conditions.
173
     *
174
     * @param array $where
175
     * @param array $attributes
176
     *
177
     * @return \Illuminate\Support\Collection
178
     */
179
    public function findWhereNotIn(array $where, $attributes = ['*'])
180
    {
181
        return $this->executeCallback(get_called_class(), __FUNCTION__, func_get_args(), function () use ($where, $attributes) {
182
            list($attribute, $values, $boolean) = array_pad($where, 3, null);
183
184
            $this->whereNotIn($attribute, $values, $boolean);
185
186
            return $this->prepareQuery($this->createModel())->get($attributes);
187
        });
188
    }
189
190
    /**
191
     * Create a new entity with the given attributes and relationships.
192
     *
193
     * @param array $attributes
194
     * @param bool $syncRelations
195
     *
196
     * @return array
197
     */
198
    public function create(array $attributes = [], bool $syncRelations = false)
199
    {
200
        // Create a new instance
201
        $instance = $this->createModel();
202
        // Fire the created event
203
        $this->getContainer('events')->fire($this->getRepositoryId().'.entity.creating', [$this, $instance]);
204
        // Extract relationships
205
        if ($syncRelations) {
206
            $relations = $this->extractRelations($instance, $attributes);
207
208
            array_forget($attributes, array_keys($relations));
209
        }
210
        // Fill instance with data
211
        $instance->fill($attributes);
212
        // Save the instance
213
        $created = $instance->save();
214
        // Sync relationships
215
        if ($syncRelations && isset($relations)) {
216
            $this->syncRelations($instance, $relations);
217
        }
218
        // Fire the created event
219
        $this->getContainer('events')->fire($this->getRepositoryId().'.entity.created', [$this, $instance]);
220
        // Return instance
221
        return [
222
            $created,
223
            $instance,
224
        ];
225
    }
226
227
    /**
228
     * Update an entity with the given attributes.
229
     *
230
     * @param mixed $id
231
     * @param array $attributes
232
     * @param bool $syncRelations
233
     *
234
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<boolean|Model>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
235
     */
236
    public function update($id, array $attributes = [], bool $syncRelations = false)
237
    {
238
        $updated = false;
239
        // Find the given instance
240
        $instance = $id instanceof Model ? $id : $this->find($id);
241
        if ($instance) {
242
            // Fire the updated event
243
            $this->getContainer('events')->fire($this->getRepositoryId().'.entity.updating', [$this, $instance]);
244
            // Extract relationships
245
            if ($syncRelations) {
246
                $relations = $this->extractRelations($instance, $attributes);
247
                array_forget($attributes, array_keys($relations));
248
            }
249
            // Fill instance with data
250
            $instance->fill($attributes);
251
            //Check if we are updating attributes values
252
            $dirty = $instance->getDirty();
253
            // Update the instance
254
            $updated = $instance->save();
255
            // Sync relationships
256
            if ($syncRelations && isset($relations)) {
257
                $this->syncRelations($instance, $relations);
258
            }
259
            if (count($dirty) > 0) {
260
                // Fire the updated event
261
                $this->getContainer('events')->fire($this->getRepositoryId().'.entity.updated', [$this, $instance]);
262
            }
263
        }
264
        
265
        return [
266
            $updated,
267
            $instance,
268
        ];
269
    }
270
271
    /**
272
     * Delete an entity with the given id.
273
     *
274
     * @param mixed $id
275
     *
276
     * @return array
277
     */
278
    public function delete($id)
279
    {
280
        // Find the given instance
281
        $deleted  = false;
282
        $instance = $id instanceof Model ? $id : $this->find($id);
283
284
        if ($instance) {
285
            // Delete the instance
286
            $deleted = $instance->delete();
287
288
            // Fire the deleted event
289
            $this->getContainer('events')->fire($this->getRepositoryId().'.entity.deleted', [$this, $instance]);
290
        }
291
292
        return [
293
            $deleted,
294
            $instance,
295
        ];
296
    }
297
298
    /**
299
     * Extract relationships.
300
     *
301
     * @param mixed $entity
302
     * @param array $attributes
303
     *
304
     * @return array
305
     */
306
    protected function extractRelations($entity, array $attributes)
307
    {
308
        $relations = [];
309
        $potential = array_diff(array_keys($attributes), $entity->getFillable());
310
        array_walk($potential, function ($relation) use ($entity, $attributes, &$relations) {
311
            if (method_exists($entity, $relation)) {
312
                $relations[$relation] = [
313
                    'values' => $attributes[$relation],
314
                    'class'  => get_class($entity->$relation()),
315
                ];
316
            }
317
        });
318
        return $relations;
319
    }
320
    /**
321
     * Sync relationships.
322
     *
323
     * @param mixed $entity
324
     * @param array $relations
325
     * @param bool  $detaching
326
     *
327
     * @return void
328
     */
329
    protected function syncRelations($entity, array $relations, $detaching = true)
330
    {
331
        foreach ($relations as $method => $relation) {
332
            switch ($relation['class']) {
333
                case 'Illuminate\Database\Eloquent\Relations\BelongsToMany':
334
                default:
335
                    $entity->$method()->sync((array) $relation['values'], $detaching);
336
                    break;
337
            }
338
        }
339
    }
340
}
341