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 Failed
Pull Request — master (#3410)
by
unknown
23:41 queued 08:26
created

Update::getToManyRelationAttributeValue()   A

Complexity

Conditions 6
Paths 4

Size

Total Lines 28
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 4
nop 3
dl 0
loc 28
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
namespace Backpack\CRUD\app\Library\CrudPanel\Traits;
4
5
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
6
use Illuminate\Database\Eloquent\Relations\HasMany;
7
use Illuminate\Database\Eloquent\Relations\HasOne;
8
use Illuminate\Database\Eloquent\Relations\MorphMany;
9
use Illuminate\Database\Eloquent\Relations\MorphOne;
10
use Illuminate\Database\Eloquent\Relations\MorphToMany;
11
use Illuminate\Support\Arr;
12
13
trait Update
14
{
15
    /*
16
    |--------------------------------------------------------------------------
17
    |                                   UPDATE
18
    |--------------------------------------------------------------------------
19
    */
20
21
    /**
22
     * Update a row in the database.
23
     *
24
     * @param int   $id   The entity's id
25
     * @param array $data All inputs to be updated.
26
     *
27
     * @return object
28
     */
29
    public function update($id, $data)
30
    {
31
        $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

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

32
        /** @scrutinizer ignore-call */ 
33
        $data = $this->compactFakeFields($data);
Loading history...
33
        $item = $this->model->findOrFail($id);
34
35
        // omit the n-n relationships when updating the eloquent item
36
        $nn_relationships = Arr::pluck($this->getRelationFieldsWithPivot(), 'name');
0 ignored issues
show
Bug introduced by
It seems like getRelationFieldsWithPivot() 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

36
        $nn_relationships = Arr::pluck($this->/** @scrutinizer ignore-call */ getRelationFieldsWithPivot(), 'name');
Loading history...
37
38
        // handle BelongsTo 1:1 relations
39
        $item = $this->associateOrDissociateBelongsToRelations($item, $data);
0 ignored issues
show
Bug introduced by
It seems like associateOrDissociateBelongsToRelations() 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

39
        /** @scrutinizer ignore-call */ 
40
        $item = $this->associateOrDissociateBelongsToRelations($item, $data);
Loading history...
40
41
        $item->fill(Arr::except($data, $nn_relationships));
42
        $item->save();
43
44
        $this->createRelations($item, $data);
0 ignored issues
show
Bug introduced by
It seems like createRelations() 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

44
        $this->/** @scrutinizer ignore-call */ 
45
               createRelations($item, $data);
Loading history...
45
46
        return $item;
47
    }
48
49
    /**
50
     * Get all fields needed for the EDIT ENTRY form.
51
     *
52
     * @param int $id The id of the entry that is being edited.
53
     *
54
     * @return array The fields with attributes, fake attributes and values.
55
     */
56
    public function getUpdateFields($id = false)
57
    {
58
        $fields = $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

58
        /** @scrutinizer ignore-call */ 
59
        $fields = $this->fields();
Loading history...
59
        $entry = ($id != false) ? $this->getEntry($id) : $this->getCurrentEntry();
0 ignored issues
show
Bug introduced by
It seems like getEntry() 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

59
        $entry = ($id != false) ? $this->/** @scrutinizer ignore-call */ getEntry($id) : $this->getCurrentEntry();
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing $id of type false|integer against false; this is ambiguous if the integer can be zero. Consider using a strict comparison !== instead.
Loading history...
Bug introduced by
It seems like getCurrentEntry() 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

59
        $entry = ($id != false) ? $this->getEntry($id) : $this->/** @scrutinizer ignore-call */ getCurrentEntry();
Loading history...
60
61
        foreach ($fields as &$field) {
62
            // set the value
63
            if (! isset($field['value'])) {
64
                if (isset($field['subfields'])) {
65
                    $field['value'] = [];
66
                    foreach ($field['subfields'] as $subfield) {
67
                        $field['value'][] = $entry->{$subfield['name']};
68
                    }
69
                } else {
70
                    $field['value'] = $this->getModelAttributeValue($entry, $field);
71
                }
72
            }
73
        }
74
75
        // always have a hidden input for the entry id
76
        if (! array_key_exists('id', $fields)) {
77
            $fields['id'] = [
78
                'name'  => $entry->getKeyName(),
79
                'value' => $entry->getKey(),
80
                'type'  => 'hidden',
81
            ];
82
        }
83
84
        return $fields;
85
    }
86
87
    /**
88
     * Get the value of the 'name' attribute from the declared relation model in the given field.
89
     *
90
     * @param \Illuminate\Database\Eloquent\Model $model The current CRUD model.
91
     * @param array                               $field The CRUD field array.
92
     *
93
     * @return mixed The value of the 'name' attribute from the relation model.
94
     */
95
    private function getModelAttributeValue($model, $field)
96
    {
97
        if (isset($field['entity']) && $field['entity'] !== false) {
98
            $relational_entity = $this->parseRelationFieldNamesFromHtml([$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

98
            $relational_entity = $this->/** @scrutinizer ignore-call */ parseRelationFieldNamesFromHtml([$field])[0]['name'];
Loading history...
99
100
            $relation_array = explode('.', $relational_entity);
101
102
            $relatedModel = array_reduce(array_splice($relation_array, 0, -1), function ($obj, $method) {
103
                return $obj->{$method} ? $obj->{$method} : $obj;
104
            }, $model);
105
106
            $relationMethod = Arr::last($relation_array);
107
            if (method_exists($relatedModel, $relationMethod)) {
108
                $relation = $relatedModel->{$relationMethod}();
109
                $relation_type = get_class($relation);
110
111
                switch ($relation_type) {
112
                    case HasOne::class:
113
                    case MorphOne::class:
114
                        return $relatedModel->{$relationMethod}->{Arr::last(explode('.', $relational_entity))};
115
116
                    case HasMany::class:
117
                    case MorphMany::class:
118
119
                        $attribute_value = $this->getManyRelationAttributeValue($relatedModel, $relationMethod, $field);
120
                        // we only want to return the json_encoded values here
121
                        if (is_string($attribute_value)) {
122
                            return $attribute_value;
123
                        }
124
125
                    break;
126
                    case BelongsToMany::class:
127
                    case MorphToMany::class:
128
                        $attribute_value = $this->getToManyRelationAttributeValue($relatedModel, $relationMethod, $field);
129
                        // we only want to return the json_encoded values here
130
                        if (is_string($attribute_value)) {
131
                            return $attribute_value;
132
                        }
133
                    break;
134
                }
135
            }
136
137
            return $relatedModel->{$relationMethod};
138
        }
139
140
        if (is_string($field['name'])) {
141
            return $model->{$field['name']};
142
        }
143
144
        if (is_array($field['name'])) {
145
            $result = [];
146
            foreach ($field['name'] as $key => $value) {
147
                $result = $model->{$value};
148
            }
149
150
            return $result;
151
        }
152
    }
153
154
    /**
155
     * Returns the json encoded pivot fields from HasMany/MorphMany relations when available.
156
     *
157
     * @param \Illuminate\Database\Eloquent\Model $model
158
     * @param string $relation_method
159
     * @param array $field
160
     * @return bool|string
161
     */
162
    private function getManyRelationAttributeValue($model, $relation_method, $field)
163
    {
164
        if (! isset($field['pivotFields']) || ! is_array($field['pivotFields'])) {
165
            return false;
166
        }
167
168
        $pivot_fields = Arr::where($field['pivotFields'], function ($item) use ($field) {
169
            return $field['name'] != $item['name'];
170
        });
171
        $related_models = $model->{$relation_method};
172
        $return = [];
173
174
        // for any given model, we grab the attributes that belong to our pivot table.
175
        foreach ($related_models as $related_model) {
176
            $item = [];
177
            //for any given related model, we attach the pivot fields.
178
            foreach ($pivot_fields as $pivot_field) {
179
                $item[$pivot_field['name']] = $related_model->{$pivot_field['name']};
180
            }
181
            $item[$related_model->getKeyName()] = $related_model->getKey();
182
            $return[] = $item;
183
        }
184
        // we return the json encoded result as expected by repeatable field.
185
        return json_encode($return);
186
    }
187
188
    /**
189
     * Returns the json encoded pivot fields from HasMany/MorphMany relations when available.
190
     *
191
     * @param \Illuminate\Database\Eloquent\Model $model
192
     * @param string $relation_method
193
     * @param array $field
194
     * @return bool|string
195
     */
196
    private function getToManyRelationAttributeValue($model, $relation_method, $field)
197
    {
198
        // if pivot is true and there are `pivotFields` we need to get those pivot values to show on the edit page
199
        if (! isset($field['pivot']) || ! isset($field['pivotFields']) || ! is_array($field['pivotFields'])) {
200
            return false;
201
        }
202
203
        // we remove our current relation from the pivotFields.
204
        $pivot_fields = Arr::where($field['pivotFields'], function ($item) use ($field) {
205
            return $field['name'] != $item['name'];
206
        });
207
208
        $related_models = $model->{$relation_method};
209
        $return = [];
210
211
        // for any given model, we grab the attributes that belong to our pivot table.
212
        foreach ($related_models as $related_model) {
213
            $item = [];
214
            $item[$field['name']] = $related_model->getKey();
215
            //for any given related model, we get the pivot fields.
216
            foreach ($pivot_fields as $pivot_field) {
217
                $item[$pivot_field['name']] = $related_model->pivot->{$pivot_field['name']};
218
            }
219
            $return[] = $item;
220
        }
221
222
        // we return the json encoded result as expected by repeatable field.
223
        return json_encode($return);
224
    }
225
}
226