GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( dd4d58...aecc92 )
by Constantin
02:23
created

TopologySorter::sortClasses()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 30
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 4.0312

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 14
cts 16
cp 0.875
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 15
nc 4
nop 1
crap 4.0312
1
<?php
2
/******************************************************************************
3
 * Copyright (c) 2016 Constantin Galbenu <[email protected]>             *
4
 ******************************************************************************/
5
6
namespace Gica\CodeAnalysis\Shared\ClassSorter;
7
8
9
use Gica\CodeAnalysis\Shared\ClassComparison\SubclassComparator;
10
use Gica\CodeAnalysis\Shared\ClassSorter;
11
12
class TopologySorter implements ClassSorter
13
{
14
    private $cache = [];
15
16
    /**
17
     * @param \ReflectionClass[] $classes
18
     * @return \ReflectionClass[]
19
     * @throws \Exception
20
     */
21 4
    public function sortClasses($classes)
22
    {
23 4
        if (count($classes) <= 1) {
24 2
            return $classes;
25
        }
26
27 2
        $input = $this->createTSortInputString($classes);
28
29 2
        $file = tempnam(sys_get_temp_dir(), 'tsort');
30
31 2
        if (false === file_put_contents($file, $input)) {
32
            throw new \Exception("file_put_contents $file error");
33
        }
34
35 2
        exec("tsort $file", $sortedClassNames, $returnVar);
36
37 2
        unlink($file);
38
39 2
        if ($returnVar != 0) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $returnVar of type integer|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
40
            throw new \Exception("tsort returned $returnVar for $input");
41
        }
42
43 2
        $sortedClassNames = array_reverse($sortedClassNames);
44
45 2
        usort($classes, function (\ReflectionClass $a, \ReflectionClass $b) use ($sortedClassNames) {
46 2
            return array_search($a->name, $sortedClassNames) <=> array_search($b->name, $sortedClassNames);
47 2
        });
48
49 2
        return $classes;
50
    }
51
52
    public function doesClassDependsOnClass(\ReflectionClass $consumerClass, \ReflectionClass $consumedClass): bool
53
    {
54
        $dependencies = $this->getClassDependencies($consumerClass);
55
56
        return $this->isParentClassOfAny($consumedClass, $dependencies);
57
    }
58
59
    /**
60
     * @param \ReflectionClass $reflectionClass
61
     * @param int $level
62
     * @return \ReflectionClass[]
63
     */
64 2
    private function getClassDependencies(\ReflectionClass $reflectionClass, int $level = 0)
65
    {
66 2
        if (!isset($this->cache[$reflectionClass->name])) {
67 2
            $this->cache[$reflectionClass->name] = $this->_getClassDependencies($reflectionClass, $level);
68
        }
69
70 2
        return $this->cache[$reflectionClass->name];
71
    }
72
73
    /**
74
     * @param \ReflectionClass $reflectionClass
75
     * @param int $level
76
     * @return \ReflectionClass[]
77
     */
78 2
    private function _getClassDependencies(\ReflectionClass $reflectionClass, int $level = 0)
79
    {
80 2
        $dependencies = [];
81
82 2
        if ($level > 5) {
83
            return $dependencies;
84
        }
85
86 2
        $constructor = $reflectionClass->getConstructor();
87 2
        if ($constructor && $constructor->getParameters()) {
88 2
            $dependencies = array_merge($dependencies, $this->classFromParameters($constructor->getParameters()));
89
        }
90
91 2
        if ($reflectionClass->getParentClass()) {
92
            $dependencies = array_merge($dependencies, $this->getClassDependencies($reflectionClass->getParentClass()));
93
        }
94
95 2
        foreach ($dependencies as $dependency) {
96 2
            $dependencies = array_merge($dependencies, $this->getClassDependencies($dependency, $level + 1));
97
        }
98
99 2
        return $dependencies;
100
    }
101
102
    private function isParentClassOfAny(\ReflectionClass $parentClass, $classes): bool
103
    {
104
        $comparator = new SubclassComparator();
105
106
        $isASubClassOrSameClass = function (\ReflectionClass $class) use ($parentClass, $comparator) {
107
            return $comparator->isASubClassOrSameClass($class, $parentClass->name);
108
        };
109
110
        $filtered = array_filter($classes, $isASubClassOrSameClass);
111
112
        return count($filtered) > 0;
113
114
    }
115
116
    /**
117
     * @param \ReflectionParameter $parameter
118
     * @return \ReflectionClass
119
     */
120 2
    private function classFromParameter(\ReflectionParameter $parameter)
121
    {
122 2
        return $parameter->getClass();
123
    }
124
125
    /**
126
     * @param \ReflectionParameter[] $parameters
127
     * @return \ReflectionClass[]
128
     */
129
    private function classFromParameters(array $parameters)
130
    {
131 2
        $strings = array_map(function (\ReflectionParameter $parameter) {
132 2
            return $this->classFromParameter($parameter);
133 2
        }, $parameters);
134
135 2
        return array_filter($strings, function ($s) {
136 2
            return !!$s;
137 2
        });
138
    }
139
140
    /**
141
     * @param \ReflectionClass[] $classes
142
     * @return string
143
     */
144 2
    private function createTSortInputString($classes): string
145
    {
146 2
        $inputLines = [];
147 2
        foreach ($classes as $class) {
148 2
            $deps = $this->getClassDependencies($class);
149 2
            foreach ($deps as $dep) {
150 2
                $inputLines[] = $class->name . ' ' . $dep->name;
151
152
            }
153
        }
154
155 2
        $input = implode("\n", $inputLines);
156 2
        return $input;
157
    }
158
}