Completed
Push — 4.0 ( 2b6eba...f29336 )
by Jacek
05:04
created

EventManager::addListener()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 8
Bugs 1 Features 1
Metric Value
c 8
b 1
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 2
1
<?php
2
3
/**
4
 * Copyright (c) 2016 Jacek Kobus <[email protected]>
5
 * See the file LICENSE.md for copying permission.
6
 */
7
8
namespace PHPExtra\EventManager;
9
10
use PHPExtra\EventManager\Event\Event;
11
use PHPExtra\EventManager\Exception\EventException;
12
use PHPExtra\EventManager\Listener\Listener;
13
use PHPExtra\EventManager\Worker\ArrayWorkerQueue;
14
use PHPExtra\EventManager\Worker\WorkerQueue;
15
use PHPExtra\EventManager\Worker\Worker;
16
use PHPExtra\EventManager\Worker\WorkerFactory;
17
use PHPExtra\EventManager\Worker\WorkerResult;
18
use Psr\Log\LoggerAwareInterface;
19
use Psr\Log\LoggerInterface;
20
use Psr\Log\NullLogger;
21
22
/**
23
 * The default EventManager implementation
24
 *
25
 * @author Jacek Kobus <[email protected]>
26
 */
27
class EventManager implements EventEmitter, LoggerAwareInterface
28
{
29
    /**
30
     * @var WorkerFactory
31
     */
32
    private $workerFactory = null;
33
34
    /**
35
     * @var WorkerQueue|Worker[]
36
     */
37
    private $workerQueue;
38
39
    /**
40
     * Whenever to throw exceptions caught from listeners or not
41
     *
42
     * @var bool
43
     */
44
    private $throwExceptions = false;
45
46
    /**
47
     * Currently running event
48
     *
49
     * @var Event
50
     */
51
    private $runningEvent = null;
52
53
    /**
54
     * @var LoggerInterface
55
     */
56
    private $logger;
57
58
    /**
59
     * Create new event manager
60
     */
61
    public function __construct()
62
    {
63
        $this->workerFactory = new WorkerFactory();
64
        $this->workerQueue = new ArrayWorkerQueue();
65
        $this->logger = new NullLogger();
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71
    public function emit(Event $event)
72
    {
73
        $previousRunningEvent = $this->runningEvent;
74
        $this->runningEvent = $event;
75
76
        $workers = $this->workerQueue->getWorkersFor($event);
77
78
        if (count($workers) > 0) {
79
            foreach ($workers as $worker) {
80
                $this->runWorker($worker, $event);
81
            }
82
        } else {
83
            $this->logger->debug(sprintf('Event %s has no workers', get_class($event)));
84
        }
85
86
        $this->runningEvent = $previousRunningEvent;
87
88
        return $this;
89
    }
90
91
    /**
92
     * @return Event
93
     */
94
    public function getRunningEvent()
95
    {
96
        return $this->runningEvent;
97
    }
98
99
    /**
100
     * @param Worker $worker
101
     * @param Event  $event
102
     */
103
    protected function onWorkerStart(Worker $worker, Event $event)
104
    {
105
    }
106
107
    /**
108
     * @param Worker $worker
109
     * @param Event  $event
110
     */
111
    protected function onWorkerStop(Worker $worker, Event $event)
112
    {
113
    }
114
115
    /**
116
     * @param Worker $worker
117
     * @param Event  $event
118
     *
119
     * @throws EventException
120
     * @return WorkerResult
121
     */
122
    private function runWorker(Worker $worker, Event $event)
123
    {
124
        $this->logger->debug(sprintf('Starting worker #%s with priority %s for event %s', $worker, $worker->getPriority(), get_class($event)));
125
126
        $this->onWorkerStart($worker, $event);
127
        $result = $worker->run($event);
128
        $this->onWorkerStop($worker, $event);
129
130
        if (!$result->isSuccessful()) {
131
            $this->logger->warning(sprintf('Worker #%s failed: %s', $worker, $result->getMessage()));
132
133
            if ($this->throwExceptions) {
134
                $this->logger->debug(sprintf('Throwing exception (throwExceptions is set to true)', $worker));
135
                $exception = new EventException($event, $worker->getListener(), sprintf('Worker #%s failed', $worker->getId()), $result->getException());
136
137
                throw $exception;
138
            }
139
        }
140
141
        return $result;
142
    }
143
144
    /**
145
     * Set to true to throw exceptions coming from listeners.
146
     * By default all exceptions are suppressed.
147
     *
148
     * @param bool $throwExceptions
149
     *
150
     * @return $this
151
     */
152
    public function setThrowExceptions($throwExceptions = true)
153
    {
154
        $this->throwExceptions = (bool)$throwExceptions;
155
156
        return $this;
157
    }
158
159
    /**
160
     * @see Priority
161
     *
162
     * @param Listener $listener
163
     * @param int      $priority
164
     *
165
     * @return $this
166
     */
167
    public function add(Listener $listener, $priority = null)
168
    {
169
        $workers = $this->workerFactory->createWorkers($listener, $priority);
170
        $workersCount = 0;
171
172
        if ($priority !== null) {
173
            $this->logger->debug(sprintf('Overriding priority for all workers to %s in %s', $priority, get_class($listener)));
174
        }
175
176
        foreach ($workers as $worker) {
177
            $this->addWorker($worker);
178
            $workersCount++;
179
        }
180
181
        if ($workersCount == 0) {
182
            $this->logger->debug(sprintf('Listener "%s" does not have any workers', get_class($listener)));
183
        }
184
185
        return $this;
186
    }
187
188
    /**
189
     * @param Worker $worker
190
     *
191
     * @return $this
192
     */
193
    private function addWorker(Worker $worker)
194
    {
195
        $this->workerQueue->addWorker($worker);
196
197
        return $this;
198
    }
199
200
    /**
201
     * {@inheritdoc}
202
     */
203
    public function setLogger(LoggerInterface $logger)
204
    {
205
        $this->logger = $logger;
206
207
        return $this;
208
    }
209
}