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 12namespace Symfony\Component\HttpKernel\Debug; 13 14use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher as BaseTraceableEventDispatcher; 15use Symfony\Component\HttpKernel\KernelEvents; 16 17/** 18 * Collects some data about event listeners. 19 * 20 * This event dispatcher delegates the dispatching to another one. 21 * 22 * @author Fabien Potencier <fabien@symfony.com> 23 */ 24class TraceableEventDispatcher extends BaseTraceableEventDispatcher 25{ 26 /** 27 * {@inheritdoc} 28 */ 29 protected function beforeDispatch(string $eventName, $event) 30 { 31 switch ($eventName) { 32 case KernelEvents::REQUEST: 33 $this->stopwatch->openSection(); 34 break; 35 case KernelEvents::VIEW: 36 case KernelEvents::RESPONSE: 37 // stop only if a controller has been executed 38 if ($this->stopwatch->isStarted('controller')) { 39 $this->stopwatch->stop('controller'); 40 } 41 break; 42 case KernelEvents::TERMINATE: 43 $token = $event->getResponse()->headers->get('X-Debug-Token'); 44 if (null === $token) { 45 break; 46 } 47 // There is a very special case when using built-in AppCache class as kernel wrapper, in the case 48 // of an ESI request leading to a `stale` response [B] inside a `fresh` cached response [A]. 49 // In this case, `$token` contains the [B] debug token, but the open `stopwatch` section ID 50 // is equal to the [A] debug token. Trying to reopen section with the [B] token throws an exception 51 // which must be caught. 52 try { 53 $this->stopwatch->openSection($token); 54 } catch (\LogicException $e) { 55 } 56 break; 57 } 58 } 59 60 /** 61 * {@inheritdoc} 62 */ 63 protected function afterDispatch(string $eventName, $event) 64 { 65 switch ($eventName) { 66 case KernelEvents::CONTROLLER_ARGUMENTS: 67 $this->stopwatch->start('controller', 'section'); 68 break; 69 case KernelEvents::RESPONSE: 70 $token = $event->getResponse()->headers->get('X-Debug-Token'); 71 if (null === $token) { 72 break; 73 } 74 $this->stopwatch->stopSection($token); 75 break; 76 case KernelEvents::TERMINATE: 77 // In the special case described in the `preDispatch` method above, the `$token` section 78 // does not exist, then closing it throws an exception which must be caught. 79 $token = $event->getResponse()->headers->get('X-Debug-Token'); 80 if (null === $token) { 81 break; 82 } 83 try { 84 $this->stopwatch->stopSection($token); 85 } catch (\LogicException $e) { 86 } 87 break; 88 } 89 } 90} 91