assertNamingConventionSatisfied()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 2
eloc 7
nc 2
nop 2
1
<?php
2
namespace PhpDDD\Command\Handler\Locator;
3
4
use PhpDDD\Command\CommandInterface;
5
use PhpDDD\Command\Exception\InvalidArgumentException;
6
use PhpDDD\Command\Exception\NoCommandHandlerRegisteredException;
7
use PhpDDD\Command\Handler\CommandHandlerInterface;
8
use PhpDDD\Command\Utils\ClassUtils;
9
10
/**
11
 * Implementation of CommandHandlerLocatorInterface
12
 */
13
class CommandHandlerLocator implements CommandHandlerLocatorInterface
14
{
15
16
    /**
17
     * @var CommandHandlerInterface[]
18
     */
19
    private $handlers = array();
20
21
    /**
22
     * {@inheritdoc}
23
     */
24
    public function getCommandHandlerForCommand(CommandInterface $command)
25
    {
26
        $commandClassName = get_class($command);
27
28
        if (!$this->isCommandRegistered($commandClassName)) {
29
            throw new NoCommandHandlerRegisteredException(
30
                sprintf(
31
                    'No handler registered to handle command "%s".',
32
                    $commandClassName
33
                )
34
            );
35
        }
36
37
        return $this->handlers[strtolower($commandClassName)];
38
    }
39
40
    /**
41
     * @return CommandHandlerInterface[]
42
     */
43
    public function getRegisteredCommandHandlers()
44
    {
45
        return $this->handlers;
46
    }
47
48
    /**
49
     * @param string                  $commandClassName
50
     * @param CommandHandlerInterface $commandHandler
51
     *
52
     * @throws InvalidArgumentException
53
     */
54
    public function register($commandClassName, CommandHandlerInterface $commandHandler)
55
    {
56
        $this->assertNamingConventionSatisfied($commandClassName, get_class($commandHandler));
57
        $this->assertImplementsCommandInterface($commandClassName);
58
59
        if ($this->isCommandRegistered($commandClassName)) {
60
            throw new InvalidArgumentException(
61
                sprintf(
62
                    'A command handler has already been defined for the command "%s". Previous handler: %s. New handler: %s',
63
                    $commandClassName,
64
                    get_class($this->handlers[strtolower($commandClassName)]),
65
                    get_class($commandHandler)
66
                )
67
            );
68
        }
69
        $this->handlers[strtolower($commandClassName)] = $commandHandler;
70
    }
71
72
    /**
73
     * @param string $commandClassName
74
     * @param string $handlerClassName
75
     *
76
     * @throws InvalidArgumentException
77
     */
78
    private function assertNamingConventionSatisfied($commandClassName, $handlerClassName)
79
    {
80
        if (!$this->isNamingConventionSatisfied($commandClassName, $handlerClassName)) {
81
            throw new InvalidArgumentException(
82
                sprintf(
83
                    'Command Handler does not follow naming convention. Expected: "%s". "%s" given.',
84
                    $this->getExpectedHandlerName($commandClassName),
85
                    ClassUtils::shortName($handlerClassName)
86
                )
87
            );
88
        }
89
    }
90
91
    /**
92
     * @param string $commandClassName
93
     * @param string $handlerClassName
94
     *
95
     * @return bool
96
     */
97
    private function isNamingConventionSatisfied($commandClassName, $handlerClassName)
98
    {
99
        $handlerClassName = ClassUtils::shortName($handlerClassName);
100
101
        return $this->getExpectedHandlerName($commandClassName) === $handlerClassName;
102
    }
103
104
    /**
105
     * @param string $commandClassName
106
     *
107
     * @return string
108
     */
109
    private function getExpectedHandlerName($commandClassName)
110
    {
111
        $commandClassName = ClassUtils::shortName($commandClassName);
112
        if ('Command' === substr($commandClassName, -7)) {
113
            $commandClassName = substr($commandClassName, 0, -7);
114
        }
115
116
        return $commandClassName.'CommandHandler';
117
    }
118
119
    /**
120
     * @param string $commandClassName
121
     *
122
     * @return bool
123
     */
124
    private function isCommandRegistered($commandClassName)
125
    {
126
        return isset($this->handlers[strtolower($commandClassName)]);
127
    }
128
129
    /**
130
     * @param string $commandClassName
131
     */
132
    private function assertImplementsCommandInterface($commandClassName)
133
    {
134
        if (!in_array('PhpDDD\\Command\\CommandInterface', class_implements($commandClassName), true)) {
135
            throw new InvalidArgumentException(
136
                sprintf(
137
                    'The class %s must implements the PhpDDD\\Command\\CommandInterface.',
138
                    $commandClassName
139
                )
140
            );
141
        }
142
    }
143
}
144