RelationFinder   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 86
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 38
c 2
b 0
f 0
dl 0
loc 86
rs 10
wmc 11

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getModelRelations() 0 28 4
A getParentKey() 0 5 1
B getRelationshipFromMethodAndModel() 0 31 6
1
<?php
2
3
namespace BeyondCode\ErdGenerator;
4
5
use Illuminate\Database\Eloquent\Relations\BelongsTo;
6
use Illuminate\Database\Eloquent\Relations\HasOneOrMany;
7
use Illuminate\Database\Eloquent\Relations\Relation;
8
use Illuminate\Support\Collection;
9
use ReflectionClass;
10
use ReflectionMethod;
11
use Illuminate\Support\Arr;
12
13
14
class RelationFinder
15
{
16
    /**
17
     * Return all relations from a fully qualified model class name.
18
     *
19
     * @param string $model
20
     * @return Collection
21
     * @throws \ReflectionException
22
     */
23
    public function getModelRelations(string $model)
24
    {
25
        $class = new ReflectionClass($model);
26
27
        $traitMethods = Collection::make($class->getTraits())->map(function (ReflectionClass $trait) {
0 ignored issues
show
Bug introduced by
It seems like $class->getTraits() can also be of type ReflectionClass[]; however, parameter $items of Illuminate\Support\Collection::make() does only seem to accept Illuminate\Contracts\Support\Arrayable, maybe add an additional type check? ( Ignorable by Annotation )

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

27
        $traitMethods = Collection::make(/** @scrutinizer ignore-type */ $class->getTraits())->map(function (ReflectionClass $trait) {
Loading history...
28
            return Collection::make($trait->getMethods(ReflectionMethod::IS_PUBLIC));
0 ignored issues
show
Bug introduced by
$trait->getMethods(ReflectionMethod::IS_PUBLIC) of type ReflectionMethod[] is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $items of Illuminate\Support\Collection::make(). ( Ignorable by Annotation )

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

28
            return Collection::make(/** @scrutinizer ignore-type */ $trait->getMethods(ReflectionMethod::IS_PUBLIC));
Loading history...
29
        })->flatten();
30
31
        $methods = Collection::make($class->getMethods(ReflectionMethod::IS_PUBLIC))
0 ignored issues
show
Bug introduced by
$class->getMethods(ReflectionMethod::IS_PUBLIC) of type ReflectionMethod[] is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $items of Illuminate\Support\Collection::make(). ( Ignorable by Annotation )

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

31
        $methods = Collection::make(/** @scrutinizer ignore-type */ $class->getMethods(ReflectionMethod::IS_PUBLIC))
Loading history...
32
            ->merge($traitMethods)
33
            ->reject(function (ReflectionMethod $method) use ($model) {
34
                return $method->class !== $model || $method->getNumberOfParameters() > 0 || $method->isStatic();;
35
            });
36
37
        $relations = Collection::make();
38
39
        $methods->map(function (ReflectionMethod $method) use ($model, &$relations) {
40
            $relations = $relations->merge($this->getRelationshipFromMethodAndModel($method, $model));
41
        });
42
43
        $relations = $relations->filter();
44
45
        if ($ignoreRelations = Arr::get(config('erd-generator.ignore', []),$model))
46
        {
47
            $relations = $relations->diffKeys(array_flip($ignoreRelations));
48
        }
49
50
        return $relations;
51
    }
52
53
    /**
54
     * @param string $qualifiedKeyName
55
     * @return mixed
56
     */
57
    protected function getParentKey(string $qualifiedKeyName)
58
    {
59
        $segments = explode('.', $qualifiedKeyName);
60
61
        return end($segments);
62
    }
63
64
    /**
65
     * @param ReflectionMethod $method
66
     * @param string $model
67
     * @return array|null
68
     */
69
    protected function getRelationshipFromMethodAndModel(ReflectionMethod $method, string $model)
70
    {
71
        try {
72
            $return = $method->invoke(app($model));
73
74
            if ($return instanceof Relation) {
75
                $localKey = null;
76
                $foreignKey = null;
77
78
                if ($return instanceof HasOneOrMany) {
79
                    $localKey = $this->getParentKey($return->getQualifiedParentKeyName());
80
                    $foreignKey = $return->getForeignKeyName();
81
                }
82
83
                if ($return instanceof BelongsTo) {
84
                    $foreignKey = $this->getParentKey($return->getQualifiedOwnerKeyName());
85
                    $localKey = method_exists($return, 'getForeignKeyName') ? $return->getForeignKeyName() : $return->getForeignKey();
86
                }
87
88
                return [
89
                    $method->getName() => new ModelRelation(
90
                        $method->getShortName(),
91
                        (new ReflectionClass($return))->getShortName(),
92
                        (new ReflectionClass($return->getRelated()))->getName(),
93
                        $localKey,
94
                        $foreignKey
95
                    )
96
                ];
97
            }
98
        } catch (\Throwable $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
99
        return null;
100
    }
101
102
}
103