Passed
Push — master ( b5c04f...a16fba )
by Mario
02:12
created

WorksWithRelations::updateOrCreateHasMany()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 21
rs 9.8333
c 0
b 0
f 0
cc 4
nc 2
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
        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
72
     */
73
    protected function updateOrCreateHasOne(array $fillable, Model $model, Relation $relation)
74
    {
75
        if (array_key_exists('id', $fillable)) {
76
            $id = $fillable['id'];
77
        } else {
78
            $id = '';
79
        }
80
81
        return $relation->updateOrCreate(['id' => $id], array_except($fillable, ['id']));
82
    }
83
84
    /**
85
     * BelongsToOne relation updateOrCreate logic.
86
     *
87
     * @param array    $fillable The relation fillable.
88
     * @param Model    $model    The eloquent model.
89
     * @param Relation $relation The eloquent relation.
90
     *
91
     * @return Model
92
     */
93
    protected function updateOrCreateBelongsToOne(array $fillable, Model $model, Relation $relation)
94
    {
95
        $related = $relation->getRelated();
96
97
        if (!$relation->first()) {
98
            $record = $relation->associate($related->create($fillable));
99
            $model->save();
100
        } else {
101
            $record = $relation->update($fillable);
102
        }
103
104
        return $record;
105
    }
106
107
    /**
108
     * HasMany relation updateOrCreate logic.
109
     *
110
     * @param array    $fillable The relation fillable.
111
     * @param Model    $model    The eloquent model.
112
     * @param Relation $relation The eloquent relation.
113
     *
114
     * @return array
115
     */
116
    protected function updateOrCreateHasMany(array $fillable, Model $model, Relation $relation)
117
    {
118
        $records = [];
119
120
        if (count($fillable) > 1) {
121
            foreach ($fillable as $fields) {
122
                if (array_key_exists('id', $fields)) {
123
                    $id = $fields['id'];
124
                } else {
125
                    $id = '';
126
                }
127
128
                $record = $relation->updateOrCreate(['id' => $id], array_except($fields, ['id']));
129
                array_push($records, $record);
130
            }
131
        } else {
132
            $record = $this->updateOrCreateHasOne($fillable, $model, $relation);
133
            array_push($records, $record);
134
        }
135
136
        return $records;
137
    }
138
139
    /**
140
     * BelongsToMany relation updateOrCreate logic.
141
     *
142
     * @param array    $fillable The relation fillable.
143
     * @param Model    $model    The eloquent model.
144
     * @param Relation $relation The eloquent relation.
145
     *
146
     * @return array
147
     */
148
    protected function updateOrCreateBelongsToMany(array $fillable, Model $model, Relation $relation)
149
    {
150
        $keys = [];
151
        $records = [];
152
153
        $related = $relation->getRelated();
154
155
        if (count($fillable) > 1) {
156
            foreach ($fillable as $fields) {
157
                if (array_key_exists('id', $fields)) {
158
                    $id = $fields['id'];
159
                } else {
160
                    $id = '';
161
                }
162
163
                $record = $related->updateOrCreate(['id' => $id], array_except($fields, ['id']));
164
165
                array_push($keys, $record->id);
166
                array_push($records, $record);
167
            }
168
        } else {
169
            if (array_key_exists('id', $fillable)) {
170
                $id = $fillable['id'];
171
            } else {
172
                $id = '';
173
            }
174
175
            $record = $related->updateOrCreate(['id' => $id], array_except($fillable, ['id']));
176
177
            array_push($keys, $record->id);
178
            array_push($records, $record);
179
        }
180
181
        $relation->sync($keys);
182
183
        return $records;
184
    }
185
186
    /**
187
     * Throw an exception if array type request data is not named after an existent Eloquent relation.
188
     *
189
     * @param Model  $model        The eloquent model.
190
     * @param string $relationName The eloquent relation name.
191
     *
192
     * @throws MassAssignmentException
193
     *
194
     * @return void
195
     */
196
    private function _checkRelationExists(Model $model, string $relationName)
197
    {
198
        if (!method_exists($model, $relationName) || !$model->{$relationName}() instanceof Relation) {
199
            if (Lang::has('resource-controller.data2relationinexistent')) {
200
                $message = trans('resource-controller.data2relationinexistent', ['relationName' => $relationName]);
201
            } else {
202
                $message = "Array type request data '{$relationName}' must be named after an existent relation.";
203
            }
204
205
            throw new MassAssignmentException($message);
206
        }
207
    }
208
}
209