comparison vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php @ 17:129ea1e6d783

Update, including to Drupal core 8.6.10
author Chris Cannam
date Thu, 28 Feb 2019 13:21:36 +0000
parents 1fec387a4317
children af1871eacc83
comparison
equal deleted inserted replaced
16:c2387f117808 17:129ea1e6d783
9 * file that was distributed with this source code. 9 * file that was distributed with this source code.
10 */ 10 */
11 11
12 namespace Symfony\Component\EventDispatcher\Debug; 12 namespace Symfony\Component\EventDispatcher\Debug;
13 13
14 use Psr\Log\LoggerInterface;
15 use Symfony\Component\EventDispatcher\Event;
14 use Symfony\Component\EventDispatcher\EventDispatcherInterface; 16 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
15 use Symfony\Component\EventDispatcher\EventSubscriberInterface; 17 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
16 use Symfony\Component\EventDispatcher\Event;
17 use Symfony\Component\Stopwatch\Stopwatch; 18 use Symfony\Component\Stopwatch\Stopwatch;
18 use Psr\Log\LoggerInterface;
19 19
20 /** 20 /**
21 * Collects some data about event listeners. 21 * Collects some data about event listeners.
22 * 22 *
23 * This event dispatcher delegates the dispatching to another one. 23 * This event dispatcher delegates the dispatching to another one.
27 class TraceableEventDispatcher implements TraceableEventDispatcherInterface 27 class TraceableEventDispatcher implements TraceableEventDispatcherInterface
28 { 28 {
29 protected $logger; 29 protected $logger;
30 protected $stopwatch; 30 protected $stopwatch;
31 31
32 private $called; 32 private $callStack;
33 private $dispatcher; 33 private $dispatcher;
34 private $wrappedListeners; 34 private $wrappedListeners;
35 35
36 public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null) 36 public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null)
37 { 37 {
38 $this->dispatcher = $dispatcher; 38 $this->dispatcher = $dispatcher;
39 $this->stopwatch = $stopwatch; 39 $this->stopwatch = $stopwatch;
40 $this->logger = $logger; 40 $this->logger = $logger;
41 $this->called = array(); 41 $this->wrappedListeners = [];
42 $this->wrappedListeners = array();
43 } 42 }
44 43
45 /** 44 /**
46 * {@inheritdoc} 45 * {@inheritdoc}
47 */ 46 */
121 /** 120 /**
122 * {@inheritdoc} 121 * {@inheritdoc}
123 */ 122 */
124 public function dispatch($eventName, Event $event = null) 123 public function dispatch($eventName, Event $event = null)
125 { 124 {
125 if (null === $this->callStack) {
126 $this->callStack = new \SplObjectStorage();
127 }
128
126 if (null === $event) { 129 if (null === $event) {
127 $event = new Event(); 130 $event = new Event();
128 } 131 }
129 132
130 if (null !== $this->logger && $event->isPropagationStopped()) { 133 if (null !== $this->logger && $event->isPropagationStopped()) {
131 $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName)); 134 $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName));
132 } 135 }
133 136
134 $this->preProcess($eventName); 137 $this->preProcess($eventName);
135 $this->preDispatch($eventName, $event); 138 try {
136 139 $this->preDispatch($eventName, $event);
137 $e = $this->stopwatch->start($eventName, 'section'); 140 try {
138 141 $e = $this->stopwatch->start($eventName, 'section');
139 $this->dispatcher->dispatch($eventName, $event); 142 try {
140 143 $this->dispatcher->dispatch($eventName, $event);
141 if ($e->isStarted()) { 144 } finally {
142 $e->stop(); 145 if ($e->isStarted()) {
143 } 146 $e->stop();
144 147 }
145 $this->postDispatch($eventName, $event); 148 }
146 $this->postProcess($eventName); 149 } finally {
150 $this->postDispatch($eventName, $event);
151 }
152 } finally {
153 $this->postProcess($eventName);
154 }
147 155
148 return $event; 156 return $event;
149 } 157 }
150 158
151 /** 159 /**
152 * {@inheritdoc} 160 * {@inheritdoc}
153 */ 161 */
154 public function getCalledListeners() 162 public function getCalledListeners()
155 { 163 {
156 $called = array(); 164 if (null === $this->callStack) {
157 foreach ($this->called as $eventName => $listeners) { 165 return [];
158 foreach ($listeners as $listener) { 166 }
159 $called[$eventName.'.'.$listener->getPretty()] = $listener->getInfo($eventName); 167
160 } 168 $called = [];
169 foreach ($this->callStack as $listener) {
170 list($eventName) = $this->callStack->getInfo();
171
172 $called[] = $listener->getInfo($eventName);
161 } 173 }
162 174
163 return $called; 175 return $called;
164 } 176 }
165 177
170 { 182 {
171 try { 183 try {
172 $allListeners = $this->getListeners(); 184 $allListeners = $this->getListeners();
173 } catch (\Exception $e) { 185 } catch (\Exception $e) {
174 if (null !== $this->logger) { 186 if (null !== $this->logger) {
175 $this->logger->info('An exception was thrown while getting the uncalled listeners.', array('exception' => $e)); 187 $this->logger->info('An exception was thrown while getting the uncalled listeners.', ['exception' => $e]);
176 } 188 }
177 189
178 // unable to retrieve the uncalled listeners 190 // unable to retrieve the uncalled listeners
179 return array(); 191 return [];
180 } 192 }
181 193
182 $notCalled = array(); 194 $notCalled = [];
183 foreach ($allListeners as $eventName => $listeners) { 195 foreach ($allListeners as $eventName => $listeners) {
184 foreach ($listeners as $listener) { 196 foreach ($listeners as $listener) {
185 $called = false; 197 $called = false;
186 if (isset($this->called[$eventName])) { 198 if (null !== $this->callStack) {
187 foreach ($this->called[$eventName] as $l) { 199 foreach ($this->callStack as $calledListener) {
188 if ($l->getWrappedListener() === $listener) { 200 if ($calledListener->getWrappedListener() === $listener) {
189 $called = true; 201 $called = true;
190 202
191 break; 203 break;
192 } 204 }
193 } 205 }
195 207
196 if (!$called) { 208 if (!$called) {
197 if (!$listener instanceof WrappedListener) { 209 if (!$listener instanceof WrappedListener) {
198 $listener = new WrappedListener($listener, null, $this->stopwatch, $this); 210 $listener = new WrappedListener($listener, null, $this->stopwatch, $this);
199 } 211 }
200 $notCalled[$eventName.'.'.$listener->getPretty()] = $listener->getInfo($eventName); 212 $notCalled[] = $listener->getInfo($eventName);
201 } 213 }
202 } 214 }
203 } 215 }
204 216
205 uasort($notCalled, array($this, 'sortListenersByPriority')); 217 uasort($notCalled, [$this, 'sortNotCalledListeners']);
206 218
207 return $notCalled; 219 return $notCalled;
208 } 220 }
209 221
210 public function reset() 222 public function reset()
211 { 223 {
212 $this->called = array(); 224 $this->callStack = null;
213 } 225 }
214 226
215 /** 227 /**
216 * Proxies all method calls to the original event dispatcher. 228 * Proxies all method calls to the original event dispatcher.
217 * 229 *
220 * 232 *
221 * @return mixed 233 * @return mixed
222 */ 234 */
223 public function __call($method, $arguments) 235 public function __call($method, $arguments)
224 { 236 {
225 return call_user_func_array(array($this->dispatcher, $method), $arguments); 237 return \call_user_func_array([$this->dispatcher, $method], $arguments);
226 } 238 }
227 239
228 /** 240 /**
229 * Called before dispatching the event. 241 * Called before dispatching the event.
230 * 242 *
247 259
248 private function preProcess($eventName) 260 private function preProcess($eventName)
249 { 261 {
250 foreach ($this->dispatcher->getListeners($eventName) as $listener) { 262 foreach ($this->dispatcher->getListeners($eventName) as $listener) {
251 $priority = $this->getListenerPriority($eventName, $listener); 263 $priority = $this->getListenerPriority($eventName, $listener);
252 $wrappedListener = new WrappedListener($listener, null, $this->stopwatch, $this); 264 $wrappedListener = new WrappedListener($listener instanceof WrappedListener ? $listener->getWrappedListener() : $listener, null, $this->stopwatch, $this);
253 $this->wrappedListeners[$eventName][] = $wrappedListener; 265 $this->wrappedListeners[$eventName][] = $wrappedListener;
254 $this->dispatcher->removeListener($eventName, $listener); 266 $this->dispatcher->removeListener($eventName, $listener);
255 $this->dispatcher->addListener($eventName, $wrappedListener, $priority); 267 $this->dispatcher->addListener($eventName, $wrappedListener, $priority);
268 $this->callStack->attach($wrappedListener, [$eventName]);
256 } 269 }
257 } 270 }
258 271
259 private function postProcess($eventName) 272 private function postProcess($eventName)
260 { 273 {
268 $priority = $this->getListenerPriority($eventName, $listener); 281 $priority = $this->getListenerPriority($eventName, $listener);
269 $this->dispatcher->removeListener($eventName, $listener); 282 $this->dispatcher->removeListener($eventName, $listener);
270 $this->dispatcher->addListener($eventName, $listener->getWrappedListener(), $priority); 283 $this->dispatcher->addListener($eventName, $listener->getWrappedListener(), $priority);
271 284
272 if (null !== $this->logger) { 285 if (null !== $this->logger) {
273 $context = array('event' => $eventName, 'listener' => $listener->getPretty()); 286 $context = ['event' => $eventName, 'listener' => $listener->getPretty()];
274 } 287 }
275 288
276 if ($listener->wasCalled()) { 289 if ($listener->wasCalled()) {
277 if (null !== $this->logger) { 290 if (null !== $this->logger) {
278 $this->logger->debug('Notified event "{event}" to listener "{listener}".', $context); 291 $this->logger->debug('Notified event "{event}" to listener "{listener}".', $context);
279 } 292 }
280 293
281 if (!isset($this->called[$eventName])) { 294 if (!isset($this->called[$eventName])) {
282 $this->called[$eventName] = new \SplObjectStorage(); 295 $this->called[$eventName] = new \SplObjectStorage();
283 } 296 }
284 297 } else {
285 $this->called[$eventName]->attach($listener); 298 $this->callStack->detach($listener);
286 } 299 }
287 300
288 if (null !== $this->logger && $skipped) { 301 if (null !== $this->logger && $skipped) {
289 $this->logger->debug('Listener "{listener}" was not called for event "{event}".', $context); 302 $this->logger->debug('Listener "{listener}" was not called for event "{event}".', $context);
290 } 303 }
297 $skipped = true; 310 $skipped = true;
298 } 311 }
299 } 312 }
300 } 313 }
301 314
302 private function sortListenersByPriority($a, $b) 315 private function sortNotCalledListeners(array $a, array $b)
303 { 316 {
304 if (is_int($a['priority']) && !is_int($b['priority'])) { 317 if (0 !== $cmp = strcmp($a['event'], $b['event'])) {
318 return $cmp;
319 }
320
321 if (\is_int($a['priority']) && !\is_int($b['priority'])) {
305 return 1; 322 return 1;
306 } 323 }
307 324
308 if (!is_int($a['priority']) && is_int($b['priority'])) { 325 if (!\is_int($a['priority']) && \is_int($b['priority'])) {
309 return -1; 326 return -1;
310 } 327 }
311 328
312 if ($a['priority'] === $b['priority']) { 329 if ($a['priority'] === $b['priority']) {
313 return 0; 330 return 0;