Passed
Push — master ( 23764c...420f5e )
by Mario
02:38
created

WorksWithRelations::updateOrCreateHasMany()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

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