Completed
Push — master ( cd6eff...f14ab5 )
by Théo
04:19 queued 02:02
created

HandleAddPrefix::__invoke()   B

Complexity

Conditions 3
Paths 7

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3.0067

Importance

Changes 0
Metric Value
cc 3
eloc 20
nc 7
nop 8
dl 0
loc 30
ccs 10
cts 11
cp 0.9091
crap 3.0067
rs 8.8571
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the humbug/php-scoper package.
7
 *
8
 * Copyright (c) 2017 Théo FIDRY <[email protected]>,
9
 *                    Pádraic Brady <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Humbug\PhpScoper\Handler;
16
17
use Closure;
18
use Humbug\PhpScoper\Autoload\ScoperAutoloadGenerator;
19
use Humbug\PhpScoper\Logger\ConsoleLogger;
20
use Humbug\PhpScoper\Scoper;
21
use Humbug\PhpScoper\Throwable\Exception\ParsingException;
22
use Humbug\PhpScoper\Throwable\Exception\RuntimeException;
23
use SplFileInfo;
24
use Symfony\Component\Filesystem\Filesystem;
25
use Symfony\Component\Finder\Finder;
26
use Throwable;
27
use function Humbug\PhpScoper\get_common_path;
28
29
/**
30
 * @final
31
 */
