Passed
Push — feature/create-console-bootstr... ( abaeda )
by Chema
04:15
created

CommandArgumentsParser::parse()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

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