Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Push — master ( 754e86...e0fed9 )
by Cristian
16:40 queued 01:19
created

Create::getRelationFieldsWithPivot()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 1
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Backpack\CRUD\app\Library\CrudPanel\Traits;
4
5
use Illuminate\Database\Eloquent\Relations\BelongsTo;
6
use Illuminate\Database\Eloquent\Relations\HasOne;
7
use Illuminate\Support\Arr;
8
9
trait Create
10
{
11
    /*
12
    |--------------------------------------------------------------------------
13
    |                                   CREATE
14
    |--------------------------------------------------------------------------
15
    */
16
17
    /**
18
     * Insert a row in the database.
19
     *
20
     * @param array $data All input values to be inserted.
21
     *
22
     * @return \Illuminate\Database\Eloquent\Model
23
     */
24
    public function create($data)
25
    {
26
        $data = $this->decodeJsonCastedAttributes($data);
0 ignored issues
show
Bug introduced by
It seems like decodeJsonCastedAttributes() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

26
        /** @scrutinizer ignore-call */ 
27
        $data = $this->decodeJsonCastedAttributes($data);
Loading history...
27
        $data = $this->compactFakeFields($data);
0 ignored issues
show
Bug introduced by
It seems like compactFakeFields() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

27
        /** @scrutinizer ignore-call */ 
28
        $data = $this->compactFakeFields($data);
Loading history...
28
29
        // omit the n-n relationships when updating the eloquent item
30
        $nn_relationships = Arr::pluck($this->getRelationFieldsWithPivot(), 'name');
31
        $item = $this->model->create(Arr::except($data, $nn_relationships));
32
33
        // if there are any relationships available, also sync those
34
        $this->createRelations($item, $data);
35
36
        return $item;
37
    }
38
39
    /**
40
     * Get all fields needed for the ADD NEW ENTRY form.
41
     *
42
     * @return array The fields with attributes and fake attributes.
43
     */
44
    public function getCreateFields()
45
    {
46
        return $this->fields();
0 ignored issues
show
Bug introduced by
It seems like fields() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

46
        return $this->/** @scrutinizer ignore-call */ fields();
Loading history...
47
    }
48
49
    /**
50
     * Get all fields with relation set (model key set on field).
51
     *
52
     * @return array The fields with model key set.
53
     */
54
    public function getRelationFields()
55
    {
56
        $fields = $this->fields();
57
        $relationFields = [];
58
59
        foreach ($fields as $field) {
60
            if (isset($field['model']) && $field['model'] !== false) {
61
                array_push($relationFields, $field);
62
            }
63
64
            if (isset($field['subfields']) &&
65
                is_array($field['subfields']) &&
66
                count($field['subfields'])) {
67
                foreach ($field['subfields'] as $subfield) {
68
                    array_push($relationFields, $subfield);
69
                }
70
            }
71
        }
72
73
        return $relationFields;
74
    }
75
76
    /**
77
     * Get all fields with n-n relation set (pivot table is true).
78
     *
79
     * @return array The fields with n-n relationships.
80
     */
81
    public function getRelationFieldsWithPivot()
82
    {
83
        $all_relation_fields = $this->getRelationFields();
84
85
        return Arr::where($all_relation_fields, function ($value, $key) {
86
            return isset($value['pivot']) && $value['pivot'];
87
        });
88
    }
89
90
    /**
91
     * Create the relations for the current model.
92
     *
93
     * @param \Illuminate\Database\Eloquent\Model $item The current CRUD model.
94
     * @param array                               $data The form data.
95
     */
96
    public function createRelations($item, $data)
97
    {
98
        $this->syncPivot($item, $data);
99
        $this->createOneToOneRelations($item, $data);
100
    }
101
102
    /**
103
     * Sync the declared many-to-many associations through the pivot field.
104
     *
105
     * @param \Illuminate\Database\Eloquent\Model $model The current CRUD model.
106
     * @param array                               $data  The form data.
107
     */
108
    public function syncPivot($model, $data)
109
    {
110
        $fields_with_relationships = $this->getRelationFields();
111
        foreach ($fields_with_relationships as $key => $field) {
112
            if (isset($field['pivot']) && $field['pivot']) {
113
                $values = isset($data[$field['name']]) ? $data[$field['name']] : [];
114
115
                // if a JSON was passed instead of an array, turn it into an array
116
                if (is_string($values)) {
117
                    $values = json_decode($values);
118
                }
119
120
                $relation_data = [];
121
                foreach ($values as $pivot_id) {
122
                    $pivot_data = [];
123
124
                    if (isset($field['pivotFields'])) {
125
                        foreach ($field['pivotFields'] as $pivot_field_name) {
126
                            $pivot_data[$pivot_field_name] = $data[$pivot_field_name][$pivot_id];
127
                        }
128
                    }
129
                    $relation_data[$pivot_id] = $pivot_data;
130
                }
131
132
                $model->{$field['name']}()->sync($relation_data);
133
            }
134
135
            if (isset($field['morph']) && $field['morph'] && isset($data[$field['name']])) {
136
                $values = $data[$field['name']];
137
                $model->{$field['name']}()->sync($values);
138
            }
139
        }
140
    }
141
142
    /**
143
     * Create any existing one to one relations for the current model from the form data.
144
     *
145
     * @param \Illuminate\Database\Eloquent\Model $item The current CRUD model.
146
     * @param array                               $data The form data.
147
     */
148
    private function createOneToOneRelations($item, $data)
149
    {
150
        $relationData = $this->getRelationDataFromFormData($data);
151
        $this->createRelationsForItem($item, $relationData);
152
    }
153
154
    /**
155
     * Create any existing one to one relations for the current model from the relation data.
156
     *
157
     * @param \Illuminate\Database\Eloquent\Model $item          The current CRUD model.
158
     * @param array                               $formattedData The form data.
159
     *
160
     * @return bool|null
161
     */
162
    private function createRelationsForItem($item, $formattedData)
163
    {
164
        if (! isset($formattedData['relations'])) {
165
            return false;
166
        }
167
        foreach ($formattedData['relations'] as $relationMethod => $relationData) {
168
            if (! isset($relationData['model'])) {
169
                continue;
170
            }
171
            $model = $relationData['model'];
172
            $relation = $item->{$relationMethod}();
173
174
            if ($relation instanceof BelongsTo) {
175
                $modelInstance = $model::find($relationData['values'])->first();
176
                if ($modelInstance != null) {
177
                    $relation->associate($modelInstance)->save();
178
                } else {
179
                    $relation->dissociate()->save();
180
                }
181
            } elseif ($relation instanceof HasOne) {
182
                if ($item->{$relationMethod} != null) {
183
                    $item->{$relationMethod}->update($relationData['values']);
184
                    $modelInstance = $item->{$relationMethod};
185
                } else {
186
                    $modelInstance = new $model($relationData['values']);
187
                    $relation->save($modelInstance);
188
                }
189
            }
190
191
            if (isset($relationData['relations'])) {
192
                $this->createRelationsForItem($modelInstance, ['relations' => $relationData['relations']]);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $modelInstance does not seem to be defined for all execution paths leading up to this point.
Loading history...
193
            }
194
        }
195
    }
196
197
    /**
198
     * Get a relation data array from the form data.
199
     * For each relation defined in the fields through the entity attribute, set the model, the parent model and the
200
     * attribute values.
201
     *
202
     * We traverse this relation array later to create the relations, for example:
203
     *
204
     * Current model HasOne Address, this Address (line_1, country_id) BelongsTo Country through country_id in Address Model.
205
     *
206
     * So when editing current model crud user have two fields address.line_1 and address.country (we infer country_id from relation)
207
     *
208
     * Those will be nested accordingly in this relation array, so address relation will have a nested relation with country.
209
     *
210
     *
211
     * @param array $data The form data.
212
     *
213
     * @return array The formatted relation data.
214
     */
215
    private function getRelationDataFromFormData($data)
216
    {
217
        $relation_fields = $this->getRelationFields();
218
        $relationData = [];
219
        foreach ($relation_fields as $relation_field) {
220
            $attributeKey = $this->parseRelationFieldNamesFromHtml([$relation_field])[0]['name'];
0 ignored issues
show
Bug introduced by
It seems like parseRelationFieldNamesFromHtml() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

220
            $attributeKey = $this->/** @scrutinizer ignore-call */ parseRelationFieldNamesFromHtml([$relation_field])[0]['name'];
Loading history...
221
222
            if (isset($relation_field['pivot']) && $relation_field['pivot'] !== true) {
223
                $key = implode('.relations.', explode('.', $this->getOnlyRelationEntity($relation_field)));
224
                $fieldData = Arr::get($relationData, 'relations.'.$key, []);
225
                if (! array_key_exists('model', $fieldData)) {
226
                    $fieldData['model'] = $relation_field['model'];
227
                }
228
                if (! array_key_exists('parent', $fieldData)) {
229
                    $fieldData['parent'] = $this->getRelationModel($attributeKey, -1);
0 ignored issues
show
Bug introduced by
The method getRelationModel() does not exist on Backpack\CRUD\app\Library\CrudPanel\Traits\Create. Did you maybe mean getRelationFields()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

229
                    /** @scrutinizer ignore-call */ 
230
                    $fieldData['parent'] = $this->getRelationModel($attributeKey, -1);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
230
                }
231
                $relatedAttribute = Arr::last(explode('.', $attributeKey));
232
                $fieldData['values'][$relatedAttribute] = Arr::get($data, $attributeKey);
233
234
                Arr::set($relationData, 'relations.'.$key, $fieldData);
235
            }
236
        }
237
238
        return $relationData;
239
    }
240
241
    public function getOnlyRelationEntity($relation_field)
242
    {
243
        $entity_array = explode('.', $relation_field['entity']);
244
245
        $relation_model = $this->getRelationModel($relation_field['entity'], -1);
246
247
        $related_method = Arr::last($entity_array);
248
249
        if (! method_exists($relation_model, $related_method)) {
250
            if (count($entity_array) <= 1) {
251
                return $relation_field['entity'];
252
            } else {
253
                array_pop($entity_array);
254
            }
255
256
            return implode('.', $entity_array);
257
        }
258
259
        return $relation_field['entity'];
260
    }
261
}
262