Passed
Push — master ( b633a0...fc5539 )
by Mario
02:10
created

WorksWithRelations::updateOrCreateBelongsToMany()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 41
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 26
dl 0
loc 41
rs 8.4444
c 0
b 0
f 0
cc 8
nc 10
nop 3
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
        $nonEmpties = array_filter($parameterBag->all());
28
        foreach ($nonEmpties as $name => $attributes) {
29
            if (is_array($request->{$name})) {
30
                $this->_checkRelationExists($model, $name);
31
32
                $relation = $model->{$name}();
33
                $this->handleRelations($attributes, $model, $relation);
34
            }
35
        }
36
    }
37
38
    /**
39
     * Handle relations.
40
     *
41
     * @param array    $fillable The relation fillable.
42
     * @param Model    $model    The eloquent model.
43
     * @param Relation $relation The eloquent relation.
44
     *
45
     * @return void
46
     */
47
    protected function handleRelations(array $fillable, Model $model, Relation $relation)
48
    {
49
        switch (true) {
50
        case $relation instanceof HasOne || $relation instanceof MorphOne:
51
            $this->updateOrCreateHasOne($fillable, $model, $relation);
52
            break;
53
        case $relation instanceof BelongsTo:
54
            $this->updateOrCreateBelongsToOne($fillable, $model, $relation);
55
            break;
56
        case $relation instanceof HasMany || $relation instanceof MorphMany:
57
            $this->updateOrCreateHasMany($fillable, $model, $relation);
58
            break;
59
        case $relation instanceof BelongsToMany || $relation instanceof MorphToMany:
60
            $this->updateOrCreateBelongsToMany($fillable, $model, $relation);
61
            break;
62
        }
63
    }
64
65
    /**
66
     * HasOne relation updateOrCreate logic.
67
     *
68
     * @param array    $fillable The relation fillable.
69
     * @param Model    $model    The eloquent model.
70
     * @param Relation $relation The eloquent relation.
71
     *
72
     * @return Model | null
73
     */
74
    protected function updateOrCreateHasOne(array $fillable, Model $model, Relation $relation)
75
    {
76
        if (array_key_exists('id', $fillable)) {
77
            $id = $fillable['id'];
78
        } else {
79
            $id = '';
80
        }
81
82
        if (array_except($fillable, ['id'])) {
83
            return $relation->updateOrCreate(['id' => $id], $fillable);
84
        }
85
86
        return null;
87
    }
88
89
    /**
90
     * BelongsToOne relation updateOrCreate logic.
91
     *
92
     * @param array    $fillable The relation fillable.
93
     * @param Model    $model    The eloquent model.
94
     * @param Relation $relation The eloquent relation.
95
     *
96
     * @return Model
97
     */
98
    protected function updateOrCreateBelongsToOne(array $fillable, Model $model, Relation $relation)
99
    {
100
        $related = $relation->getRelated();
101
102
        if (array_except($fillable, ['id'])) {
103
            if (!$relation->first()) {
104
                $record = $relation->associate($related->create($fillable));
105
                $model->save();
106
            } else {
107
                $record = $relation->update($fillable);
108
            }
109
110
            return $record;
111
        }
112
113
        return null;
114
    }
115
116
    /**
117
     * HasMany relation updateOrCreate logic.
118
     *
119
     * @param array    $fillable The relation fillable.
120
     * @param Model    $model    The eloquent model.
121
     * @param Relation $relation The eloquent relation.
122
     *
123
     * @return array
124
     */
125
    protected function updateOrCreateHasMany(array $fillable, Model $model, Relation $relation)
126
    {
127
        $records = [];
128
129
        if (count($fillable) > 1) {
130
            foreach ($fillable as $fields) {
131
                if (array_key_exists('id', $fields)) {
132
                    $id = $fields['id'];
133
                } else {
134
                    $id = '';
135
                }
136
137
                if (array_except($fields, ['id'])) {
138
                    $record = $relation->updateOrCreate(['id' => $id], $fields);
139
                    array_push($records, $record);
140
                }
141
            }
142
        } else {
143
            $record = $this->updateOrCreateHasOne($fillable, $model, $relation);
144
            array_push($records, $record);
145
        }
146
147
        return $records;
148
    }
149
150
    /**
151
     * BelongsToMany relation updateOrCreate logic.
152
     *
153
     * @param array    $fillable The relation fillable.
154
     * @param Model    $model    The eloquent model.
155
     * @param Relation $relation The eloquent relation.
156
     *
157
     * @return array
158
     */
159
    protected function updateOrCreateBelongsToMany(array $fillable, Model $model, Relation $relation)
160
    {
161
        $keys = [];
162
        $records = [];
163
164
        $related = $relation->getRelated();
165
166
        if (count($fillable) > 1) {
167
            foreach ($fillable as $fields) {
168
                if (array_key_exists('id', $fields)) {
169
                    $id = $fields['id'];
170
                } else {
171
                    $id = '';
172
                }
173
174
                if (array_except($fields, ['id'])) {
175
                    $record = $related->updateOrCreate(['id' => $id], $fields);
176
                    array_push($keys, $record->id);
177
                    array_push($records, $record);
178
                }
179
            }
180
        } else {
181
            if (array_key_exists('id', $fillable)) {
182
                $id = $fillable['id'];
183
                array_push($keys, $id);
184
            } else {
185
                $id = '';
186
            }
187
188
            if (array_except($fillable, ['id'])) {
189
                $record = $related->updateOrCreate(['id' => $id], $fillable);
190
                array_push($keys, $record->id);
191
                array_push($records, $record);
192
            }
193
        }
194
195
        if ($keys) {
196
            $relation->sync($keys);
197
        }
198
199
        return $records;
200
    }
201
202
    /**
203
     * Throw an exception if array type request data is not named after an existent Eloquent relation.
204
     *
205
     * @param Model  $model        The eloquent model.
206
     * @param string $relationName The eloquent relation name.
207
     *
208
     * @throws MassAssignmentException
209
     *
210
     * @return void
211
     */
212
    private function _checkRelationExists(Model $model, string $relationName)
213
    {
214
        if (!method_exists($model, $relationName) || !$model->{$relationName}() instanceof Relation) {
215
            if (Lang::has('resource-controller.data2relationinexistent')) {
216
                $message = trans('resource-controller.data2relationinexistent', ['relationName' => $relationName]);
217
            } else {
218
                $message = "Array type request data '{$relationName}' must be named after an existent relation.";
219
            }
220
221
            throw new MassAssignmentException($message);
222
        }
223
    }
224
}
225