vendor/symfony/http-kernel/EventListener/ProfilerListener.php line 99

  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\HttpKernel\EventListener;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpFoundation\RequestMatcherInterface;
  14. use Symfony\Component\HttpFoundation\RequestStack;
  15. use Symfony\Component\HttpFoundation\Session\Session;
  16. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  17. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  18. use Symfony\Component\HttpKernel\Event\TerminateEvent;
  19. use Symfony\Component\HttpKernel\KernelEvents;
  20. use Symfony\Component\HttpKernel\Profiler\Profile;
  21. use Symfony\Component\HttpKernel\Profiler\Profiler;
  22. /**
  23.  * ProfilerListener collects data for the current request by listening to the kernel events.
  24.  *
  25.  * @author Fabien Potencier <fabien@symfony.com>
  26.  *
  27.  * @final
  28.  */
  29. class ProfilerListener implements EventSubscriberInterface
  30. {
  31.     private Profiler $profiler;
  32.     private ?RequestMatcherInterface $matcher;
  33.     private bool $onlyException;
  34.     private bool $onlyMainRequests;
  35.     private ?\Throwable $exception null;
  36.     /** @var \SplObjectStorage<Request, Profile> */
  37.     private \SplObjectStorage $profiles;
  38.     private RequestStack $requestStack;
  39.     private ?string $collectParameter;
  40.     /** @var \SplObjectStorage<Request, Request|null> */
  41.     private \SplObjectStorage $parents;
  42.     /**
  43.      * @param bool $onlyException    True if the profiler only collects data when an exception occurs, false otherwise
  44.      * @param bool $onlyMainRequests True if the profiler only collects data when the request is the main request, false otherwise
  45.      */
  46.     public function __construct(Profiler $profilerRequestStack $requestStackRequestMatcherInterface $matcher nullbool $onlyException falsebool $onlyMainRequests falsestring $collectParameter null)
  47.     {
  48.         $this->profiler $profiler;
  49.         $this->matcher $matcher;
  50.         $this->onlyException $onlyException;
  51.         $this->onlyMainRequests $onlyMainRequests;
  52.         $this->profiles = new \SplObjectStorage();
  53.         $this->parents = new \SplObjectStorage();
  54.         $this->requestStack $requestStack;
  55.         $this->collectParameter $collectParameter;
  56.     }
  57.     /**
  58.      * Handles the onKernelException event.
  59.      */
  60.     public function onKernelException(ExceptionEvent $event): void
  61.     {
  62.         if ($this->onlyMainRequests && !$event->isMainRequest()) {
  63.             return;
  64.         }
  65.         $this->exception $event->getThrowable();
  66.     }
  67.     /**
  68.      * Handles the onKernelResponse event.
  69.      */
  70.     public function onKernelResponse(ResponseEvent $event): void
  71.     {
  72.         if ($this->onlyMainRequests && !$event->isMainRequest()) {
  73.             return;
  74.         }
  75.         if ($this->onlyException && null === $this->exception) {
  76.             return;
  77.         }
  78.         $request $event->getRequest();
  79.         if (null !== $this->collectParameter && null !== $collectParameterValue $request->get($this->collectParameter)) {
  80.             true === $collectParameterValue || filter_var($collectParameterValue\FILTER_VALIDATE_BOOL) ? $this->profiler->enable() : $this->profiler->disable();
  81.         }
  82.         $exception $this->exception;
  83.         $this->exception null;
  84.         if (null !== $this->matcher && !$this->matcher->matches($request)) {
  85.             return;
  86.         }
  87.         $session $request->hasPreviousSession() ? $request->getSession() : null;
  88.         if ($session instanceof Session) {
  89.             $usageIndexValue $usageIndexReference = &$session->getUsageIndex();
  90.             $usageIndexReference \PHP_INT_MIN;
  91.         }
  92.         try {
  93.             if (!$profile $this->profiler->collect($request$event->getResponse(), $exception)) {
  94.                 return;
  95.             }
  96.         } finally {
  97.             if ($session instanceof Session) {
  98.                 $usageIndexReference $usageIndexValue;
  99.             }
  100.         }
  101.         $this->profiles[$request] = $profile;
  102.         $this->parents[$request] = $this->requestStack->getParentRequest();
  103.     }
  104.     public function onKernelTerminate(TerminateEvent $event): void
  105.     {
  106.         // attach children to parents
  107.         foreach ($this->profiles as $request) {
  108.             if (null !== $parentRequest $this->parents[$request]) {
  109.                 if (isset($this->profiles[$parentRequest])) {
  110.                     $this->profiles[$parentRequest]->addChild($this->profiles[$request]);
  111.                 }
  112.             }
  113.         }
  114.         // save profiles
  115.         foreach ($this->profiles as $request) {
  116.             $this->profiler->saveProfile($this->profiles[$request]);
  117.         }
  118.         $this->profiles = new \SplObjectStorage();
  119.         $this->parents = new \SplObjectStorage();
  120.     }
  121.     public static function getSubscribedEvents(): array
  122.     {
  123.         return [
  124.             KernelEvents::RESPONSE => ['onKernelResponse', -100],
  125.             KernelEvents::EXCEPTION => ['onKernelException'0],
  126.             KernelEvents::TERMINATE => ['onKernelTerminate', -1024],
  127.         ];
  128.     }
  129. }