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
Pull Request — master (#3654)
by
unknown
13:52
created

Create::getOnlyRelationEntity()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 3
nop 1
dl 0
loc 19
rs 9.9332
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
        $data = $this->changeBelongsToNamesFromRelationshipToForeignKey($data);
0 ignored issues
show
Bug introduced by
It seems like changeBelongsToNamesFromRelationshipToForeignKey() 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

28
        /** @scrutinizer ignore-call */ 
29
        $data = $this->changeBelongsToNamesFromRelationshipToForeignKey($data);
Loading history...
29
30
        // omit the n-n relationships when updating the eloquent item
31
        $nn_relationships = Arr::pluck($this->getRelationFieldsWithPivot(), 'name');
32
33
        $item = $this->model->create(Arr::except($data, $nn_relationships));
34
35
        // if there are any relationships available, also sync those
36
        $this->createRelations($item, $data);
37
38
        return $item;
39
    }
40
41
    /**
42
     * Get all fields needed for the ADD NEW ENTRY form.
43
     *
44
     * @return array The fields with attributes and fake attributes.
45
     */
46
    public function getCreateFields()
47
    {
48
        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

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

222
            $attributeKey = $this->/** @scrutinizer ignore-call */ parseRelationFieldNamesFromHtml([$relation_field])[0]['name'];
Loading history...
223
224
            if (! is_null(Arr::get($data, $attributeKey)) && isset($relation_field['pivot']) && $relation_field['pivot'] !== true) {
225
                $key = implode('.relations.', explode('.', $this->getOnlyRelationEntity($relation_field)));
0 ignored issues
show
Bug introduced by
It seems like getOnlyRelationEntity() 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

225
                $key = implode('.relations.', explode('.', $this->/** @scrutinizer ignore-call */ getOnlyRelationEntity($relation_field)));
Loading history...
226
                $fieldData = Arr::get($relationData, 'relations.'.$key, []);
227
                if (! array_key_exists('model', $fieldData)) {
228
                    $fieldData['model'] = $relation_field['model'];
229
                }
230
                if (! array_key_exists('parent', $fieldData)) {
231
                    $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

231
                    /** @scrutinizer ignore-call */ 
232
                    $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...
232
                }
233
                $relatedAttribute = Arr::last(explode('.', $attributeKey));
234
                $fieldData['values'][$relatedAttribute] = Arr::get($data, $attributeKey);
235
236
                Arr::set($relationData, 'relations.'.$key, $fieldData);
237
            }
238
        }
239
240
        return $relationData;
241
    }
242
}
243