No Description

TraceableEventDispatcher.php 3.4KB

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