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 Cristian
12:28
created

Relationships::getFieldsWithRelationType()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 1
nop 1
dl 0
loc 13
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\Model;
6
use Illuminate\Support\Arr;
7
use Illuminate\Support\Str;
8
9
trait Relationships
10
{
11
    /**
12
     * From the field entity we get the relation instance.
13
     *
14
     * @param array $entity
15
     * @return object
16
     */
17
    public function getRelationInstance($field)
18
    {
19
        $entity = $this->getOnlyRelationEntity($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

19
        /** @scrutinizer ignore-call */ 
20
        $entity = $this->getOnlyRelationEntity($field);
Loading history...
20
        $entity_array = explode('.', $entity);
21
        $relation_model = $this->getRelationModel($entity);
0 ignored issues
show
Bug introduced by
The method getRelationModel() does not exist on Backpack\CRUD\app\Librar...el\Traits\Relationships. Did you maybe mean getRelationInstance()? ( Ignorable by Annotation )

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

21
        /** @scrutinizer ignore-call */ 
22
        $relation_model = $this->getRelationModel($entity);

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...
22
23
        $related_method = Arr::last($entity_array);
24
        if (count(explode('.', $entity)) == count(explode('.', $field['entity']))) {
25
            $relation_model = $this->getRelationModel($entity, -1);
26
        }
27
        $relation_model = new $relation_model();
28
29
        //if counts are diferent means that last element of entity is the field in relation.
30
        if (count(explode('.', $entity)) != count(explode('.', $field['entity']))) {
31
            if (in_array($related_method, $relation_model->getFillable())) {
32
                if (count($entity_array) > 1) {
33
                    $related_method = $entity_array[(count($entity_array) - 2)];
34
                    $relation_model = $this->getRelationModel($entity, -2);
35
                } else {
36
                    $relation_model = $this->model;
37
                }
38
            }
39
        }
40
        if (count($entity_array) == 1) {
41
            if (method_exists($this->model, $related_method)) {
42
                return $this->model->{$related_method}();
43
            }
44
        }
45
46
        return $relation_model->{$related_method}();
47
    }
48
49
    /**
50
     * Get the fields for relationships, according to the relation type. It looks only for direct
51
     * relations - it will NOT look through relationships of relationships.
52
     *
53
     * @param string|array $relation_types Eloquent relation class or array of Eloquent relation classes. Eg: BelongsTo
54
     *
55
     * @return array The fields with corresponding relation types.
56
     */
57
    public function getFieldsWithRelationType($relation_types): array
58
    {
59
        $relation_types = (array) $relation_types;
60
61
        return collect($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

61
        return collect($this->/** @scrutinizer ignore-call */ fields())
Loading history...
62
            ->where('model')
63
            ->whereIn('relation_type', $relation_types)
64
            ->filter(function ($item) {
65
                $related_model = get_class($this->model->{Arr::first(explode('.', $item['entity']))}()->getRelated());
66
67
                return Str::contains($item['entity'], '.') && $item['model'] !== $related_model ? false : true;
68
            })
69
            ->toArray();
70
    }
71
72
    /**
73
     * Grabs an relation instance and returns the class name of the related model.
74
     *
75
     * @param array $field
76
     * @return string
77
     */
78
    public function inferFieldModelFromRelationship($field)
79
    {
80
        $relation = $this->getRelationInstance($field);
81
82
        return get_class($relation->getRelated());
83
    }
84
85
    /**
86
     * Return the relation type from a given field: BelongsTo, HasOne ... etc.
87
     *
88
     * @param array $field
89
     * @return string
90
     */
91
    public function inferRelationTypeFromRelationship($field)
92
    {
93
        $relation = $this->getRelationInstance($field);
94
95
        return Arr::last(explode('\\', get_class($relation)));
96
    }
97
98
    /**
99
     * Parse the field name back to the related entity after the form is submited.
100
     * Its called in getAllFieldNames().
101
     *
102
     * @param array $fields
103
     * @return array
104
     */
105
    public function parseRelationFieldNamesFromHtml($fields)
106
    {
107
        foreach ($fields as &$field) {
108
            //we only want to parse fields that has a relation type and their name contains [ ] used in html.
109
            if (isset($field['relation_type']) && preg_match('/[\[\]]/', $field['name']) !== 0) {
110
                $chunks = explode('[', $field['name']);
111
112
                foreach ($chunks as &$chunk) {
113
                    if (strpos($chunk, ']')) {
114
                        $chunk = str_replace(']', '', $chunk);
115
                    }
116
                }
117
                $field['name'] = implode('.', $chunks);
118
            }
119
        }
120
121
        return $fields;
122
    }
123
124
    /**
125
     * Based on relation type returns the default field type.
126
     *
127
     * @param string $relation_type
128
     * @return bool
129
     */
130
    public function inferFieldTypeFromFieldRelation($field)
131
    {
132
        switch ($field['relation_type']) {
133
            case 'BelongsToMany':
134
            case 'HasMany':
135
            case 'HasManyThrough':
136
            case 'MorphMany':
137
            case 'MorphToMany':
138
            case 'BelongsTo':
139
                return 'relationship';
0 ignored issues
show
Bug Best Practice introduced by
The expression return 'relationship' returns the type string which is incompatible with the documented return type boolean.
Loading history...
140
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
141
            default:
142
                return 'text';
0 ignored issues
show
Bug Best Practice introduced by
The expression return 'text' returns the type string which is incompatible with the documented return type boolean.
Loading history...
143
            break;
144
        }
145
    }
146
147
    /**
148
     * Based on relation type returns if relation allows multiple entities.
149
     *
150
     * @param string $relation_type
151
     * @return bool
152
     */
153
    public function guessIfFieldHasMultipleFromRelationType($relation_type)
154
    {
155
        switch ($relation_type) {
156
            case 'BelongsToMany':
157
            case 'HasMany':
158
            case 'HasManyThrough':
159
            case 'HasOneOrMany':
160
            case 'MorphMany':
161
            case 'MorphOneOrMany':
162
            case 'MorphToMany':
163
                return true;
164
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
165
            default:
166
                return false;
167
            break;
168
        }
169
    }
170
171
    /**
172
     * Based on relation type returns if relation has a pivot table.
173
     *
174
     * @param string $relation_type
175
     * @return bool
176
     */
177
    public function guessIfFieldHasPivotFromRelationType($relation_type)
178
    {
179
        switch ($relation_type) {
180
            case 'BelongsToMany':
181
            case 'MorphToMany':
182
                return true;
183
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
184
            default:
185
                return false;
186
            break;
187
        }
188
    }
189
190
    /**
191
     * Check if field name contains a dot, if so, meaning it's a nested relation.
192
     *
193
     * @param array $field
194
     * @return bool
195
     */
196
    protected function isNestedRelation($field): bool
197
    {
198
        if (strpos($field['entity'], '.') !== false) {
199
            return true;
200
        }
201
202
        return false;
203
    }
204
205
    /**
206
     * Associate and dissociate BelongsTo relations in the model.
207
     *
208
     * @param  Model
209
     * @param  array The form data.
0 ignored issues
show
Bug introduced by
The type Backpack\CRUD\app\Library\CrudPanel\Traits\The was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
210
     * @return Model Model with relationships set up.
211
     */
212
    public function associateOrDissociateBelongsToRelations($item, array $data)
213
    {
214
        $belongsToFields = $this->getFieldsWithRelationType('BelongsTo');
215
216
        foreach ($belongsToFields as $relationField) {
217
            if (method_exists($item, $this->getOnlyRelationEntity($relationField))) {
218
                $relatedId = Arr::get($data, $relationField['name']);
219
                $related = $relationField['model']::find($relatedId);
220
221
                $item->{$this->getOnlyRelationEntity($relationField)}()->associate($related);
222
            }
223
        }
224
225
        return $item;
226
    }
227
}
228