vendor/codefog/contao-haste/src/EventListener/AjaxReloadListener.php line 66

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Codefog\HasteBundle\EventListener;
  4. use Codefog\HasteBundle\AjaxReloadManager;
  5. use Contao\ContentModel;
  6. use Contao\CoreBundle\DependencyInjection\Attribute\AsHook;
  7. use Contao\CoreBundle\Routing\ScopeMatcher;
  8. use Contao\ModuleModel;
  9. use Symfony\Component\Asset\Packages;
  10. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpFoundation\RequestStack;
  13. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  14. class AjaxReloadListener implements EventSubscriberInterface
  15. {
  16. public function __construct(
  17. private readonly AjaxReloadManager $manager,
  18. private readonly Packages $packages,
  19. private readonly RequestStack $requestStack,
  20. private readonly ScopeMatcher $scopeMatcher,
  21. ) {
  22. }
  23. #[AsHook('getContentElement')]
  24. public function onGetContentElement(ContentModel $model, string $buffer): string
  25. {
  26. // Subscribe the content element if the included frontend module has subscribed itself
  27. if ('module' === $model->type && $this->manager->isRegistered(AjaxReloadManager::TYPE_MODULE, (int) $model->module)) {
  28. $this->manager->subscribe(AjaxReloadManager::TYPE_CONTENT, (int) $model->id, $this->manager->getEvents(AjaxReloadManager::TYPE_MODULE, (int) $model->module));
  29. }
  30. // Subscribe the content element if the included content element has subscribed itself
  31. if ('alias' === $model->type && $this->manager->isRegistered(AjaxReloadManager::TYPE_CONTENT, (int) $model->cteAlias)) {
  32. $this->manager->subscribe(AjaxReloadManager::TYPE_CONTENT, (int) $model->id, $this->manager->getEvents(AjaxReloadManager::TYPE_CONTENT, (int) $model->cteAlias));
  33. }
  34. $event = $this->getEventFromCurrentRequest();
  35. $isAjax = null !== $event;
  36. $buffer = $this->manager->updateBuffer(AjaxReloadManager::TYPE_CONTENT, (int) $model->id, $buffer, $isAjax);
  37. if ($isAjax) {
  38. $this->manager->storeBuffer(AjaxReloadManager::TYPE_CONTENT, (int) $model->id, $event, $buffer);
  39. }
  40. return $buffer;
  41. }
  42. #[AsHook('getFrontendModule')]
  43. public function onGetFrontendModule(ModuleModel $model, string $buffer): string
  44. {
  45. $event = $this->getEventFromCurrentRequest();
  46. $isAjax = null !== $event;
  47. $buffer = $this->manager->updateBuffer(AjaxReloadManager::TYPE_MODULE, (int) $model->id, $buffer, $isAjax);
  48. if ($isAjax) {
  49. $this->manager->storeBuffer(AjaxReloadManager::TYPE_MODULE, (int) $model->id, $event, $buffer);
  50. }
  51. return $buffer;
  52. }
  53. public function onResponse(ResponseEvent $event): void
  54. {
  55. if (!$this->scopeMatcher->isFrontendMainRequest($event)) {
  56. return;
  57. }
  58. $request = $event->getRequest();
  59. // Only handle GET requests
  60. if (!$request->isMethod(Request::METHOD_GET)) {
  61. return;
  62. }
  63. $response = $event->getResponse();
  64. // Only handle text/html responses
  65. if (!str_starts_with((string) $response->headers->get('Content-Type', ''), 'text/html')) {
  66. return;
  67. }
  68. // Modify the regular response
  69. if ($this->manager->hasListeners() && !$request->headers->has('Haste-Ajax-Reload')) {
  70. // Vary on the header, so we don't have the same URL cached
  71. $response->headers->set('Vary', 'Haste-Ajax-Reload', false);
  72. // Add the necessary <script> tags
  73. $response->setContent(str_replace(
  74. '</body>',
  75. \sprintf('<script src="%s"></script></body>', $this->packages->getUrl('ajax-reload.js', 'codefog_haste')),
  76. $response->getContent(),
  77. ));
  78. return;
  79. }
  80. // Return the requested buffers in an ajax response
  81. if ($request->headers->has('Haste-Ajax-Reload') && ($buffers = $this->manager->getBuffers()) !== []) {
  82. $response->setContent(json_encode($buffers));
  83. $response->headers->set('Content-Type', 'application/json');
  84. }
  85. }
  86. public static function getSubscribedEvents(): array
  87. {
  88. return [
  89. ResponseEvent::class => 'onResponse',
  90. ];
  91. }
  92. /**
  93. * Get the event from the current request.
  94. */
  95. private function getEventFromCurrentRequest(): string|null
  96. {
  97. $request = $this->requestStack->getCurrentRequest();
  98. if (null === $request || !$request->isXmlHttpRequest() || !$request->server->has('HTTP_HASTE_AJAX_RELOAD')) {
  99. return null;
  100. }
  101. return $request->server->get('HTTP_HASTE_AJAX_RELOAD');
  102. }
  103. }