Completed
Push — master ( 6f9845...68f10d )
by Marco
12:19 queued 14s
created

MakeLocatorForInstalledJson::__invoke()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 76

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 76
c 0
b 0
f 0
rs 8.5236
cc 4
nc 4
nop 2

How to fix   Long Method   

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
2
3
declare(strict_types=1);
4
5
namespace Roave\BetterReflection\SourceLocator\Type\Composer\Factory;
6
7
use Roave\BetterReflection\SourceLocator\Ast\Locator;
8
use Roave\BetterReflection\SourceLocator\Type\AggregateSourceLocator;
9
use Roave\BetterReflection\SourceLocator\Type\Composer\Factory\Exception\FailedToParseJson;
10
use Roave\BetterReflection\SourceLocator\Type\Composer\Factory\Exception\InvalidProjectDirectory;
11
use Roave\BetterReflection\SourceLocator\Type\Composer\Factory\Exception\MissingInstalledJson;
12
use Roave\BetterReflection\SourceLocator\Type\Composer\Psr\Psr0Mapping;
13
use Roave\BetterReflection\SourceLocator\Type\Composer\Psr\Psr4Mapping;
14
use Roave\BetterReflection\SourceLocator\Type\Composer\PsrAutoloaderLocator;
15
use Roave\BetterReflection\SourceLocator\Type\DirectoriesSourceLocator;
16
use Roave\BetterReflection\SourceLocator\Type\SingleFileSourceLocator;
17
use Roave\BetterReflection\SourceLocator\Type\SourceLocator;
18
use function array_filter;
19
use function array_map;
20
use function array_merge;
21
use function array_merge_recursive;
22
use function file_exists;
23
use function file_get_contents;
24
use function is_array;
25
use function is_dir;
26
use function json_decode;
27
use function realpath;
28
29
final class MakeLocatorForInstalledJson
30
{
31
    public function __invoke(string $installationPath, Locator $astLocator) : SourceLocator
32
    {
33
        $realInstallationPath = (string) realpath($installationPath);
34
35
        if (! is_dir($realInstallationPath)) {
36
            throw InvalidProjectDirectory::atPath($installationPath);
37
        }
38
39
        $installedJsonPath = $realInstallationPath . '/vendor/composer/installed.json';
40
41
        if (! file_exists($installedJsonPath)) {
42
            throw MissingInstalledJson::inProjectPath($installationPath);
43
        }
44
45
        $installed = json_decode((string) file_get_contents($installedJsonPath), true);
46
47
        if (! is_array($installed)) {
48
            throw FailedToParseJson::inFile($installedJsonPath);
49
        }
50
51
        $classMapPaths       = array_merge(
52
            [],
53
            ...array_map(function (array $package) use ($realInstallationPath) : array {
54
                return $this->prefixPaths(
55
                    $this->packageToClassMapPaths($package),
56
                    $this->packagePrefixPath($realInstallationPath, $package)
57
                );
58
            }, $installed)
59
        );
60
        $classMapFiles       = array_filter($classMapPaths, 'is_file');
61
        $classMapDirectories = array_filter($classMapPaths, 'is_dir');
62
        $filePaths           = array_merge(
63
            [],
64
            ...array_map(function (array $package) use ($realInstallationPath) : array {
65
                return $this->prefixPaths(
66
                    $this->packageToFilePaths($package),
67
                    $this->packagePrefixPath($realInstallationPath, $package)
68
                );
69
            }, $installed)
70
        );
71
72
        return new AggregateSourceLocator(array_merge(
73
            [
74
                new PsrAutoloaderLocator(
75
                    Psr4Mapping::fromArrayMappings(array_merge_recursive(
76
                        [],
77
                        ...array_map(function (array $package) use ($realInstallationPath) : array {
78
                            return $this->prefixWithPackagePath(
79
                                $this->packageToPsr4AutoloadNamespaces($package),
80
                                $realInstallationPath,
81
                                $package
82
                            );
83
                        }, $installed)
84
                    )),
85
                    $astLocator
86
                ),
87
                new PsrAutoloaderLocator(
88
                    Psr0Mapping::fromArrayMappings(array_merge_recursive(
89
                        [],
90
                        ...array_map(function (array $package) use ($realInstallationPath) : array {
91
                            return $this->prefixWithPackagePath(
92
                                $this->packageToPsr0AutoloadNamespaces($package),
93
                                $realInstallationPath,
94
                                $package
95
                            );
96
                        }, $installed)
97
                    )),
98
                    $astLocator
99
                ),
100
                new DirectoriesSourceLocator($classMapDirectories, $astLocator),
101
            ],
102
            ...array_map(static function (string $file) use ($astLocator) : array {
103
                return [new SingleFileSourceLocator($file, $astLocator)];
104
            }, array_merge($classMapFiles, $filePaths))
105
        ));
106
    }
107
108
    /**
109
     * @param mixed[] $package
110
     *
111
     * @return array<string, array<int, string>>
0 ignored issues
show
Documentation introduced by Marco Pivetta
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
112
     */
113
    private function packageToPsr4AutoloadNamespaces(array $package) : array
114
    {
115
        return array_map(static function ($namespacePaths) : array {
116
            return (array) $namespacePaths;
117
        }, $package['autoload']['psr-4'] ?? []);
118
    }
119
120
    /**
121
     * @param mixed[] $package
122
     *
123
     * @return array<string, array<int, string>>
0 ignored issues
show
Documentation introduced by Marco Pivetta
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
124
     */
125
    private function packageToPsr0AutoloadNamespaces(array $package) : array
126
    {
127
        return array_map(static function ($namespacePaths) : array {
128
            return (array) $namespacePaths;
129
        }, $package['autoload']['psr-0'] ?? []);
130
    }
131
132
    /**
133
     * @param mixed[] $package
134
     *
135
     * @return array<int, string>
0 ignored issues
show
Documentation introduced by Marco Pivetta
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
136
     */
137
    private function packageToClassMapPaths(array $package) : array
138
    {
139
        return $package['autoload']['classmap'] ?? [];
140
    }
141
142
    /**
143
     * @param mixed[] $package
144
     *
145
     * @return array<int, string>
0 ignored issues
show
Documentation introduced by Marco Pivetta
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
146
     */
147
    private function packageToFilePaths(array $package) : array
148
    {
149
        return $package['autoload']['files'] ?? [];
150
    }
151
152
    /**
153
     * @param mixed[] $package
154
     *
155
     * @psalm-param array{name: string} $package
156
     */
157
    private function packagePrefixPath(string $trimmedInstallationPath, array $package) : string
158
    {
159
        return $trimmedInstallationPath . '/vendor/' . $package['name'] . '/';
160
    }
161
162
    /**
163
     * @param array<int|string, array<string>> $paths
164
     * @param array<string, array<string>>     $package
165
     *
166
     * @return array<int|string, string|array<string>>
0 ignored issues
show
Documentation introduced by Marco Pivetta
The doc-type array<int|string, could not be parsed: Expected ">" at position 7, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
167
     *
168
     * @psalm-param array{name: string} $package
169
     */
170 View Code Duplication
    private function prefixWithPackagePath(array $paths, string $trimmedInstallationPath, array $package) : array
0 ignored issues
show
Duplication introduced by Marco Pivetta
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
171
    {
172
        $prefix = $this->packagePrefixPath($trimmedInstallationPath, $package);
173
174
        return array_map(function (array $paths) use ($prefix) : array {
175
            return $this->prefixPaths($paths, $prefix);
176
        }, $paths);
177
    }
178
179
    /**
180
     * @param array<int|string, string> $paths
181
     *
182
     * @return array<int|string, string>
0 ignored issues
show
Documentation introduced by Marco Pivetta
The doc-type array<int|string, could not be parsed: Expected ">" at position 7, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
183
     */
184
    private function prefixPaths(array $paths, string $prefix) : array
185
    {
186
        return array_map(static function (string $path) use ($prefix) {
187
            return $prefix . $path;
188
        }, $paths);
189
    }
190
}
191