InspectSymbolCommand::getConfigFilePath()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 11
rs 10
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\Console\Command;
16
17
use Fidry\Console\Command\Command;
18
use Fidry\Console\Command\CommandRegistry;
19
use Fidry\Console\Command\Configuration as CommandConfiguration;
20
use Fidry\Console\ExitCode;
21
use Fidry\Console\Input\IO;
22
use Humbug\PhpScoper\Configuration\Configuration;
23
use Humbug\PhpScoper\Configuration\ConfigurationFactory;
24
use Humbug\PhpScoper\Console\ConfigLoader;
25
use Humbug\PhpScoper\Symbol\EnrichedReflector;
26
use Humbug\PhpScoper\Symbol\EnrichedReflectorFactory;
27
use InvalidArgumentException;
28
use Symfony\Component\Console\Application as DummyApplication;
29
use Symfony\Component\Console\Input\InputArgument;
30
use Symfony\Component\Console\Input\InputOption;
31
use Symfony\Component\Console\Output\NullOutput;
32
use Symfony\Component\Filesystem\Filesystem;
33
use Symfony\Component\Filesystem\Path;
34
use function assert;
35
use function file_exists;
36
use function implode;
37
use function Safe\getcwd;
38
use function Safe\sprintf;
39
use const DIRECTORY_SEPARATOR;
40
41
/**
42
 * @private
43
 */
