CommandArgumentsParser   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 85
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 11
eloc 28
c 0
b 0
f 0
dl 0
loc 85
rs 10

4 Methods

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