vendor/contao/core-bundle/src/EventListener/PreviewToolbarListener.php line 64

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of Contao.
  5.  *
  6.  * (c) Leo Feyer
  7.  *
  8.  * @license LGPL-3.0-or-later
  9.  */
  10. namespace Contao\CoreBundle\EventListener;
  11. use Contao\CoreBundle\Routing\ScopeMatcher;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  15. use Symfony\Component\Routing\RouterInterface;
  16. use Twig\Environment as TwigEnvironment;
  17. use Twig\Error\Error as TwigError;
  18. /**
  19.  * Injects the back end preview toolbar on any response within the /preview.php
  20.  * entry point.
  21.  *
  22.  * The onKernelResponse method must be connected to the kernel.response event.
  23.  *
  24.  * The toolbar is only injected on well-formed HTML with a proper </body> tag,
  25.  * so is never included in sub-requests or ESI requests.
  26.  *
  27.  * @internal
  28.  */
  29. class PreviewToolbarListener
  30. {
  31.     /**
  32.      * @var ScopeMatcher
  33.      */
  34.     private $scopeMatcher;
  35.     /**
  36.      * @var TwigEnvironment
  37.      */
  38.     private $twig;
  39.     /**
  40.      * @var RouterInterface
  41.      */
  42.     private $router;
  43.     /**
  44.      * @var string
  45.      */
  46.     private $previewScript;
  47.     public function __construct(ScopeMatcher $scopeMatcherTwigEnvironment $twigRouterInterface $routerstring $previewScript '')
  48.     {
  49.         $this->scopeMatcher $scopeMatcher;
  50.         $this->twig $twig;
  51.         $this->router $router;
  52.         $this->previewScript $previewScript;
  53.     }
  54.     public function __invoke(ResponseEvent $event): void
  55.     {
  56.         if ($this->scopeMatcher->isBackendMasterRequest($event)) {
  57.             return;
  58.         }
  59.         $request $event->getRequest();
  60.         $response $event->getResponse();
  61.         // Do not capture redirects, errors, or modify XML HTTP Requests
  62.         if (
  63.             !$request->attributes->get('_preview'false)
  64.             || $request->isXmlHttpRequest()
  65.             || !($response->isSuccessful() || $response->isClientError())
  66.         ) {
  67.             return;
  68.         }
  69.         // Only inject the toolbar into HTML responses
  70.         if (
  71.             'html' !== $request->getRequestFormat()
  72.             || false === strpos((string) $response->headers->get('Content-Type'), 'text/html')
  73.             || false !== stripos((string) $response->headers->get('Content-Disposition'), 'attachment;')
  74.         ) {
  75.             return;
  76.         }
  77.         $this->injectToolbar($response$request);
  78.     }
  79.     /**
  80.      * @throws TwigError
  81.      */
  82.     private function injectToolbar(Response $responseRequest $request): void
  83.     {
  84.         $content $response->getContent();
  85.         $pos strripos($content'</body>');
  86.         if (false === $pos) {
  87.             return;
  88.         }
  89.         $toolbar $this->twig->render(
  90.             '@ContaoCore/Frontend/preview_toolbar_base_js.html.twig',
  91.             [
  92.                 'action' => $this->router->generate('contao_backend_switch'),
  93.                 'request' => $request,
  94.                 'preview_script' => $this->previewScript,
  95.             ]
  96.         );
  97.         $response->setContent(substr($content0$pos)."\n".$toolbar."\n".substr($content$pos));
  98.     }
  99. }