44
final class InspectSymbolCommand implements Command
45
{
46
    private const SYMBOL_ARG = 'symbol';
47
    private const SYMBOL_TYPE_ARG = 'type';
48
    private const CONFIG_FILE_OPT = 'config';
49
    private const NO_CONFIG_OPT = 'no-config';
50
51
    private Filesystem $fileSystem;
52
    private ConfigurationFactory $configFactory;
53
    private EnrichedReflectorFactory $enrichedReflectorFactory;
54
55
    public function __construct(
56
        Filesystem $fileSystem,
57
        ConfigurationFactory $configFactory,
58
        EnrichedReflectorFactory $enrichedReflectorFactory
59
    ) {
60
        $this->fileSystem = $fileSystem;
61
        $this->configFactory = $configFactory;
62
        $this->enrichedReflectorFactory = $enrichedReflectorFactory;
63
    }
64
65
    public function getConfiguration(): CommandConfiguration
66
    {
67
        return new CommandConfiguration(
68
            'inspect-symbol',
69
            'Checks the given symbol for a given configuration. Helpful to have an insight on how PHP-Scoper will interpret this symbol',
70
            '',
71
            [
72
                new InputArgument(
73
                    self::SYMBOL_ARG,
74
                    InputArgument::REQUIRED,
75
                    'The symbol to inspect.',
76
                ),
77
                new InputArgument(
78
                    self::SYMBOL_TYPE_ARG,
79
                    InputArgument::OPTIONAL,
80
                    sprintf(
0 ignored issues
show
Deprecated Code introduced by
The function Safe\sprintf() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+ ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

80
                    /** @scrutinizer ignore-deprecated */ sprintf(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
81
                        'The symbol type inspect ("%s").',
82
                        implode('", "', SymbolType::ALL),
83
                    ),
84
                    SymbolType::ANY_TYPE,
85
                ),
86
            ],
87
            [
88
                ChangeableDirectory::createOption(),
89
                new InputOption(
90
                    self::CONFIG_FILE_OPT,
91
                    'c',
92
                    InputOption::VALUE_REQUIRED,
93
                    sprintf(
0 ignored issues
show
Deprecated Code introduced by
The function Safe\sprintf() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+ ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

93
                    /** @scrutinizer ignore-deprecated */ sprintf(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
94
                        'Configuration file. Will use "%s" if found by default.',
95
                        ConfigurationFactory::DEFAULT_FILE_NAME,
96
                    ),
97
                ),
98
                new InputOption(
99
                    self::NO_CONFIG_OPT,
100
                    null,
101
                    InputOption::VALUE_NONE,
102
                    'Do not look for a configuration file.',
103
                ),
104
            ],
105
        );
106
    }
107
108
    public function execute(IO $io): int
109
    {
110
        $io->newLine();
111
112
        ChangeableDirectory::changeWorkingDirectory($io);
113
114
        // Only get current working directory _after_ we changed to the desired
115
        // working directory
116
        $cwd = getcwd();
117
118
        $symbol = $io->getArgument(self::SYMBOL_ARG)->asString();
119
        /** @var SymbolType::*_TYPE $symbolType */
120
        $symbolType = $io->getArgument(self::SYMBOL_TYPE_ARG)->asStringChoice(SymbolType::ALL);
121
        $config = $this->retrieveConfig($io, $cwd);
122
123
        $enrichedReflector = $this->enrichedReflectorFactory->create(
124
            $config->getSymbolsConfiguration(),
125
        );
126
127
        self::printSymbol(
128
            $io,
129
            $symbol,
130
            $symbolType,
131
            $config->getPath(),
132
            $enrichedReflector,
133
        );
134
135
        return ExitCode::SUCCESS;
136
    }
137
138
    private function retrieveConfig(IO $io, string $cwd): Configuration
139
    {
140
        $configLoader = new ConfigLoader(
141
            new CommandRegistry(new DummyApplication()),
142
            $this->fileSystem,
143
            $this->configFactory,
144
        );
145
146
        $configFilePath = $this->getConfigFilePath($io, $cwd);
147
        $noConfig = $io->getOption(self::NO_CONFIG_OPT)->asBoolean();
148
149
        if (null === $configFilePath) {
150
            // Unlike when scoping, we do not want a config file to be created
151
            // neither bother the user with passing the no-config option if the
152
            // file does not exist.
153
            $noConfig = true;
154
        }
155
156
        return $configLoader->loadConfig(
157
            new IO(
158
                $io->getInput(),
159
                new NullOutput(),
160
            ),
161
            '',
162
            $noConfig,
163
            $configFilePath,
164
            ConfigurationFactory::DEFAULT_FILE_NAME,
165
            // We do not want the init command to be triggered if there is no
166
            // config file.
167
            true,
168
            [],
169
            getcwd(),
170
        );
171
    }
172
173
    /**
174
     * @return non-empty-string|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string|null at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string|null.
Loading history...
175
     */
176
    private function getConfigFilePath(IO $io, string $cwd): ?string
177
    {
178
        $configPath = (string) $io->getOption(self::CONFIG_FILE_OPT)->asNullableString();
179
180
        if ('' === $configPath) {
181
            $configPath = ConfigurationFactory::DEFAULT_FILE_NAME;
182
        }
183
184
        $configPath = $this->canonicalizePath($configPath, $cwd);
185
186
        return file_exists($configPath) ? $configPath : null;
187
    }
188
189
    /**
190
     * @param SymbolType::*_TYPE $type
0 ignored issues
show
Documentation Bug introduced by
The doc comment $type at position 0 could not be parsed: Unknown type name '$type' at position 0 in $type.
Loading history...
191
     */
192
    private static function printSymbol(
193
        IO $io,
194
        string $symbol,
195
        string $type,
196
        ?string $configPath,
197
        EnrichedReflector $reflector
198
    ): void {
199
        self::printDocBlock($io);
200
        self::printConfigLoaded($io, $configPath);
201
        self::printInspectionHeadline($io, $symbol, $type);
202
203
        $io->newLine();
204
205
        if (!(SymbolType::ANY_TYPE === $type)) {
206
            self::printTypedSymbol($io, $symbol, $type, $reflector);
207
        } else {
208
            self::printAnyTypeSymbol($io, $symbol, $reflector);
209
        }
210
    }
211
212
    private static function printDocBlock(IO $io): void
213
    {
214
        $io->writeln([
215
            'Internal (configured via the `excluded-*` settings) are treated as PHP native symbols, i.e. will remain untouched.',
216
            'Exposed symbols (configured via the `expose-*` settings) will be prefixed but aliased to its original symbol.',
217
            'If a symbol is neither internal or exposed, it will be prefixed and not aliased',
218
            '',
219
            'For more information, see:',
220
        ]);
221
        $io->listing([
222
            '<href=https://github.com/humbug/php-scoper/blob/master/docs/configuration.md#excluded-symbols>Doc link for excluded symbols</>',
223
            '<href=https://github.com/humbug/php-scoper/blob/master/docs/configuration.md#exposed-symbols>Doc link for exposed symbols</>',
224
        ]);
225
    }
226
227
    private static function printConfigLoaded(IO $io, ?string $configPath): void
228
    {
229
        $io->writeln(
230
            null === $configPath
231
                ? 'No configuration loaded.'
232
                : sprintf(
0 ignored issues
show
Deprecated Code introduced by
The function Safe\sprintf() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+ ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

232
                : /** @scrutinizer ignore-deprecated */ sprintf(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
233
                    'Loaded the configuration <comment>%s</comment>',
234
                    $configPath,
235
                ),
236
        );
237
        $io->newLine();
238
    }
239
240
    /**
241
     * @param SymbolType::*_TYPE $type
0 ignored issues
show
Documentation Bug introduced by
The doc comment $type at position 0 could not be parsed: Unknown type name '$type' at position 0 in $type.
Loading history...
242
     */
243
    private static function printInspectionHeadline(
244
        IO $io,
245
        string $symbol,
246
        string $type
247
    ): void {
248
        $io->writeln(
249
            sprintf(
0 ignored issues
show
Deprecated Code introduced by
The function Safe\sprintf() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+ ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

249
            /** @scrutinizer ignore-deprecated */ sprintf(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
250
                'Inspecting the symbol <comment>%s</comment> %s',
251
                $symbol,
252
                SymbolType::ANY_TYPE === $type
253
                    ? 'for all types.'
254
                    : sprintf('for type <comment>%s</comment>:', $type),
0 ignored issues
show
Deprecated Code introduced by
The function Safe\sprintf() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+ ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

254
                    : /** @scrutinizer ignore-deprecated */ sprintf('for type <comment>%s</comment>:', $type),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
255
            ),
256
        );
257
    }
258
259
    private static function printAnyTypeSymbol(
260
        IO $io,
261
        string $symbol,
262
        EnrichedReflector $reflector
263
    ): void {
264
        foreach (SymbolType::getAllSpecificTypes() as $specificType) {
265
            $io->writeln(
266
                sprintf(
0 ignored issues
show
Deprecated Code introduced by
The function Safe\sprintf() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+ ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

266
                /** @scrutinizer ignore-deprecated */ sprintf(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
267
                    'As a <comment>%s</comment>:',
268
                    $specificType,
269
                ),
270
            );
271
272
            self::printTypedSymbol($io, $symbol, $specificType, $reflector);
273
        }
274
    }
275
276
    /**
277
     * @param SymbolType::*_TYPE $type
0 ignored issues
show
Documentation Bug introduced by
The doc comment $type at position 0 could not be parsed: Unknown type name '$type' at position 0 in $type.
Loading history...
278
     */
279
    private static function printTypedSymbol(
280
        IO $io,
281
        string $symbol,
282
        string $type,
283
        EnrichedReflector $reflector
284
    ): void {
285
        [$internal, $exposed] = self::determineSymbolStatus(
286
            $symbol,
287
            $type,
288
            $reflector,
289
        );
290
291
        $io->listing([
292
            sprintf(
0 ignored issues
show
Deprecated Code introduced by
The function Safe\sprintf() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+ ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

292
            /** @scrutinizer ignore-deprecated */ sprintf(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
293
                'Internal: %s',
294
                self::convertBoolToString($internal),
295
            ),
296
            sprintf(
0 ignored issues
show
Deprecated Code introduced by
The function Safe\sprintf() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+ ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

296
            /** @scrutinizer ignore-deprecated */ sprintf(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
297
                'Exposed:  %s',
298
                self::convertBoolToString($exposed),
299
            ),
300
        ]);
301
    }
302
303
    /**
304
     * @param SymbolType::*_TYPE $type
0 ignored issues
show
Documentation Bug introduced by
The doc comment $type at position 0 could not be parsed: Unknown type name '$type' at position 0 in $type.
Loading history...
305
     */
306
    private static function determineSymbolStatus(
307
        string $symbol,
308
        string $type,
309
        EnrichedReflector $reflector
310
    ): array {
311
        switch ($type) {
312
            case SymbolType::CLASS_TYPE:
313
                return [
314
                    $reflector->isClassInternal($symbol),
315
                    $reflector->isExposedClass($symbol),
316
                ];
317
318
            case SymbolType::FUNCTION_TYPE:
319
                return [
320
                    $reflector->isFunctionInternal($symbol),
321
                    $reflector->isExposedFunction($symbol),
322
                ];
323
324
            case SymbolType::CONSTANT_TYPE:
325
                return [
326
                    $reflector->isConstantInternal($symbol),
327
                    $reflector->isExposedConstant($symbol),
328
                ];
329
        }
330
331
        throw new InvalidArgumentException(
332
            sprintf(
0 ignored issues
show
Deprecated Code introduced by
The function Safe\sprintf() has been deprecated: The Safe version of this function is no longer needed in PHP 8.0+ ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

332
            /** @scrutinizer ignore-deprecated */ sprintf(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
333
                'Invalid type "%s"',
334
                $type,
335
            ),
336
        );
337
    }
338
339
    private static function convertBoolToString(bool $bool): string
340
    {
341
        return true === $bool ? '<question>true</question>' : '<error>false</error>';
342
    }
343
344
    /**
345
     * @param non-empty-string $path
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
346
     *
347
     * @return non-empty-string Absolute canonical path
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
348
     */
349
    private function canonicalizePath(string $path, string $cwd): string
350
    {
351
        $canonicalPath = Path::canonicalize(
352
            $this->fileSystem->isAbsolutePath($path)
353
                ? $path
354
                : $cwd.DIRECTORY_SEPARATOR.$path,
355
        );
356
357
        assert('' !== $canonicalPath);
358
359
        return $canonicalPath;
360
    }
361
}
362