Completed
Pull Request — master (#221)
by Christopher
11:18 queued 15s
created

MetadataRelationsTrait   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 129
Duplicated Lines 0 %

Importance

Changes 10
Bugs 0 Features 0
Metric Value
wmc 16
eloc 49
c 10
b 0
f 0
dl 0
loc 129
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A isUnknownPolymorphSide() 0 6 1
B getRelationshipsFromMethods() 0 33 8
A getCodeForMethod() 0 25 4
A getRelationships() 0 3 1
A isKnownPolymorphSide() 0 6 1
A getModelClassMethods() 0 8 1
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: alex
5
 * Date: 13/02/20
6
 * Time: 1:08 PM.
7
 */
8
namespace AlgoWeb\PODataLaravel\Models;
9
10
use Illuminate\Database\Eloquent\Model;
11
use Illuminate\Database\Eloquent\Relations\BelongsTo;
12
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
13
use Illuminate\Database\Eloquent\Relations\MorphMany;
14
use Illuminate\Database\Eloquent\Relations\MorphOne;
15
use Illuminate\Database\Eloquent\Relations\MorphToMany;
16
use Illuminate\Database\Eloquent\Relations\Relation;
17
use Mockery\Mock;
18
use POData\Common\InvalidOperationException;
19
20
trait MetadataRelationsTrait
21
{
22
23
    /**
24
     * Get model's relationships.
25
     *
26
     * @throws InvalidOperationException
27
     * @throws \ReflectionException
28
     * @return array
29
     */
30
    public function getRelationships()
31
    {
32
        return  $this->getRelationshipsFromMethods();
33
    }
34
35
    private $hasUnknownPolymorphic = false;
36
    private $hasKnownPolymorphic = false;
37
    /**
38
     * Is this model the known side of at least one polymorphic relation?
39
     *
40
     * @throws InvalidOperationException
41
     * @throws \ReflectionException
42
     */
43
    public function isKnownPolymorphSide()
44
    {
45
        // isKnownPolymorph needs to be checking KnownPolymorphSide results - if you're checking UnknownPolymorphSide,
46
        // you're turned around
47
        $rels = $this->getRelationshipsFromMethods();
0 ignored issues
show
Unused Code introduced by
The assignment to $rels is dead and can be removed.
Loading history...
48
        return $this->hasKnownPolymorphic;
49
    }
50
51
    /**
52
     * Is this model on the unknown side of at least one polymorphic relation?
53
     *
54
     * @throws InvalidOperationException
55
     * @throws \ReflectionException
56
     */
57
    public function isUnknownPolymorphSide()
58
    {
59
        // isUnknownPolymorph needs to be checking UnknownPolymorphSide results - if you're checking KnownPolymorphSide,
60
        // you're turned around
61
        $rels = $this->getRelationshipsFromMethods();
0 ignored issues
show
Unused Code introduced by
The assignment to $rels is dead and can be removed.
Loading history...
62
        return $this->hasUnknownPolymorphic;
63
    }
64
    /**
65
     * @param  \ReflectionMethod         $method
66
     * @throws InvalidOperationException
67
     * @return string
68
     */
69
    protected function getCodeForMethod(\ReflectionMethod $method) : string
70
    {
71
        $fileName = $method->getFileName();
72
73
        $file = new \SplFileObject($fileName);
74
        $file->seek($method->getStartLine() - 1);
75
        $code = '';
76
        while ($file->key() < $method->getEndLine()) {
77
            $code .= $file->current();
78
            $file->next();
79
        }
80
81
        $code = trim(preg_replace('/\s\s+/', '', $code));
82
        if (false === stripos($code, 'function')) {
83
            $msg = 'Function definition must have keyword \'function\'';
84
            throw new InvalidOperationException($msg);
85
        }
86
        $begin = strpos($code, 'function(');
87
        $code = substr($code, $begin, strrpos($code, '}') - $begin + 1);
88
        $lastCode = $code[strlen($code) - 1];
89
        if ('}' != $lastCode) {
90
            $msg = 'Final character of function definition must be closing brace';
91
            throw new InvalidOperationException($msg);
92
        }
93
        return $code;
94
    }
95
    /**
96
     * @param  Model $model
97
     * @return array
98
     */
99
    protected function getModelClassMethods(Model $model)
100
    {
101
        // TODO: Handle case when Mock::class not present
102
        return array_diff(
103
            get_class_methods($model),
104
            get_class_methods(\Illuminate\Database\Eloquent\Model::class),
105
            get_class_methods(Mock::class),
106
            get_class_methods(MetadataTrait::class)
107
        );
108
    }
109
    /**
110
     * @param bool $biDir
111
     *
112
     * @throws InvalidOperationException
113
     * @throws \ReflectionException
114
     * @return array
115
     */
116
    protected function getRelationshipsFromMethods()
117
    {
118
        /*$biDirVal = true;
119
        $isCached = isset(static::$relationCategories[$biDirVal]) && !empty(static::$relationCategories[$biDirVal]);
120
        if ($isCached) {
121
            return static::$relationCategories[$biDirVal];
122
        }*/
123
        $relationships = [];
124
        /** @var Model $model */
125
        $model = $this;
126
        $methods = $this->getModelClassMethods($model);
127
        foreach ($methods as $method) {
128
            //Use reflection to inspect the code, based on Illuminate/Support/SerializableClosure.php
129
            $reflection = new \ReflectionMethod($model, $method);
130
            $code = $this->getCodeForMethod($reflection);
131
            foreach (static::$relTypes as $relation) {
132
                //Resolve the relation's model to a Relation object.
133
                if (
134
                    !stripos($code, sprintf('$this->%s(', $relation)) ||
135
                    !(($relationObj = $model->$method()) instanceof Relation) ||
136
                    !in_array(MetadataTrait::class, class_uses($relationObj->getRelated()))
137
                ) {
138
                    continue;
139
                }
140
                if (in_array($relation, ['morphedByMany','morphTo'])) {
141
                    $this->hasUnknownPolymorphic = true;
142
                } elseif (in_array($relation, ['morphOne','morphMany','morphToMany'])) {
143
                    $this->hasKnownPolymorphic = true;
144
                }
145
                $relationships[]= $method;
146
            }
147
        }
148
        return $relationships;
149
    }
150
}
151