Open Journal Systems  3.3.0
lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php
1 <?php
2 
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11 
13 
14 use Psr\Log\LoggerInterface;
18 use Symfony\Component\Stopwatch\Stopwatch;
19 
28 {
29  protected $logger;
30  protected $stopwatch;
31 
32  private $called;
33  private $dispatcher;
34  private $wrappedListeners;
35 
36  public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null)
37  {
38  $this->dispatcher = $dispatcher;
39  $this->stopwatch = $stopwatch;
40  $this->logger = $logger;
41  $this->called = array();
42  $this->wrappedListeners = array();
43  }
44 
48  public function addListener($eventName, $listener, $priority = 0)
49  {
50  $this->dispatcher->addListener($eventName, $listener, $priority);
51  }
52 
56  public function addSubscriber(EventSubscriberInterface $subscriber)
57  {
58  $this->dispatcher->addSubscriber($subscriber);
59  }
60 
64  public function removeListener($eventName, $listener)
65  {
66  if (isset($this->wrappedListeners[$eventName])) {
67  foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
68  if ($wrappedListener->getWrappedListener() === $listener) {
69  $listener = $wrappedListener;
70  unset($this->wrappedListeners[$eventName][$index]);
71  break;
72  }
73  }
74  }
75 
76  return $this->dispatcher->removeListener($eventName, $listener);
77  }
78 
82  public function removeSubscriber(EventSubscriberInterface $subscriber)
83  {
84  return $this->dispatcher->removeSubscriber($subscriber);
85  }
86 
90  public function getListeners($eventName = null)
91  {
92  return $this->dispatcher->getListeners($eventName);
93  }
94 
98  public function getListenerPriority($eventName, $listener)
99  {
100  if (!method_exists($this->dispatcher, 'getListenerPriority')) {
101  return 0;
102  }
103 
104  return $this->dispatcher->getListenerPriority($eventName, $listener);
105  }
106 
110  public function hasListeners($eventName = null)
111  {
112  return $this->dispatcher->hasListeners($eventName);
113  }
114 
118  public function dispatch($eventName, Event $event = null)
119  {
120  if (null === $event) {
121  $event = new Event();
122  }
123 
124  if (null !== $this->logger && $event->isPropagationStopped()) {
125  $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName));
126  }
127 
128  $this->preProcess($eventName);
129  $this->preDispatch($eventName, $event);
130 
131  $e = $this->stopwatch->start($eventName, 'section');
132 
133  $this->dispatcher->dispatch($eventName, $event);
134 
135  if ($e->isStarted()) {
136  $e->stop();
137  }
138 
139  $this->postDispatch($eventName, $event);
140  $this->postProcess($eventName);
141 
142  return $event;
143  }
144 
148  public function getCalledListeners()
149  {
150  $called = array();
151  foreach ($this->called as $eventName => $listeners) {
152  foreach ($listeners as $listener) {
153  $info = $this->getListenerInfo($listener->getWrappedListener(), $eventName);
154  $called[$eventName.'.'.$info['pretty']] = $info;
155  }
156  }
157 
158  return $called;
159  }
160 
164  public function getNotCalledListeners()
165  {
166  try {
167  $allListeners = $this->getListeners();
168  } catch (\Exception $e) {
169  if (null !== $this->logger) {
170  $this->logger->info('An exception was thrown while getting the uncalled listeners.', array('exception' => $e));
171  }
172 
173  // unable to retrieve the uncalled listeners
174  return array();
175  }
176 
177  $notCalled = array();
178  foreach ($allListeners as $eventName => $listeners) {
179  foreach ($listeners as $listener) {
180  $called = false;
181  if (isset($this->called[$eventName])) {
182  foreach ($this->called[$eventName] as $l) {
183  if ($l->getWrappedListener() === $listener) {
184  $called = true;
185 
186  break;
187  }
188  }
189  }
190 
191  if (!$called) {
192  $info = $this->getListenerInfo($listener, $eventName);
193  $notCalled[$eventName.'.'.$info['pretty']] = $info;
194  }
195  }
196  }
197 
198  uasort($notCalled, array($this, 'sortListenersByPriority'));
199 
200  return $notCalled;
201  }
202 
211  public function __call($method, $arguments)
212  {
213  return \call_user_func_array(array($this->dispatcher, $method), $arguments);
214  }
215 
222  protected function preDispatch($eventName, Event $event)
223  {
224  }
225 
232  protected function postDispatch($eventName, Event $event)
233  {
234  }
235 
236  private function preProcess($eventName)
237  {
238  foreach ($this->dispatcher->getListeners($eventName) as $listener) {
239  $info = $this->getListenerInfo($listener, $eventName);
240  $name = isset($info['class']) ? $info['class'] : $info['type'];
241  $wrappedListener = new WrappedListener($listener, $name, $this->stopwatch, $this);
242  $this->wrappedListeners[$eventName][] = $wrappedListener;
243  $this->dispatcher->removeListener($eventName, $listener);
244  $this->dispatcher->addListener($eventName, $wrappedListener, $info['priority']);
245  }
246  }
247 
248  private function postProcess($eventName)
249  {
250  unset($this->wrappedListeners[$eventName]);
251  $skipped = false;
252  foreach ($this->dispatcher->getListeners($eventName) as $listener) {
253  if (!$listener instanceof WrappedListener) { // #12845: a new listener was added during dispatch.
254  continue;
255  }
256  // Unwrap listener
257  $priority = $this->getListenerPriority($eventName, $listener);
258  $this->dispatcher->removeListener($eventName, $listener);
259  $this->dispatcher->addListener($eventName, $listener->getWrappedListener(), $priority);
260 
261  $info = $this->getListenerInfo($listener->getWrappedListener(), $eventName);
262  if ($listener->wasCalled()) {
263  if (null !== $this->logger) {
264  $this->logger->debug(sprintf('Notified event "%s" to listener "%s".', $eventName, $info['pretty']));
265  }
266 
267  if (!isset($this->called[$eventName])) {
268  $this->called[$eventName] = new \SplObjectStorage();
269  }
270 
271  $this->called[$eventName]->attach($listener);
272  }
273 
274  if (null !== $this->logger && $skipped) {
275  $this->logger->debug(sprintf('Listener "%s" was not called for event "%s".', $info['pretty'], $eventName));
276  }
277 
278  if ($listener->stoppedPropagation()) {
279  if (null !== $this->logger) {
280  $this->logger->debug(sprintf('Listener "%s" stopped propagation of the event "%s".', $info['pretty'], $eventName));
281  }
282 
283  $skipped = true;
284  }
285  }
286  }
287 
296  private function getListenerInfo($listener, $eventName)
297  {
298  $info = array(
299  'event' => $eventName,
300  'priority' => $this->getListenerPriority($eventName, $listener),
301  );
302 
303  // unwrap for correct listener info
304  if ($listener instanceof WrappedListener) {
305  $listener = $listener->getWrappedListener();
306  }
307 
308  if ($listener instanceof \Closure) {
309  $info += array(
310  'type' => 'Closure',
311  'pretty' => 'closure',
312  );
313  } elseif (\is_string($listener)) {
314  try {
315  $r = new \ReflectionFunction($listener);
316  $file = $r->getFileName();
317  $line = $r->getStartLine();
318  } catch (\ReflectionException $e) {
319  $file = null;
320  $line = null;
321  }
322  $info += array(
323  'type' => 'Function',
324  'function' => $listener,
325  'file' => $file,
326  'line' => $line,
327  'pretty' => $listener,
328  );
329  } elseif (\is_array($listener) || (\is_object($listener) && \is_callable($listener))) {
330  if (!\is_array($listener)) {
331  $listener = array($listener, '__invoke');
332  }
333  $class = \is_object($listener[0]) ? \get_class($listener[0]) : $listener[0];
334  try {
335  $r = new \ReflectionMethod($class, $listener[1]);
336  $file = $r->getFileName();
337  $line = $r->getStartLine();
338  } catch (\ReflectionException $e) {
339  $file = null;
340  $line = null;
341  }
342  $info += array(
343  'type' => 'Method',
344  'class' => $class,
345  'method' => $listener[1],
346  'file' => $file,
347  'line' => $line,
348  'pretty' => $class.'::'.$listener[1],
349  );
350  }
351 
352  return $info;
353  }
354 
355  private function sortListenersByPriority($a, $b)
356  {
357  if (\is_int($a['priority']) && !\is_int($b['priority'])) {
358  return 1;
359  }
360 
361  if (!\is_int($a['priority']) && \is_int($b['priority'])) {
362  return -1;
363  }
364 
365  if ($a['priority'] === $b['priority']) {
366  return 0;
367  }
368 
369  if ($a['priority'] > $b['priority']) {
370  return -1;
371  }
372 
373  return 1;
374  }
375 }
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\getListeners
getListeners($eventName=null)
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:90
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\addSubscriber
addSubscriber(EventSubscriberInterface $subscriber)
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:56
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:27
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\removeListener
removeListener($eventName, $listener)
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:64
Symfony\Component\EventDispatcher\EventSubscriberInterface
Definition: lib/vendor/symfony/event-dispatcher/EventSubscriberInterface.php:25
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\getListenerPriority
getListenerPriority($eventName, $listener)
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:98
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\preDispatch
preDispatch($eventName, Event $event)
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:222
Symfony\Component\EventDispatcher\Debug\WrappedListener
Definition: lib/vendor/symfony/event-dispatcher/Debug/WrappedListener.php:21
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php:19
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\__construct
__construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger=null)
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:36
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\addListener
addListener($eventName, $listener, $priority=0)
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:48
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\postDispatch
postDispatch($eventName, Event $event)
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:232
Symfony\Component\EventDispatcher\Debug
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:12
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\hasListeners
hasListeners($eventName=null)
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:110
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\removeSubscriber
removeSubscriber(EventSubscriberInterface $subscriber)
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:82
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\$logger
$logger
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:29
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\getNotCalledListeners
getNotCalledListeners()
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:164
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\$stopwatch
$stopwatch
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:30
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\getCalledListeners
getCalledListeners()
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:148
Symfony\Component\EventDispatcher\EventDispatcherInterface
Definition: lib/vendor/symfony/event-dispatcher/EventDispatcherInterface.php:21
Symfony\Component\EventDispatcher\Event
Definition: lib/vendor/symfony/event-dispatcher/Event.php:28
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\__call
__call($method, $arguments)
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:211
Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher\dispatch
dispatch($eventName, Event $event=null)
Definition: lib/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:118