[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
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 12 namespace Symfony\Component\EventDispatcher\Debug; 13 14 use Psr\Log\LoggerInterface; 15 use Symfony\Component\EventDispatcher\Event; 16 use Symfony\Component\EventDispatcher\EventDispatcherInterface; 17 use Symfony\Component\EventDispatcher\EventSubscriberInterface; 18 use Symfony\Component\Stopwatch\Stopwatch; 19 20 /** 21 * Collects some data about event listeners. 22 * 23 * This event dispatcher delegates the dispatching to another one. 24 * 25 * @author Fabien Potencier <fabien@symfony.com> 26 */ 27 class TraceableEventDispatcher implements TraceableEventDispatcherInterface 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 45 /** 46 * {@inheritdoc} 47 */ 48 public function addListener($eventName, $listener, $priority = 0) 49 { 50 $this->dispatcher->addListener($eventName, $listener, $priority); 51 } 52 53 /** 54 * {@inheritdoc} 55 */ 56 public function addSubscriber(EventSubscriberInterface $subscriber) 57 { 58 $this->dispatcher->addSubscriber($subscriber); 59 } 60 61 /** 62 * {@inheritdoc} 63 */ 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 79 /** 80 * {@inheritdoc} 81 */ 82 public function removeSubscriber(EventSubscriberInterface $subscriber) 83 { 84 return $this->dispatcher->removeSubscriber($subscriber); 85 } 86 87 /** 88 * {@inheritdoc} 89 */ 90 public function getListeners($eventName = null) 91 { 92 return $this->dispatcher->getListeners($eventName); 93 } 94 95 /** 96 * {@inheritdoc} 97 */ 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 107 /** 108 * {@inheritdoc} 109 */ 110 public function hasListeners($eventName = null) 111 { 112 return $this->dispatcher->hasListeners($eventName); 113 } 114 115 /** 116 * {@inheritdoc} 117 */ 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 145 /** 146 * {@inheritdoc} 147 */ 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 161 /** 162 * {@inheritdoc} 163 */ 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 203 /** 204 * Proxies all method calls to the original event dispatcher. 205 * 206 * @param string $method The method name 207 * @param array $arguments The method arguments 208 * 209 * @return mixed 210 */ 211 public function __call($method, $arguments) 212 { 213 return \call_user_func_array(array($this->dispatcher, $method), $arguments); 214 } 215 216 /** 217 * Called before dispatching the event. 218 * 219 * @param string $eventName The event name 220 * @param Event $event The event 221 */ 222 protected function preDispatch($eventName, Event $event) 223 { 224 } 225 226 /** 227 * Called after dispatching the event. 228 * 229 * @param string $eventName The event name 230 * @param Event $event The event 231 */ 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 288 /** 289 * Returns information about the listener. 290 * 291 * @param object $listener The listener 292 * @param string $eventName The event name 293 * 294 * @return array Information about the listener 295 */ 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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |