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 ( 79a1c3...b48fec )
by joseph
13s
created

Psr4Validator.php$0 ➔ yieldPhpFilesToCheck()   F

Complexity

Conditions 11

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 11

Importance

Changes 0
Metric Value
cc 11
dl 0
loc 34
ccs 26
cts 26
cp 1
crap 11
rs 3.1764
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\PHPQA;
4
5
class Psr4Validator
6
{
7
8
    /**
9
     * @var string
10
     */
11
    protected $pathToProjectRoot;
12
    /**
13
     * @var array
14
     */
15
    protected $decodedComposerJson;
16
    private $parseErrors  = [];
17
    private $psr4Errors   = [];
18
    private $ignoreRegexPatterns;
19
    private $ignoredFiles = [];
20
    private $missingPaths = [];
21
22
    /**
23
     * Psr4Validator constructor.
24
     *
25
     * @param array  $ignoreRegexPatterns Set of regex patterns used to exclude files or directories
26
     * @param string $pathToProjectRoot
27
     * @param array  $decodedComposerJson
28
     */
29 3
    public function __construct(array $ignoreRegexPatterns, string $pathToProjectRoot, array $decodedComposerJson)
30
    {
31 3
        $this->ignoreRegexPatterns = $ignoreRegexPatterns;
32 3
        $this->pathToProjectRoot   = $pathToProjectRoot;
33 3
        $this->decodedComposerJson = $decodedComposerJson;
34 3
    }
35
36
    /**
37
     * @throws \Exception
38
     */
39 3
    public function main(): array
40
    {
41 3
        $this->loop();
42 3
        $errors = [];
43
        //Actual Errors
44 3
        if (!empty($this->psr4Errors)) {
45 1
            $errors['PSR-4 Errors:'] = $this->psr4Errors;
46
        }
47 3
        if (!empty($this->parseErrors)) {
48 1
            $errors['Parse Errors:'] = $this->parseErrors;
49
        }
50 3
        if (!empty($this->missingPaths)) {
51 1
            $errors['Missing Paths:'] = $this->missingPaths;
52
        }
53 3
        if ([] === $errors) {
54 2
            return $errors;
55
        }
56
        //Debug Info
57 1
        if (!empty($this->ignoredFiles)) {
58 1
            $errors['Ignored Files:'] = $this->ignoredFiles;
59
        }
60
61 1
        return $errors;
62
    }
63
64
    /**
65
     * @throws \Exception
66
     */
67 3
    private function loop()
68
    {
69 3
        foreach ($this->yieldPhpFilesToCheck() as list($absPathRoot, $namespaceRoot, $fileInfo)) {
70 3
            $this->check($absPathRoot, $namespaceRoot, $fileInfo);
71
        }
72 3
    }
73
74 3
    private function check(string $absPathRoot, string $namespaceRoot, \SplFileInfo $fileInfo)
75
    {
76 3
        $actualNamespace = $this->getActualNamespace($fileInfo);
77 3
        if ('' === $actualNamespace) {
78 1
            return;
79
        }
80 3
        $expectedNamespace = $this->expectedFileNamespace($absPathRoot, $namespaceRoot, $fileInfo);
81 3
        if ($actualNamespace !== $expectedNamespace) {
82 1
            $this->psr4Errors[$namespaceRoot][] =
83
                [
84 1
                    'fileInfo'          => $fileInfo->getRealPath(),
85 1
                    'expectedNamespace' => $expectedNamespace,
86 1
                    'actualNamespace'   => $actualNamespace,
87
                ];
88
        }
89 3
    }
90
91 3
    private function expectedFileNamespace(string $absPathRoot, string $namespaceRoot, \SplFileInfo $fileInfo): string
92
    {
93 3
        $relativePath = \substr($fileInfo->getPathname(), \strlen($absPathRoot));
94 3
        $relativeDir  = \dirname($relativePath);
95 3
        $relativeNs   = '';
96 3
        if ($relativeDir !== '.') {
97 3
            $relativeNs = \str_replace(
98 3
                '/',
99 3
                '\\',
100 3
                \ltrim($relativeDir, '/')
101
            );
102
        }
103
104 3
        return rtrim($namespaceRoot.$relativeNs, '\\');
105
    }
106
107 3
    private function getActualNamespace(\SplFileInfo $fileInfo): string
108
    {
109 3
        $contents = \file_get_contents($fileInfo->getPathname());
110 3
        \preg_match('%namespace\s+?([^;]+)%', $contents, $matches);
111 3
        if (empty($matches) || !isset($matches[1])) {
112 1
            $this->parseErrors[] = $fileInfo->getRealPath();
113
114 1
            return '';
115
        }
116
117 3
        return $matches[1];
118
    }
119
120
    /**
121
     * @param string $realPath
122
     *
123
     * @return \SplHeap|\SplFileInfo[]
124
     */
125 3
    private function getDirectoryIterator(string $realPath)
126
    {
127 3
        $directoryIterator = new \RecursiveDirectoryIterator(
128 3
            $realPath,
129 3
            \RecursiveDirectoryIterator::SKIP_DOTS
130
        );
131 3
        $iterator          = new \RecursiveIteratorIterator(
132 3
            $directoryIterator,
133 3
            \RecursiveIteratorIterator::SELF_FIRST
134
        );
135
136
        return new class($iterator) extends \SplHeap
137
        {
138 3
            public function __construct(\RecursiveIteratorIterator $iterator)
139
            {
140 3
                foreach ($iterator as $item) {
141 3
                    $this->insert($item);
142
                }
143 3
            }
144
145 3
            public function compare($item1, $item2)
146
            {
147 3
                return strcmp($item2->getRealpath(), $item1->getRealpath());
148
            }
149
        };
150
    }
151
152 1
    private function addMissingPathError(string $path, string $namespaceRoot, string $absPathRoot)
153
    {
154 1
        $invalidPathMessage = "Namespace root '$namespaceRoot'".
155 1
                              "\ncontains a path '$path''".
156 1
                              "\nwhich doesn't exist\n";
157 1
        if (stripos($absPathRoot, "Magento") !== false) {
158
            $invalidPathMessage .= 'Magento\'s composer includes this by default, '
159 1
                                   .'it should be removed from the psr-4 section';
160
        }
161 1
        $this->missingPaths[$path] = $invalidPathMessage;
162 1
    }
163
164
    /**
165
     * @return \Generator
166
     * @throws \Exception
167
     * @SuppressWarnings(PHPMD.StaticAccess)
168
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
169
     */
170 3
    private function yieldPhpFilesToCheck(): \Generator
171
    {
172 3
        $json = $this->decodedComposerJson;
173 3
        foreach (['autoload', 'autoload-dev'] as $autoload) {
174 3
            if (!isset($json[$autoload]['psr-4'])) {
175 1
                continue;
176
            }
177 3
            $psr4 = $json[$autoload]['psr-4'];
178 3
            foreach ($psr4 as $namespaceRoot => $paths) {
179 3
                if (!\is_array($paths)) {
180 1
                    $paths = [$paths];
181
                }
182 3
                foreach ($paths as $path) {
183 3
                    $absPathRoot     = $this->pathToProjectRoot.'/'.$path;
184 3
                    $realAbsPathRoot = \realpath($absPathRoot);
185 3
                    if (false === $realAbsPathRoot) {
186 1
                        $this->addMissingPathError($path, $namespaceRoot, $absPathRoot);
187 1
                        continue;
188
                    }
189 3
                    $iterator = $this->getDirectoryIterator($absPathRoot);
190 3
                    foreach ($iterator as $fileInfo) {
191 3
                        if ('php' !== $fileInfo->getExtension()) {
192 3
                            continue;
193
                        }
194 3
                        foreach ($this->ignoreRegexPatterns as $pattern) {
195 1
                            if (\preg_match($pattern, $fileInfo->getRealPath())) {
196 1
                                $this->ignoredFiles[] = $fileInfo->getRealPath();
197 1
                                continue 2;
198
                            }
199
                        }
200
                        yield [
201 3
                            $absPathRoot,
202 3
                            $namespaceRoot,
203 3
                            $fileInfo,
204
                        ];
205
                    }
206
                }
207
            }
208
        }
209 3
    }
210
}
211