32
class HandleAddPrefix
33
{
34
    private $fileSystem;
35
    private $scoper;
36
37 10
    public function __construct(Scoper $scoper)
38
    {
39 10
        $this->fileSystem = new Filesystem();
40 10
        $this->scoper = $scoper;
41
    }
42
43
    /**
44
     * Applies prefix to all the code found in the given paths, AKA scope all the files found.
45
     *
46
     * @param string              $prefix                   e.g. 'Foo'
47
     * @param string[]            $paths                    List of files (absolute paths) which will be scoped
48
     * @param string              $output                   Absolute path to the output directory
49
     * @param callable[]          $patchers
50
     * @param string[]            $whitelist                List of classes that will not be scoped
51
     * @param string[]|callable[] $globalNamespaceWhitelist
52
     * @param bool                $stopOnFailure
53
     * @param ConsoleLogger       $logger
54
     */
55 10
    public function __invoke(
56
        string $prefix,
57
        array $paths,
58
        string $output,
59
        array $patchers,
60
        array $whitelist,
61
        array $globalNamespaceWhitelist,
62
        bool $stopOnFailure,
63
        ConsoleLogger $logger
64
    ) {
65 10
        $this->fileSystem->mkdir($output);
66
67
        try {
68 10
            $files = $this->retrieveFiles($paths, $output);
69
70 9
            $globalWhitelister = $this->createGlobalWhitelister($globalNamespaceWhitelist);
71
72 9
            $vendorDir = $this->scopeFiles($files, $prefix, $patchers, $whitelist, $globalWhitelister, $stopOnFailure, $logger);
73
74 7
            if (null !== $vendorDir) {
75
                $autoload = (new ScoperAutoloadGenerator($whitelist))->dump($prefix);
76
77 7
                $this->fileSystem->dumpFile($vendorDir.'/scoper-autoload.php', $autoload);
78
            }
79 3
        } catch (Throwable $throwable) {
80 3
            $this->fileSystem->remove($output);
81
82 3
            throw $throwable;
83
        }
84
    }
85
86
    /**
87
     * @param string[]|callable[] $globalNamespaceWhitelist
88
     *
89
     * @return Closure
90
     */
91
    private function createGlobalWhitelister(array $globalNamespaceWhitelist): Closure
92
    {
93 9
        return function (string $className) use ($globalNamespaceWhitelist): bool {
94
            foreach ($globalNamespaceWhitelist as $whitelister) {
95
                if (is_string($whitelister)) {
96
                    if ($className === $whitelister) {
97
                        return true;
98
                    } else {
99
                        continue;
100
                    }
101
                }
102
103
                /** @var callable $whitelister */
104
                if (true === $whitelister($className)) {
105
                    return true;
106
                }
107
            }
108
109
            return false;
110 9
        };
111
    }
112
113
    /**
114
     * @param string[] $paths
115
     * @param string   $output
116
     *
117
     * @return string[]
118
     */
119 10
    private function retrieveFiles(array $paths, string $output): array
120
    {
121 10
        $pathsToSearch = [];
122 10
        $filesToAppend = [];
123
124 10
        foreach ($paths as $path) {
125 10
            if (false === file_exists($path)) {
126 1
                throw new RuntimeException(
127 1
                    sprintf(
128 1
                        'Could not find the file "%s".',
129 1
                        $path
130
                    )
131
                );
132
            }
133
134 9
            if (is_dir($path)) {
135 3
                $pathsToSearch[] = $path;
136
            } else {
137 9
                $filesToAppend[] = $path;
138
            }
139
        }
140
141 9
        $finder = new Finder();
142
143 9
        $finder->files()
144 9
            ->in($pathsToSearch)
145 9
            ->append($filesToAppend)
146 9
            ->sortByName()
147
        ;
148
149 9
        $files = array_values(
150 9
            array_map(
151 9
                function (SplFileInfo $fileInfo) {
152 8
                    return $fileInfo->getRealPath();
153 9
                },
154 9
                iterator_to_array($finder)
155
            )
156
        );
157
158 9
        $commonPath = get_common_path($files);
159
160 9
        return array_reduce(
161 9
            $files,
162 9
            function (array $files, string $file) use ($output, $commonPath): array {
163 8
                if (false === file_exists($file)) {
164
                    throw new RuntimeException(
165
                        sprintf(
166
                            'Could not find the file "%s".',
167
                            $file
168
                        )
169
                    );
170
                }
171
172 8
                if (false === is_readable($file)) {
173
                    throw new RuntimeException(
174
                        sprintf(
175
                            'Could not read the file "%s".',
176
                            $file
177
                        )
178
                    );
179
                }
180
181 8
                $files[$file] = $output.str_replace($commonPath, '', $file);
182
183 8
                return $files;
184 9
            },
185 9
            []
186
        );
187
    }
188
189
    /**
190
     * @param string[]      $files
191
     * @param string        $prefix
192
     * @param callable[]    $patchers
193
     * @param string[]      $whitelist
194
     * @param callable      $globalWhitelister
195
     * @param bool          $stopOnFailure
196
     * @param ConsoleLogger $logger
197
     *
198
     * @return string|null
199
     */
200 9
    private function scopeFiles(
201
        array $files,
202
        string $prefix,
203
        array $patchers,
204
        array $whitelist,
205
        callable $globalWhitelister,
206
        bool $stopOnFailure,
207
        ConsoleLogger $logger
208
    ): ?string {
209 9
        $count = count($files);
210 9
        $logger->outputFileCount($count);
211
212 9
        $vendorDirs = [];
213
214 9
        foreach ($files as $inputFilePath => $outputFilePath) {
215 8
            if (preg_match('~((?:.*)\/vendor)\/.*~', $outputFilePath, $matches)) {
216
                $vendorDirs[$matches[1]] = true;
217
            }
218
219 8
            $this->scopeFile($inputFilePath, $outputFilePath, $prefix, $patchers, $whitelist, $globalWhitelister, $stopOnFailure, $logger);
220
        }
221
222 7
        $vendorDirs = array_keys($vendorDirs);
223
224 7
        usort(
225 7
            $vendorDirs,
226 7
            function ($a, $b) {
227
                return strlen($b) <=> strlen($a);
228 7
            }
229
        );
230
231 7
        return (0 === count($vendorDirs)) ? null : $vendorDirs[0];
232
    }
233
234
    /**
235
     * @param string        $inputFilePath
236
     * @param string        $outputFilePath
237
     * @param string        $prefix
238
     * @param callable[]    $patchers
239
     * @param string[]      $whitelist
240
     * @param callable      $globalWhitelister
241
     * @param bool          $stopOnFailure
242
     * @param ConsoleLogger $logger
243
     */
244 8
    private function scopeFile(
245
        string $inputFilePath,
246
        string $outputFilePath,
247
        string $prefix,
248
        array $patchers,
249
        array $whitelist,
250
        callable $globalWhitelister,
251
        bool $stopOnFailure,
252
        ConsoleLogger $logger
253
    ): void {
254
        try {
255 8
            $scoppedContent = $this->scoper->scope($inputFilePath, $prefix, $patchers, $whitelist, $globalWhitelister);
256 3
        } catch (Throwable $error) {
257 3
            $exception = new ParsingException(
258 3
                sprintf(
259 3
                    'Could not parse the file "%s".',
260 3
                    $inputFilePath
261
                ),
262 3
                0,
263 3
                $error
264
            );
265
266 3
            if ($stopOnFailure) {
267 2
                throw $exception;
268
            }
269
270 1
            $logger->outputWarnOfFailure($inputFilePath, $exception);
271
272 1
            $scoppedContent = file_get_contents($inputFilePath);
273
        }
274
275 6
        $this->fileSystem->dumpFile($outputFilePath, $scoppedContent);
276
277 6
        if (false === isset($exception)) {
278 5
            $logger->outputSuccess($inputFilePath);
279
        }
280
    }
281
}
282