CommandArgumentsParser::parse()   A
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 14
c 0
b 0
f 0
dl 0
loc 28
ccs 15
cts 15
cp 1
rs 9.2222
cc 6
nc 6
nop 1
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Console\Domain\CommandArguments;
6
7
use InvalidArgumentException;
8
9
use function count;
10
11
final class CommandArgumentsParser implements CommandArgumentsParserInterface
12
{
13
    /**
14
     * @param array{
15
     *     autoload: array{"psr-4"?:array<string,string>},
16
     *     autoload-dev?: array{"psr-4"?:array<string,string>},
17
     * } $composerJson
18
     */
19 19
    public function __construct(
20
        private array $composerJson,
21
    ) {
22 19
    }
23
24
    /**
25
     * @param string $desiredNamespace The location of the new module. For example: App/TestModule
26
     *
27
     * @throws InvalidArgumentException
28
     */
29 19
    public function parse(string $desiredNamespace): CommandArguments
30
    {
31 19
        if (!isset($this->composerJson['autoload'])) {
32 1
            throw CommandArgumentsException::noAutoloadFound();
33
        }
34
35 18
        if (!isset($this->composerJson['autoload']['psr-4'])) {
36 1
            throw CommandArgumentsException::noAutoloadPsr4Found();
37
        }
38
39 17
        $psr4 = $this->composerJson['autoload']['psr-4'];
40 17
        $psr4Dev = $this->composerJson['autoload-dev']['psr-4'] ?? [];
41
42 17
        $allPsr4Combinations = $this->allPossiblePsr4Combinations($desiredNamespace);
43
44 17
        foreach ($allPsr4Combinations as $psr4Combination) {
45 17
            $psr4Key = $psr4Combination . '\\';
46
47 17
            if (isset($psr4[$psr4Key])) {
48 14
                return $this->foundPsr4($psr4Key, $psr4[$psr4Key], $desiredNamespace);
49
            }
50 17
51 2
            if (isset($psr4Dev[$psr4Key])) {
52
                return $this->foundPsr4($psr4Key, $psr4Dev[$psr4Key], $desiredNamespace);
53
            }
54
        }
55 1
56
        throw CommandArgumentsException::noAutoloadPsr4MatchFound($desiredNamespace, array_keys($psr4));
57
    }
58
59
    /**
60
     * Combine all possible psr-4 combinations and return them ordered by longer to shorter.
61
     * This way we'll be able to find the longer match first.
62
     * For example: App/TestModule/TestSubModule will produce an array such as:
63
     * [
64
     *   'App/TestModule/TestSubModule',
65
     *   'App/TestModule',
66
     *   'App',
67
     * ]
68
     *
69
     * @return list<string>
70 17
     */
71
    private function allPossiblePsr4Combinations(string $desiredNamespace): array
72 17
    {
73
        $result = [];
74 17
75 17
        foreach (explode('/', $desiredNamespace) as $explodedArg) {
76 17
            if ($result === []) {
77
                $result[] = $explodedArg;
78 17
            } else {
79 17
                $prevValue = $result[count($result) - 1];
80
                $result[] = $prevValue . '\\' . $explodedArg;
81
            }
82
        }
83 17
84
        return array_reverse($result);
85
    }
86 16
87
    private function foundPsr4(string $psr4Key, string $psr4Value, string $desiredNamespace): CommandArguments
88 16
    {
89 16
        $rootDir = mb_substr($psr4Value, 0, -1);
90 16
        $rootNamespace = mb_substr($psr4Key, 0, -1);
91 16
        $targetDirectory = str_replace(['/', $rootNamespace, '\\'], ['\\', $rootDir, '/'], $desiredNamespace);
92
        $namespace = str_replace([$rootDir, '/'], [$rootNamespace, '\\'], $targetDirectory);
93 16
94
        return new CommandArguments($namespace, $targetDirectory);
95
    }
96
}
97