WorksWithRelations   A
last analyzed

Complexity

Total Complexity 37

Size/Duplication

Total Lines 206
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 37
eloc 79
dl 0
loc 206
rs 9.44
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
B handleRelations() 0 15 8
A updateOrCreateRelations() 0 9 3
A updateOrCreateBelongsToOne() 0 16 3
B updateOrCreateHasMany() 0 34 10
A _checkRelationExists() 0 10 4
A updateOrCreateHasOne() 0 17 5
A updateOrCreateBelongsToMany() 0 25 4
1
<?php
2
3
namespace RafflesArgentina\ResourceController\Traits;
4
5
use Lang;
6
7
use Illuminate\Http\Request;
8
use Illuminate\Database\Eloquent\Model;
9
use Illuminate\Database\Eloquent\Relations\Relation;
10
use Illuminate\Database\Eloquent\Relations\{HasOne, MorphOne, BelongsTo};
11
use Illuminate\Database\Eloquent\Relations\{HasMany, MorphMany, MorphToMany, BelongsToMany};
12
use Illuminate\Database\Eloquent\MassAssignmentException;
13
14
trait WorksWithRelations
15
{
16
    /**
17
     * Update or create relations handling array type request data.
18
     *
19
     * @param Request $request The Request object.
20
     * @param Model   $model   The eloquent model.
21
     *
22
     * @return void
23
     */
24
    public function updateOrCreateRelations(Request $request, Model $model)
25
    {
26
        $parameterBag = $request->request;
27
        foreach ($parameterBag->all() as $name => $attributes) {
28
            if (is_array($request->{$name})) {
29
                $this->_checkRelationExists($model, $name);
30
31
                $relation = $model->{$name}();
32
                $this->handleRelations($attributes, $model, $relation);
33
            }
34
        }
35
    }
36
37
    /**
38
     * Handle relations.
39
     *
40
     * @param array    $fillable The relation fillable.
41
     * @param Model    $model    The eloquent model.
42
     * @param Relation $relation The eloquent relation.
43
     *
44
     * @return void
45
     */
46
    protected function handleRelations(array $fillable, Model $model, Relation $relation)
47
    {
48
        switch (true) {
49
        case $relation instanceof HasOne || $relation instanceof MorphOne:
50
            $this->updateOrCreateHasOne($fillable, $model, $relation);
51
            break;
52
        case $relation instanceof BelongsTo:
53
            $this->updateOrCreateBelongsToOne($fillable, $model, $relation);
54
            break;
55
        case $relation instanceof HasMany || $relation instanceof MorphMany:
56
            $this->updateOrCreateHasMany($fillable, $model, $relation);
57
            break;
58
        case $relation instanceof BelongsToMany || $relation instanceof MorphToMany:
59
            $this->updateOrCreateBelongsToMany($fillable, $model, $relation);
60
            break;
61
        }
62
    }
63
64
    /**
65
     * HasOne relation updateOrCreate logic.
66
     *
67
     * @param array    $fillable The relation fillable.
68
     * @param Model    $model    The eloquent model.
69
     * @param Relation $relation The eloquent relation.
70
     *
71
     * @return Model | null
72
     */
73
    protected function updateOrCreateHasOne(array $fillable, Model $model, Relation $relation)
74
    {
75
        $id = '';
76
77
        if (array_key_exists('id', $fillable)) {
78
            $id = $fillable['id'];
79
        }
80
81
        if (array_except($fillable, ['id'])) {
82
            if (property_exists($this, 'pruneHasOne') && $this->pruneHasOne !== false) {
83
                $relation->update($fillable);
84
            }
85
86
            return $relation->updateOrCreate(['id' => $id], $fillable);
87
        }
88
89
        return null;
90
    }
91
92
    /**
93
     * BelongsToOne relation updateOrCreate logic.
94
     *
95
     * @param array    $fillable The relation fillable.
96
     * @param Model    $model    The eloquent model.
97
     * @param Relation $relation The eloquent relation.
98
     *
99
     * @return Model
100
     */
101
    protected function updateOrCreateBelongsToOne(array $fillable, Model $model, Relation $relation)
102
    {
103
        $related = $relation->getRelated();
104
105
        if (array_except($fillable, ['id'])) {
106
            if (!$relation->first()) {
107
                $record = $relation->associate($related->create($fillable));
108
                $model->save();
109
            } else {
110
                $record = $relation->update($fillable);
111
            }
112
113
            return $record;
114
        }
115
116
        return null;
117
    }
118
119
    /**
120
     * HasMany relation updateOrCreate logic.
121
     *
122
     * @param array    $fillable The relation fillable.
123
     * @param Model    $model    The eloquent model.
124
     * @param Relation $relation The eloquent relation.
125
     *
126
     * @return array
127
     */
128
    protected function updateOrCreateHasMany(array $fillable, Model $model, Relation $relation)
129
    {
130
        $keys = [];
131
        $id = '';
132
        $records = [];
133
134
        foreach ($fillable as $fields) {
135
            if (is_array($fields)) {
136
                if (array_key_exists('id', $fields)) {
137
                    $id = $fields['id'];
138
                }
139
140
                if (array_except($fields, ['id'])) {
141
                    $record = $relation->updateOrCreate(['id' => $id], $fields);
142
                    array_push($keys, $record->id);
143
                    array_push($records, $record);
144
                }
145
            } else {
146
                if (array_except($fillable, ['id'])) {
147
                    $record = $relation->updateOrCreate(['id' => $id], $fillable);
148
                    array_push($keys, $record->id);
149
                    array_push($records, $record);
150
                }
151
            }
152
        }
153
154
        if ($keys && (property_exists($this, 'pruneHasMany') && $this->pruneHasMany !== false)) {
155
            $notIn = $relation->getRelated()->whereNotIn('id', $keys)->get();
156
            foreach ($notIn as $record) {
157
                $record->delete();
158
            }
159
        }
160
161
        return $records;
162
    }
163
164
    /**
165
     * BelongsToMany relation updateOrCreate logic.
166
     *
167
     * @param array    $fillable The relation fillable.
168
     * @param Model    $model    The eloquent model.
169
     * @param Relation $relation The eloquent relation.
170
     *
171
     * @return array
172
     */
173
    protected function updateOrCreateBelongsToMany(array $fillable, Model $model, Relation $relation)
174
    {
175
        $keys = [];
176
        $records = [];
177
178
        $related = $relation->getRelated();
179
180
        foreach ($fillable as $fields) {
181
            if (array_key_exists('id', $fields)) {
182
                $id = $fields['id'];
183
                array_push($keys, $id);
184
            } else {
185
                $id = '';
186
            }
187
188
            if (array_except($fields, ['id'])) {
189
                $record = $related->updateOrCreate(['id' => $id], $fields);
190
                array_push($keys, $record->id);
191
                array_push($records, $record);
192
            }
193
        }
194
195
        $relation->sync($keys);
196
197
        return $records;
198
    }
199
200
    /**
201
     * Throw an exception if array type request data is not named after an existent Eloquent relation.
202
     *
203
     * @param Model  $model        The eloquent model.
204
     * @param string $relationName The eloquent relation name.
205
     *
206
     * @throws MassAssignmentException
207
     *
208
     * @return void
209
     */
210
    private function _checkRelationExists(Model $model, string $relationName)
211
    {
212
        if (!method_exists($model, $relationName) || !$model->{$relationName}() instanceof Relation) {
213
            if (Lang::has('resource-controller.data2relationinexistent')) {
214
                $message = trans('resource-controller.data2relationinexistent', ['relationName' => $relationName]);
215
            } else {
216
                $message = "Array type request data '{$relationName}' must be named after an existent relation.";
217
            }
218
219
            throw new MassAssignmentException($message);
220
        }
221
    }
222
}
223