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

Test Setup Failed
Pull Request — master (#4002)
by
unknown
24:42 queued 09:36
created

Create::createOneToOneRelations()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
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
     * @return \Illuminate\Database\Eloquent\Model
22
     */
23
    public function create($data)
24
    {
25
        $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

25
        /** @scrutinizer ignore-call */ 
26
        $data = $this->decodeJsonCastedAttributes($data);
Loading history...
26
        $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

26
        /** @scrutinizer ignore-call */ 
27
        $data = $this->compactFakeFields($data);
Loading history...
27
        $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

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

47
        return $this->/** @scrutinizer ignore-call */ fields();
Loading history...
48
    }
49
50
    /**
51
     * Get all fields with relation set (model key set on field).
52
     *
53
     * @return array The fields with model key set.
54
     */
55
    public function getRelationFields()
56
    {
57
        $fields = $this->getCleanStateFields();
0 ignored issues
show
Bug introduced by
It seems like getCleanStateFields() 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

57
        /** @scrutinizer ignore-call */ 
58
        $fields = $this->getCleanStateFields();
Loading history...
58
        $relationFields = [];
59
60
        foreach ($fields as $field) {
61
            if (isset($field['model']) && $field['model'] !== false) {
62
                array_push($relationFields, $field);
63
            }
64
65
            if (isset($field['subfields']) &&
66
                is_array($field['subfields']) &&
67
                count($field['subfields'])) {
68
                foreach ($field['subfields'] as $subfield) {
69
                    array_push($relationFields, $subfield);
70
                }
71
            }
72
        }
73
74
        return $relationFields;
75
    }
76
77
    /**
78
     * Get all fields with n-n relation set (pivot table is true).
79
     *
80
     * @return array The fields with n-n relationships.
81
     */
82
    public function getRelationFieldsWithPivot()
83
    {
84
        $all_relation_fields = $this->getRelationFields();
85
86
        return Arr::where($all_relation_fields, function ($value, $key) {
87
            return isset($value['pivot']) && $value['pivot'];
88
        });
89
    }
90
91
    /**
92
     * Create the relations for the current model.
93
     *
94
     * @param  \Illuminate\Database\Eloquent\Model  $item  The current CRUD model.
95
     * @param  array  $data  The form data.
96
     */
97
    public function createRelations($item, $data)
98
    {
99
        $this->syncPivot($item, $data);
100
        $this->createOneToOneRelations($item, $data);
101
    }
102
103
    /**
104
     * Sync the declared many-to-many associations through the pivot field.
105
     *
106
     * @param  \Illuminate\Database\Eloquent\Model  $model  The current CRUD model.
107
     * @param  array  $data  The form data.
108
     */
109
    public function syncPivot($model, $data)
110
    {
111
        $fields_with_relationships = $this->getRelationFields();
112
        foreach ($fields_with_relationships as $key => $field) {
113
            if (isset($field['pivot']) && $field['pivot']) {
114
                $values = isset($data[$field['name']]) ? $data[$field['name']] : [];
115
116
                // if a JSON was passed instead of an array, turn it into an array
117
                if (is_string($values)) {
118
                    $values = json_decode($values, true);
119
                }
120
121
                $relation_data = [];
122
                if (isset($field['fields'])) {
123
                    foreach ($values as $pivot_row) {
124
                        $relation_data[$pivot_row[$field['name']]] = Arr::except($pivot_row, $field['name']);
125
                    }
126
                }
127
128
                // if there is no relation data, and the values array is single dimensional we have
129
                // an array of keys with no aditional pivot data. sync those.
130
                if (empty($relation_data) && count($values) == count($values, COUNT_RECURSIVE)) {
131
                    $relation_data = array_values($values);
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
     * @return bool|null
162
     */
163
    private function createRelationsForItem($item, $formattedData)
164
    {
165
        if (! isset($formattedData['relations'])) {
166
            return false;
167
        }
168
        foreach ($formattedData['relations'] as $relationMethod => $relationData) {
169
            if (! isset($relationData['model'])) {
170
                continue;
171
            }
172
            $model = $relationData['model'];
173
            $relation = $item->{$relationMethod}();
174
175
            if ($relation instanceof BelongsTo) {
176
                $modelInstance = $model::find($relationData['values'])->first();
177
                if ($modelInstance != null) {
178
                    $relation->associate($modelInstance)->save();
179
                } else {
180
                    $relation->dissociate()->save();
181
                }
182
            } elseif ($relation instanceof HasOne) {
183
                if ($item->{$relationMethod} != null) {
184
                    $item->{$relationMethod}->update($relationData['values']);
185
                    $modelInstance = $item->{$relationMethod};
186
                } else {
187
                    $modelInstance = new $model($relationData['values']);
188
                    $relation->save($modelInstance);
189
                }
190
            }
191
192
            if (isset($relationData['relations'])) {
193
                $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...
194
            }
195
        }
196
    }
197
198
    /**
199
     * Get a relation data array from the form data.
200
     * For each relation defined in the fields through the entity attribute, set the model, the parent model and the
201
     * attribute values.
202
     *
203
     * We traverse this relation array later to create the relations, for example:
204
     *
205
     * Current model HasOne Address, this Address (line_1, country_id) BelongsTo Country through country_id in Address Model.
206
     *
207
     * So when editing current model crud user have two fields address.line_1 and address.country (we infer country_id from relation)
208
     *
209
     * Those will be nested accordingly in this relation array, so address relation will have a nested relation with country.
210
     *
211
     *
212
     * @param  array  $data  The form data.
213
     * @return array The formatted relation data.
214
     */
215
    private function getRelationDataFromFormData($data)
216
    {
217
        $relation_fields = $this->getRelationFields();
218
219
        //remove fields that are not in the submitted form data
220
        $relation_fields = array_filter($relation_fields, function ($item) use ($data) {
221
            return Arr::has($data, $item['name']);
222
        });
223
224
        $relationData = [];
225
        foreach ($relation_fields as $relation_field) {
226
            $attributeKey = $relation_field['name'];
227
228
            if (! is_null(Arr::get($data, $attributeKey)) && isset($relation_field['pivot']) && $relation_field['pivot'] !== true) {
229
                $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

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

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