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 (#3410)
by
unknown
11:29
created

Relationships::isNestedRelation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 1
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);
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->{Str::before($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 string
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';
140
            default:
141
                return 'text';
142
        }
143
    }
144
145
    /**
146
     * Based on relation type returns if relation allows multiple entities.
147
     *
148
     * @param string $relation_type
149
     * @return bool
150
     */
151
    public function guessIfFieldHasMultipleFromRelationType($relation_type)
152
    {
153
        switch ($relation_type) {
154
            case 'BelongsToMany':
155
            case 'HasMany':
156
            case 'HasManyThrough':
157
            case 'HasOneOrMany':
158
            case 'MorphMany':
159
            case 'MorphOneOrMany':
160
            case 'MorphToMany':
161
                return true;
162
            default:
163
                return false;
164
        }
165
    }
166
167
    /**
168
     * Based on relation type returns if relation has a pivot table.
169
     *
170
     * @param string $relation_type
171
     * @return bool
172
     */
173
    public function guessIfFieldHasPivotFromRelationType($relation_type)
174
    {
175
        switch ($relation_type) {
176
            case 'BelongsToMany':
177
            case 'MorphToMany':
178
                return true;
179
                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...
180
            default:
181
                return false;
182
                break;
183
        }
184
    }
185
186
    /**
187
     * Check if field name contains a dot, if so, meaning it's a nested relation.
188
     *
189
     * @param array $field
190
     * @return bool
191
     */
192
    protected function isNestedRelation($field): bool
193
    {
194
        return Str::contains($field['entity'], '.');
195
    }
196
197
    /**
198
     * Return the relation without any model attributes there.
199
     * Eg. user.entity_id would return user, as entity_id is not a relation in user.
200
     *
201
     * @param array $relation_field
202
     * @return string
203
     */
204
    public function getOnlyRelationEntity($relation_field)
205
    {
206
        $relation_model = $this->getRelationModel($relation_field['entity'], -1);
207
        $related_method = Str::afterLast($relation_field['entity'], '.');
208
209
        if (! method_exists($relation_model, $related_method) && $this->isNestedRelation($relation_field)) {
210
            return Str::beforeLast($relation_field['entity'], '.');
211
        }
212
213
        return $relation_field['entity'];
214
    }
215
}
216