Completed
Push — master ( 1ab698...097436 )
by Tomas
03:57
created

Dispatcher::log()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 6
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 3
nc 2
nop 3
crap 2
1
<?php
2
3
namespace Tomaj\Hermes;
4
5
use Exception;
6
use Psr\Log\LoggerInterface;
7
use Psr\Log\LogLevel;
8
use Tomaj\Hermes\Handler\HandlerInterface;
9
use Tomaj\Hermes\Driver\DriverInterface;
10
use Tomaj\Hermes\Restart\RestartException;
11
use Tomaj\Hermes\Restart\RestartInterface;
12
use Tracy\Debugger;
13
use DateTime;
14
15
class Dispatcher implements DispatcherInterface
16
{
17
    /**
18
     * Dispatcher driver
19
     *
20
     * @var DriverInterface
21
     */
22
    private $driver;
23
24
    /**
25
     * Logger
26
     *
27
     * @var LoggerInterface
28
     */
29
    private $logger;
30
31
    /**
32
     * Restart
33
     *
34
     * @var RestartInterface
35
     */
36
    private $restart;
37
38
    /**
39
     * All registered handlers
40
     *
41
     * @var HandlerInterface[][]
42
     */
43
    private $handlers = [];
44
45
    /**
46
     * @var DateTime
47
     */
48
    private $startTime;
49
50
    /**
51
     * Create new Dispatcher
52
     *
53
     * @param DriverInterface $driver
54
     * @param LoggerInterface $logger
55
     * @param RestartInterface $restart
56
     */
57 24
    public function __construct(DriverInterface $driver, LoggerInterface $logger = null, RestartInterface $restart = null)
58
    {
59 24
        $this->driver = $driver;
60 24
        $this->logger = $logger;
61 24
        $this->restart = $restart;
62 24
        $this->startTime = new DateTime();
63 24
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68 6
    public function emit(MessageInterface $message)
69
    {
70 6
        $this->driver->send($message);
71
72 6
        $this->log(
73 6
            LogLevel::INFO,
74 6
            "Dispatcher send message #{$message->getId()} to driver " . get_class($this->driver),
75 6
            $this->messageLoggerContext($message)
76 6
        );
77 6
        return $this;
78
    }
79
80
    /**
81
     * Basic method for background job to star listening.
82
     *
83
     * This method hook to driver wait() method and start listening events.
84
     * Method is blocking, so when you call it all processing will stop.
85
     * WARNING! Don't use it on web server calls. Run it only with cli.
86
     *
87
     * @return void
88
     */
89
    public function handle()
90
    {
91
        try {
92 18
            $this->driver->wait(function (MessageInterface $message) {
93 18
                $this->log(
94 18
                    LogLevel::INFO,
95 18
                    "Start handle message #{$message->getId()} ({$message->getType()})",
96 18
                    $this->messageLoggerContext($message)
97 18
                );
98
99 18
                $result = $this->dispatch($message);
100
101 18
                if ($this->restart && $this->restart->shouldRestart($this->startTime)) {
102 3
                    throw new RestartException('Restart');
103
                }
104
105 15
                return $result;
106 18
            });
107 18
        } catch (RestartException $e) {
108 3
            $this->log(LogLevel::NOTICE, 'Existing hermes dispatcher - restart');
109 3
        } catch (Exception $exception) {
110
            Debugger::log($exception, Debugger::EXCEPTION);
111
        }
112 18
    }
113
114
    /**
115
     * Dispatch message
116
     *
117
     * @param MessageInterface $message
118
     *
119
     * @return bool
120
     */
121 18
    private function dispatch(MessageInterface $message)
122
    {
123 18
        $type = $message->getType();
124
125 18
        if (!$this->hasHandlers($type)) {
126 6
            return true;
127
        }
128
129 15
        $result = true;
130
131 15
        foreach ($this->handlers[$type] as $handler) {
132 15
            $handlerResult = $this->handleMessage($handler, $message);
133
134 15
            if ($result && !$handlerResult) {
135 6
                $result = false;
136 6
            }
137 15
        }
138
139 15
        return $result;
140
    }
141
142
    /**
143
     * Handle given message with given handler
144
     *
145
     * @param HandlerInterface $handler
146
     * @param MessageInterface $message
147
     *
148
     * @return bool
149
     */
150 15
    private function handleMessage(HandlerInterface $handler, MessageInterface $message)
151
    {
152
        // check if handler implements Psr\Log\LoggerAwareInterface (you can use \Psr\Log\LoggerAwareTrait)
153 15
        if ($this->logger && method_exists($handler, 'setLogger')) {
154
            $handler->setLogger($this->logger);
0 ignored issues
show
Bug introduced by
The method setLogger() does not seem to exist on object<Tomaj\Hermes\Handler\HandlerInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
155
        }
156
157
        try {
158 15
            $result = $handler->handle($message);
159
160 12
            $this->log(
161 12
                LogLevel::INFO,
162 12
                "End handle message #{$message->getId()} ({$message->getType()})",
163 12
                $this->messageLoggerContext($message)
164 12
            );
165 15
        } catch (Exception $e) {
166 3
            $this->log(
167 3
                LogLevel::ERROR,
168 3
                "Handler " . get_class($handler) . " throws exception - {$e->getMessage()}",
169 3
                ['error' => $e, 'message' => $this->messageLoggerContext($message), 'exception' => $e]
170 3
            );
171 3
            Debugger::log($e, Debugger::EXCEPTION);
172 3
            $result = false;
173
        }
174 15
        return $result;
175
    }
176
177
    /**
178
     * Check if actual dispatcher has handler for given type
179
     *
180
     * @param string $type
181
     *
182
     * @return bool
183
     */
184 18
    private function hasHandlers($type)
185
    {
186 18
        return isset($this->handlers[$type]) && count($this->handlers[$type]) > 0;
187
    }
188
189
    /**
190
     * {@inheritdoc}
191
     */
192 18
    public function registerHandler($type, HandlerInterface $handler)
193
    {
194 18
        if (!isset($this->handlers[$type])) {
195 18
            $this->handlers[$type] = [];
196 18
        }
197
198 18
        $this->handlers[$type][] = $handler;
199 18
    }
200
201
    /**
202
     * Serialize message to logger context
203
     *
204
     * @param MessageInterface $message
205
     *
206
     * @return array
207
     */
208 24
    private function messageLoggerContext(MessageInterface $message)
209
    {
210
        return [
211 24
            'id' => $message->getId(),
212 24
            'created' => $message->getCreated(),
213 24
            'type' => $message->getType(),
214 24
            'payload' => $message->getPayload(),
215 24
        ];
216
    }
217
218
    /**
219
     * Interal log method wrapper
220
     *
221
     * @param string $level
222
     * @param string $message
223
     * @param array $context
224
     *
225
     * @return void
226
     */
227 24
    private function log($level, $message, array $context = array())
228
    {
229 24
        if ($this->logger) {
230 6
            $this->logger->log($level, $message, $context);
231 6
        }
232 24
    }
233
}
234