Passed
Branch master (72182d)
by Pádraic
02:17
created

HandleAddPrefix   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 219
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 80.48%

Importance

Changes 0
Metric Value
dl 0
loc 219
ccs 66
cts 82
cp 0.8048
rs 10
c 0
b 0
f 0
wmc 20
lcom 1
cbo 6

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
B createGlobalWhitelister() 0 21 5
B retrieveFiles() 0 69 6
A __invoke() 0 23 2
A scopeFiles() 0 15 2
B scopeFile() 0 36 4
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\Logger\ConsoleLogger;
19
use Humbug\PhpScoper\Scoper;
20
use Humbug\PhpScoper\Throwable\Exception\ParsingException;
21
use Humbug\PhpScoper\Throwable\Exception\RuntimeException;
22
use SplFileInfo;
23
use Symfony\Component\Filesystem\Filesystem;
24
use Symfony\Component\Finder\Finder;
25
use Throwable;
26
use function Humbug\PhpScoper\get_common_path;
27
28
/**
29
 * @final
30
 */
31
class HandleAddPrefix
32
{
33
    private $fileSystem;
34
    private $scoper;
35
36 10
    public function __construct(Scoper $scoper)
37
    {
38 10
        $this->fileSystem = new Filesystem();
39 10
        $this->scoper = $scoper;
40
    }
41
42
    /**
43
     * Apply prefix to all the code found in the given paths, AKA scope all the files found.
44
     *
45
     * @param string              $prefix                   e.g. 'Foo'
46
     * @param string[]            $paths                    List of files to scan (absolute paths)
47
     * @param string              $output                   absolute path to the output directory
48
     * @param callable[]          $patchers
49
     * @param string[]|callable[] $globalNamespaceWhitelist
50
     * @param bool                $stopOnFailure
51
     * @param ConsoleLogger       $logger
52
     */
53 10
    public function __invoke(
54
        string $prefix,
55
        array $paths,
56
        string $output,
57
        array $patchers,
58
        array $globalNamespaceWhitelist,
59
        bool $stopOnFailure,
60
        ConsoleLogger $logger
61
    ) {
62 10
        $this->fileSystem->mkdir($output);
63
64
        try {
65 10
            $files = $this->retrieveFiles($paths, $output);
66
67 9
            $globalWhitelister = $this->createGlobalWhitelister($globalNamespaceWhitelist);
68
69 9
            $this->scopeFiles($files, $prefix, $patchers, $globalWhitelister, $stopOnFailure, $logger);
70 3
        } catch (Throwable $throwable) {
71 3
            $this->fileSystem->remove($output);
72
73 3
            throw $throwable;
74
        }
75
    }
76
77
    /**
78
     * @param string[]|callable[] $globalNamespaceWhitelist
79
     *
80
     * @return Closure
81
     */
82 9
    private function createGlobalWhitelister(array $globalNamespaceWhitelist): Closure
83
    {
84
        return function (string $className) use ($globalNamespaceWhitelist): bool {
85
            foreach ($globalNamespaceWhitelist as $whitelister) {
86
                if (is_string($whitelister)) {
87
                    if ($className === $whitelister) {
88
                        return true;
89
                    } else {
90
                        continue;
91
                    }
92
                }
93
94
                /** @var callable $whitelister */
95
                if (true === $whitelister($className)) {
96
                    return true;
97
                }
98
            }
99
100
            return false;
101 9
        };
102
    }
103
104
    /**
105
     * @param string[] $paths
106
     * @param string   $output
107
     *
108
     * @return string[]
109
     */
110 10
    private function retrieveFiles(array $paths, string $output): array
111
    {
112 10
        $pathsToSearch = [];
113 10
        $filesToAppend = [];
114
115 10
        foreach ($paths as $path) {
116 10
            if (false === file_exists($path)) {
117 1
                throw new RuntimeException(
118 1
                    sprintf(
119 1
                        'Could not find the file "%s".',
120 1
                        $path
121
                    )
122
                );
123
            }
124
125 9
            if (is_dir($path)) {
126 3
                $pathsToSearch[] = $path;
127
            } else {
128 9
                $filesToAppend[] = $path;
129
            }
130
        }
131
132 9
        $finder = new Finder();
133
134 9
        $finder->files()
135 9
            ->in($pathsToSearch)
136 9
            ->append($filesToAppend)
137 9
            ->sortByName()
138
        ;
139
140 9
        $files = array_values(
141 9
            array_map(
142
                function (SplFileInfo $fileInfo) {
143 8
                    return $fileInfo->getRealPath();
144 9
                },
145 9
                iterator_to_array($finder)
146
            )
147
        );
148
149 9
        $commonPath = get_common_path($files);
150
151 9
        return array_reduce(
152 9
            $files,
153 9
            function (array $files, string $file) use ($output, $commonPath): array {
154 8
                if (false === file_exists($file)) {
155
                    throw new RuntimeException(
156
                        sprintf(
157
                            'Could not find the file "%s".',
158
                            $file
159
                        )
160
                    );
161
                }
162
163 8
                if (false === is_readable($file)) {
164
                    throw new RuntimeException(
165
                        sprintf(
166
                            'Could not read the file "%s".',
167
                            $file
168
                        )
169
                    );
170
                }
171
172 8
                $files[$file] = $output.str_replace($commonPath, '', $file);
173
174 8
                return $files;
175 9
            },
176 9
            []
177
        );
178
    }
179
180
    /**
181
     * @param string[]      $files
182
     * @param string        $prefix
183
     * @param callable[]    $patchers
184
     * @param callable      $globalWhitelister
185
     * @param bool          $stopOnFailure
186
     * @param ConsoleLogger $logger
187
     */
188 9
    private function scopeFiles(
189
        array $files,
190
        string $prefix,
191
        array $patchers,
192
        callable $globalWhitelister,
193
        bool $stopOnFailure,
194
        ConsoleLogger $logger
195
    ) {
196 9
        $count = count($files);
197 9
        $logger->outputFileCount($count);
198
199 9
        foreach ($files as $inputFilePath => $outputFilePath) {
200 8
            $this->scopeFile($inputFilePath, $outputFilePath, $prefix, $patchers, $globalWhitelister, $stopOnFailure, $logger);
201
        }
202
    }
203
204
    /**
205
     * @param string        $inputFilePath
206
     * @param string        $outputFilePath
207
     * @param string        $prefix
208
     * @param callable[]    $patchers
209
     * @param callable      $globalWhitelister
210
     * @param bool          $stopOnFailure
211
     * @param ConsoleLogger $logger
212
     */
213 8
    private function scopeFile(
214
        string $inputFilePath,
215
        string $outputFilePath,
216
        string $prefix,
217
        array $patchers,
218
        callable $globalWhitelister,
219
        bool $stopOnFailure,
220
        ConsoleLogger $logger
221
    ) {
222
        try {
223 8
            $scoppedContent = $this->scoper->scope($inputFilePath, $prefix, $patchers, $globalWhitelister);
224 3
        } catch (Throwable $error) {
225 3
            $exception = new ParsingException(
226 3
                sprintf(
227 3
                    'Could not parse the file "%s".',
228 3
                    $inputFilePath
229
                ),
230 3
                0,
231 3
                $error
232
            );
233
234 3
            if ($stopOnFailure) {
235 2
                throw $exception;
236
            }
237
238 1
            $logger->outputWarnOfFailure($inputFilePath, $exception);
239
240 1
            $scoppedContent = file_get_contents($inputFilePath);
241
        }
242
243 6
        $this->fileSystem->dumpFile($outputFilePath, $scoppedContent);
244
245 6
        if (false === isset($exception)) {
246 5
            $logger->outputSuccess($inputFilePath);
247
        }
248
    }
249
}
250