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
Push — v4dot1 ( d0147e...2219a0 )
by
unknown
05:44
created

Relationships::getAvailableRelationsInModel()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 2 Features 0
Metric Value
cc 5
eloc 12
c 3
b 2
f 0
nc 16
nop 0
dl 0
loc 22
rs 9.5555
1
<?php
2
3
namespace Backpack\CRUD\app\Library\CrudPanel\Traits;
4
5
use Exception;
6
use Illuminate\Database\Eloquent\Relations\Relation;
7
use Illuminate\Support\Arr;
8
9
trait Relationships
10
{
11
    /**
12
     * If the field name is not a relationship method e.g: article_id,
13
     * we try to find if this field has a relation defined.
14
     *
15
     * @param string $fieldName
16
     * @return array|bool
17
     */
18
    public function checkIfFieldNameBelongsToAnyRelation($fieldName)
19
    {
20
        $relations = $this->getAvailableRelationsInModel();
21
22
        if (empty($relations)) {
23
            return false;
24
        }
25
26
        if (in_array($fieldName, array_column($relations, 'name'))) {
27
            return array_filter($relations, function ($arr) use ($fieldName) {
28
                if (isset($arr['name'])) {
29
                    return $arr['name'] == $fieldName;
30
                }
31
32
                return false;
33
            })[0];
34
        }
35
36
        return false;
37
    }
38
39
    /**
40
     * Invokes $method_name in $model and returns true in case the return of the method call
41
     * is an instance of Illuminate\Database\Eloquent\Relations\Relation.
42
     *
43
     * @param string $method_name
44
     * @return bool
45
     */
46
    protected function checkIfMethodReturnRelation($method_name) {
47
        try {
48
            $return = $this->model->{$method_name}();
49
50
            if ($return instanceof Relation) {
51
                return true;
52
            }
53
            return false;
54
55
        }catch(\Exception $e) {
56
            return false;
57
        }
58
    }
59
60
    /**
61
     * Get the user defined methods in model that return any type of relation.
62
     * Only returns methods that have their return type explicitly specified. For example:
63
     * public function article() : BelongsTo { return $this->belongsTo(...); }
64
     * public function tags() : HasMany {}.
65
     */
66
    public function getAvailableRelationsInModel()
67
    {
68
        //this is the currently supported, we should be able to add more in future.
69
        $eloquentRelationships = ['HasOne', 'BelongsTo', 'HasMany', 'BelongsToMany'];
70
        $relations = [];
71
        try {
72
            $reflect = new \ReflectionClass($this->model);
73
74
75
            foreach ($reflect->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
76
                if ($method->hasReturnType()) {
77
78
                    $returnType = $method->getReturnType();
79
                    //dd(in_array(class_basename($returnType->getName()), $eloquentRelationships));
80
                    if (in_array(class_basename($returnType->getName()), $eloquentRelationships)) {
81
                        $relations[] = $this->getFieldAttributesFromRelationship($this->model, $method->getName());
82
                    }
83
                }
84
            }
85
            return $relations;
86
        } catch (Exception $e) {
87
            return;
88
        }
89
    }
90
91
    /**
92
     * Gets the relation data from the method in the model.
93
     *
94
     * @param ReflectionMethod $method
0 ignored issues
show
Bug introduced by
The type Backpack\CRUD\app\Librar...Traits\ReflectionMethod was not found. Did you mean ReflectionMethod? If so, make sure to prefix the type with \.
Loading history...
95
     * @return array
96
     */
97
    public function inferFieldAttributesFromRelationship($method)
98
    {
99
        // get the parent of the last relation if using dot notation
100
        // eg: user.account.address -> Return model for account and the relation address in account model.
101
        $relationModel = $this->getRelationModel($method, -1);
0 ignored issues
show
Bug introduced by
It seems like getRelationModel() 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

101
        /** @scrutinizer ignore-call */ 
102
        $relationModel = $this->getRelationModel($method, -1);
Loading history...
102
        $relatedMethod = Arr::last(explode('.', $method));
103
        if ($relationModel != get_class($this->model)) {
104
            $relationModel = new $relationModel();
105
            if (method_exists($relationModel, $relatedMethod)) {
106
                return $this->getFieldAttributesFromRelationship($relationModel, $relatedMethod);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getFieldAt...nModel, $relatedMethod) returns the type false which is incompatible with the documented return type array.
Loading history...
107
            }
108
        }
109
        if (method_exists($this->model, $relatedMethod)) {
110
            return $this->getFieldAttributesFromRelationship($this->model, $relatedMethod);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getFieldAt...>model, $relatedMethod) returns the type false which is incompatible with the documented return type array.
Loading history...
111
        }
112
113
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
114
    }
115
116
    public function getFieldAttributesFromRelationship($model, $method)
117
    {
118
        try {
119
            $method = (new \ReflectionClass($model))->getMethod($method);
120
121
            $relation = $method->invoke($model);
122
123
            if ($relation instanceof Relation) {
124
                $relationship['type'] = 'relationship';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$relationship was never initialized. Although not strictly required by PHP, it is generally a good practice to add $relationship = array(); before regardless.
Loading history...
125
                $relationship['entity'] = $method->getName();
126
                $relationship['relation_type'] = (new \ReflectionClass($relation))->getShortName();
127
128
                $relationship['multiple'] = $this->relationAllowsMultiple($relationship['relation_type']);
129
                $relationship['model'] = get_class($relation->getRelated());
130
131
                if ($relationship['relation_type'] == 'BelongsTo' || $relationship['relation_type'] == 'HasOne') {
132
                    $relationship['name'] = $relation->getForeignKeyName();
133
                }
134
135
                if ($relationship['relation_type'] == 'hasManyThrough' || $relationship['relation_type'] == 'BelongsToMany' || $relationship['relation_type'] == 'morphMany') {
136
                    $relationship['pivot'] = true;
137
                }
138
139
                return $relationship;
140
            }
141
142
            return false;
143
        } catch (Exception $e) {
144
            dd($e);
145
            return false;
146
        }
147
    }
148
149
    /**
150
     * Based on relation type returns if relation allows multiple entities.
151
     *
152
     * @param string $relationType
153
     * @return bool
154
     */
155
    public function relationAllowsMultiple($relationType)
156
    {
157
        switch ($relationType) {
158
            case 'HasMany':
159
            case 'BelongsToMany':
160
            case 'HasManyThrough':
161
            case 'MorphMany':
162
                return true;
163
164
            default:
165
                return false;
166
        }
167
    }
168
}
169