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
Pull Request — master (#106)
by joseph
20:31
created

getPathToRelationRootForEntity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1.008

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 8
ccs 4
cts 5
cp 0.8
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1.008
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\CodeGeneration;
4
5
use EdmondsCommerce\DoctrineStaticMeta\Config;
6
use Symfony\Component\Finder\Finder;
7
use Symfony\Component\Finder\SplFileInfo;
8
9
/**
10
 * Class UnusedCodeRemover
11
 *
12
 * Finds and removes generated code that does not seem to be used
13
 *
14
 * Caution - this is destructive - do not use in a dirty repo!!!
15
 *
16
 * @package EdmondsCommerce\DoctrineStaticMeta\CodeGeneration
17
 */
18
class UnusedRelationsRemover
19
{
20
    /**
21
     * @var NamespaceHelper
22
     */
23
    protected $namespaceHelper;
24
    /**
25
     * @var Config
26
     */
27
    protected $config;
28
    /**
29
     * @var array
30
     */
31
    private $filesRemoved = [];
32
    /**
33
     * @var string
34
     */
35
    private $pathToProjectRoot;
36
    /**
37
     * @var string
38
     */
39
    private $projectRootNamespace;
40
    /**
41
     * @var array
42
     */
43
    private $relationTraits = [];
44
    /**
45 2
     * @var array
46
     */
47 2
    private $entitySubFqnsToName = [];
48 2
    /**
49 2
     * @var array
50 2
     */
51 2
    private $entityPaths = [];
52 2
53
    public function __construct(NamespaceHelper $namespaceHelper, Config $config)
54
    {
55 2
        $this->namespaceHelper = $namespaceHelper;
56
        $this->config          = $config;
57
    }
58 2
59
60 2
    public function run(?string $pathToProjectRoot = null, ?string $projectRootNamespace = null): array
61 2
    {
62
        $this->pathToProjectRoot    = $pathToProjectRoot ?? $this->config::getProjectRootDirectory();
63 2
        $this->projectRootNamespace =
64
            $projectRootNamespace ?? $this->namespaceHelper->getProjectRootNamespaceFromComposerJson();
65
        $this->initArrayOfRelationTraits();
66 2
        $this->initAllEntitySubFqns();
67 2
        foreach (\array_keys($this->entitySubFqnsToName) as $entitySubFqn) {
68 2
            $this->removeUnusedEntityRelations($entitySubFqn);
69 2
        }
70 2
71
        return $this->filesRemoved;
72
    }
73
74 2
    private function initArrayOfRelationTraits(): void
75
    {
76 2
        $this->relationTraits = [];
77
        $pluralRelations      = $this->getFileInfoObjectsInDirs(
78
            [
79 2
                __DIR__ . '/../../codeTemplates/src/Entity/Relations/TemplateEntity/Traits/HasTemplateEntities',
80 2
            ]
81 2
        );
82 2
        foreach ($pluralRelations as $pluralRelation) {
83 2
            $realPath                                  = $pluralRelation->getRealPath();
84
            $this->relationTraits['plural'][$realPath] = $this->convertPathToNamespace(
85
                $this->getSubPathFromSrcAndTrimExtension(
86
                    $realPath
87 2
                )
88
            );
89
        }
90
        $singularRelations = $this->getFileInfoObjectsInDirs(
91
            [
92
                __DIR__ . '/../../codeTemplates/src/Entity/Relations/TemplateEntity/Traits/HasTemplateEntity',
93
            ]
94 2
        );
95
        foreach ($singularRelations as $singularRelation) {
96 2
            $realPath                                    = $singularRelation->getRealPath();
97 2
            $this->relationTraits['singular'][$realPath] = $this->convertPathToNamespace(
98
                $this->getSubPathFromSrcAndTrimExtension(
99 2
                    $realPath
100
                )
101
            );
102 2
        }
103
    }
104 2
105
    /**
106
     * @param array $dirs
107 2
     *
108
     * @return array|SplFileInfo[]
109 2
     */
110 2
    private function getFileInfoObjectsInDirs(array $dirs): array
111
    {
112 2
        $finder   = new Finder();
113
        $iterable = $finder->files()->in($dirs);
114
115 2
        return iterator_to_array($iterable);
116
    }
117 2
118 2
    private function convertPathToNamespace(string $path): string
119 2
    {
120 2
        return \str_replace('/', '\\', $path);
121 2
    }
122 2
123 2
    private function getSubPathFromSrcAndTrimExtension(string $path): string
124
    {
125 2
        $subPath = substr($path, strpos($path, 'src') + 3);
126
        $subPath = substr($subPath, 0, strpos($subPath, '.php'));
127 2
128
        return $subPath;
129 2
    }
130
131 2
    private function initAllEntitySubFqns(): void
132
    {
133
        $files                     = $this->getFileInfoObjectsInDirs([$this->pathToProjectRoot . '/src/Entities']);
134 2
        $this->entitySubFqnsToName = [];
135
        foreach ($files as $file) {
136 2
            $realPath                                 = $file->getRealPath();
137
            $this->entityPaths[$realPath]             = \file_get_contents($realPath);
138
            $entitySubFqn                             = $this->getEntitySubFqnFromEntityFilePath($realPath);
139 2
            $this->entitySubFqnsToName[$entitySubFqn] = $this->getPluralSingularFromEntitySubFqn($entitySubFqn);
140 2
        }
141
    }
142
143
    private function getEntitySubFqnFromEntityFilePath(string $path): string
144 2
    {
145
        $subPath = $this->getSubPathFromSrcAndTrimExtension($path);
146 2
147 2
        return \str_replace('/', '\\', $subPath);
148 2
    }
149
150 2
    private function getPluralSingularFromEntitySubFqn(string $entitySubFqn): array
151 2
    {
152
        $entityFqn = $this->projectRootNamespace . $entitySubFqn;
153 2
154
        return [
155 1
            'singular' => ucfirst($entityFqn::getSingular()),
156 1
            'plural'   => ucfirst($entityFqn::getPlural()),
157 1
        ];
158 1
    }
159 1
160
    private function removeUnusedEntityRelations(string $entitySubFqn): void
161
    {
162
        $entitySubSubFqn = $this->getEntitySubSubFqn($entitySubFqn);
163 1
        $hasPlural       = $this->removeRelationsBySingularOrPlural('plural', $entitySubSubFqn);
164 1
        $hasSingular     = $this->removeRelationsBySingularOrPlural('singular', $entitySubSubFqn);
165 1
166 1
        if (false === $hasPlural && false === $hasSingular) {
167 1
            $this->removeAllRelationFilesForEntity($entitySubSubFqn);
168
169
            return;
170 1
        }
171
        if (false === $hasPlural) {
172 2
            $this->removeHasPluralOrSingularInterfaceAndAbstract(
173
                'plural',
174 2
                $entitySubFqn,
175
                $entitySubSubFqn
176
            );
177 2
        }
178
179 2
        if (false === $hasSingular) {
180
            $this->removeHasPluralOrSingularInterfaceAndAbstract(
181 2
                'singular',
182 2
                $entitySubFqn,
183 2
                $entitySubSubFqn
184 2
            );
185 2
        }
186 1
    }
187 2
188
    private function getEntitySubSubFqn(string $entitySubFqn): string
189
    {
190 2
        return substr($entitySubFqn, \strlen('\\Entities\\'));
191
    }
192
193 2
    private function removeRelationsBySingularOrPlural(string $singularOrPlural, string $entitySubSubFqn): bool
194
    {
195
        $foundUsedRelations = false;
196 2
197
        foreach ($this->relationTraits[$singularOrPlural] as $relationTrait) {
198 2
            $relationType = $this->getRelationType($relationTrait);
199 2
            $pattern      = $this->getRegexForRelationTraitUseStatement($entitySubSubFqn, $relationType);
200 2
            foreach ($this->entityPaths as $entityFileContents) {
201 2
                if (1 === \preg_match($pattern, $entityFileContents)) {
202
                    $foundUsedRelations = true;
203
                    continue 2;
204 2
                }
205
            }
206 2
            $this->removeRelation($entitySubSubFqn, $relationType);
207
        }
208
209 2
        return $foundUsedRelations;
210
    }
211
212
    private function getRelationType(string $relationTraitSubFqn)
213 2
    {
214
        return preg_split(
215 2
            '%\\\\HasTemplateEntit(y|ies)\\\\HasTemplateEntit(y|ies)%',
216 2
            $relationTraitSubFqn
217
        )[1];
218
    }
219 2
220 2
    private function getRegexForRelationTraitUseStatement(string $entitySubSubFqn, string $relationType): string
221 2
    {
222 2
        $entitySubSubFqn = \str_replace('\\', '\\\\', $entitySubSubFqn);
223 2
224
        return <<<REGEXP
225 2
%use .+?\\\\Entity\\\\Relations\\\\$entitySubSubFqn([^;]+?)$relationType%
226
REGEXP;
227 2
    }
228 2
229 2
    private function removeRelation(string $entitySubSubFqn, string $relationType): void
230 2
    {
231 2
        $directory = $this->getPathToRelationRootForEntity($entitySubSubFqn);
232 2
        if (!\is_dir($directory)) {
233
            return;
234
        }
235
        $finder = (new Finder())->files()
236 2
                                ->in($directory)
237
                                ->path('%^(Interfaces|Traits).+?' . $relationType . '%');
238 2
        $this->removeFoundFiles($finder);
239 2
    }
240
241 2
    private function getPathToRelationRootForEntity(string $entitySubSubFqn): string
242
    {
243 2
        return $this->pathToProjectRoot
244
               . '/src/Entity/Relations/'
245 2
               . \str_replace(
246
                   '\\',
247
                   '/',
248 2
                   $entitySubSubFqn
249 2
               );
250 2
    }
251
252 2
    private function removeFoundFiles(Finder $finder): void
253
    {
254 2
        foreach ($finder as $fileInfo) {
255
            $this->removeFile($fileInfo->getRealPath());
256 2
        }
257 2
    }
258
259 2
    private function removeFile(string $path): void
260 2
    {
261
        if (!\file_exists($path)) {
262
            return;
263 2
        }
264 2
        $this->filesRemoved[] = $path;
265 2
        unlink($path);
266
    }
267 2
268
    private function removeAllRelationFilesForEntity(string $entitySubSubFqn): void
269 1
    {
270
        $relationsPath = $this->getPathToRelationRootForEntity($entitySubSubFqn);
271
        $directories   = [
272
            "$relationsPath/Traits",
273
            "$relationsPath/Interfaces",
274 1
        ];
275 1
        foreach ($directories as $directory) {
276
            if (!\is_dir($directory)) {
277
                continue;
278 1
            }
279 1
            $finder = (new Finder())->files()
280 1
                                    ->in($directory);
281 1
            $this->removeFoundFiles($finder);
282 1
        }
283
    }
284 1
285 1
    private function removeHasPluralOrSingularInterfaceAndAbstract(
286
        string $pluralOrSingular,
287
        string $entitySubFqn,
288
        string $entitySubSubFqn
289
    ): void {
290
        $directory = $this->getPathToRelationRootForEntity($entitySubSubFqn);
291
        if (!\is_dir($directory)) {
292
            return;
293
        }
294
        $hasName = $this->entitySubFqnsToName[$entitySubFqn][$pluralOrSingular];
295
        $finder  = (new Finder())->files()
296
                                 ->in($directory)
297
                                 ->path(
298
                                     '%^(Interfaces|Traits).+?Has' . $hasName . '(/|Abstract\.php|Interface\.php)%'
299
                                 );
300
        $this->removeFoundFiles($finder);
301
    }
302
}
303