Passed
Pull Request — master (#127)
by Sergei
07:40
created

CommandLoader::setCommandMap()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3.004

Importance

Changes 0
Metric Value
eloc 13
c 0
b 0
f 0
dl 0
loc 19
ccs 12
cts 13
cp 0.9231
rs 9.8333
cc 3
nc 3
nop 1
crap 3.004
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Console;
6
7
use Psr\Container\ContainerInterface;
8
use Symfony\Component\Console\Command\Command;
9
use Symfony\Component\Console\Command\LazyCommand;
10
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
11
use Symfony\Component\Console\Exception\CommandNotFoundException;
12
13
final class CommandLoader implements CommandLoaderInterface
14
{
15
    private ContainerInterface $container;
16
17
    /**
18
     * @psalm-var array<string, array{
19
     *         name: string,
20
     *         aliases: string[],
21
     *         class: class-string<Command>,
22
     *     }>
23
     */
24
    private array $commandMap;
25
26
    /**
27
     * @var string[]
28
     */
29
    private array $commandNames;
30
31
    /**
32
     * @param array $commandMap An array with command names as keys and service ids as values
33
     *
34
     * @psalm-param array<string, class-string> $commandMap
35
     */
36 33
    public function __construct(ContainerInterface $container, array $commandMap)
37
    {
38 33
        $this->container = $container;
39 33
        $this->setCommandMap($commandMap);
40 33
    }
41
42 9
    public function get(string $name)
43
    {
44 9
        if (!$this->has($name)) {
45
            throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
46
        }
47
48 9
        $commandName = $this->commandMap[$name]['name'];
49 9
        $commandAliases = $this->commandMap[$name]['aliases'];
50 9
        $commandClass = $this->commandMap[$name]['class'];
51
52 9
        $description = $commandClass::getDefaultDescription();
53
54 9
        if ($description === null) {
55 3
            return $this->getCommandInstance($name);
56
        }
57
58 6
        return new LazyCommand(
59 6
            $commandName,
60
            $commandAliases,
61
            $description,
62 6
            $commandName === '',
63 6
            function () use ($name) {
64 5
                return $this->getCommandInstance($name);
65 6
            }
66
        );
67
    }
68
69 9
    public function has(string $name): bool
70
    {
71 9
        return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]['class']);
72
    }
73
74
    public function getNames(): array
75
    {
76
        return $this->commandNames;
77
    }
78
79 8
    private function getCommandInstance(string $name): Command
80
    {
81 8
        $commandName = $this->commandMap[$name]['name'];
82 8
        $commandClass = $this->commandMap[$name]['class'];
83 8
        $commandAliases = $this->commandMap[$name]['aliases'];
84
85
        /** @var Command $command */
86 8
        $command = $this->container->get($commandClass);
87
88 8
        if ($command->getName() !== $commandName) {
89 1
            $command->setName($commandName);
90
        }
91 8
        if ($command->getAliases() !== $commandAliases) {
92
            $command->setAliases($commandAliases);
93
        }
94
95 8
        return $command;
96
    }
97
98
    /**
99
     * @psalm-param array<string, class-string> $commandMap
100
     */
101 33
    private function setCommandMap(array $commandMap): void
102
    {
103 33
        $this->commandMap = [];
104 33
        $this->commandNames = [];
105
106 33
        foreach ($commandMap as $name => $class) {
107 33
            $aliases = explode('|', $name);
108 33
            $primaryName = array_shift($aliases);
109
110
            $item = [
111 33
                'name' => $primaryName,
112 33
                'aliases' => $aliases,
113 33
                'class' => $class,
114
            ];
115
116 33
            $this->commandMap[$primaryName] = $item;
117 33
            $this->commandNames[] = $primaryName;
118 33
            foreach ($aliases as $alias) {
119
                $this->commandMap[$alias] = $item;
120
            }
121
        }
122 33
    }
123
}
124