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 ( 75bdf9...8faa57 )
by joseph
83:56 queued 81:04
created

getEntitySubFqnFromEntityFilePath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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