vendor/pimcore/pimcore/bundles/CoreBundle/EventListener/Frontend/EditmodeListener.php line 97

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Enterprise License (PEL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  * @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  * @license    http://www.pimcore.org/license     GPLv3 and PEL
  13.  */
  14. namespace Pimcore\Bundle\CoreBundle\EventListener\Frontend;
  15. use Pimcore\Bundle\AdminBundle\Security\User\UserLoader;
  16. use Pimcore\Bundle\CoreBundle\EventListener\Traits\PimcoreContextAwareTrait;
  17. use Pimcore\Config;
  18. use Pimcore\Extension\Bundle\PimcoreBundleManager;
  19. use Pimcore\Http\Request\Resolver\DocumentResolver;
  20. use Pimcore\Http\Request\Resolver\EditmodeResolver;
  21. use Pimcore\Http\Request\Resolver\PimcoreContextResolver;
  22. use Pimcore\Model\Document;
  23. use Pimcore\Version;
  24. use Psr\Log\LoggerAwareTrait;
  25. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  26. use Symfony\Component\HttpFoundation\Response;
  27. use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
  28. use Symfony\Component\HttpKernel\Event\GetResponseEvent;
  29. use Symfony\Component\HttpKernel\KernelEvents;
  30. /**
  31.  * Modifies responses for editmode
  32.  */
  33. class EditmodeListener implements EventSubscriberInterface
  34. {
  35.     use LoggerAwareTrait;
  36.     use PimcoreContextAwareTrait;
  37.     /**
  38.      * @var EditmodeResolver
  39.      */
  40.     protected $editmodeResolver;
  41.     /**
  42.      * @var DocumentResolver
  43.      */
  44.     protected $documentResolver;
  45.     /**
  46.      * @var UserLoader
  47.      */
  48.     protected $userLoader;
  49.     /**
  50.      * @var PimcoreBundleManager
  51.      */
  52.     protected $bundleManager;
  53.     /**
  54.      * @var array
  55.      */
  56.     protected $contentTypes = [
  57.         'text/html'
  58.     ];
  59.     /**
  60.      * @param EditmodeResolver $editmodeResolver
  61.      * @param DocumentResolver $documentResolver
  62.      * @param UserLoader $userLoader
  63.      * @param PimcoreBundleManager $bundleManager
  64.      */
  65.     public function __construct(
  66.         EditmodeResolver $editmodeResolver,
  67.         DocumentResolver $documentResolver,
  68.         UserLoader $userLoader,
  69.         PimcoreBundleManager $bundleManager
  70.     ) {
  71.         $this->editmodeResolver $editmodeResolver;
  72.         $this->documentResolver $documentResolver;
  73.         $this->userLoader $userLoader;
  74.         $this->bundleManager $bundleManager;
  75.     }
  76.     /**
  77.      * @inheritdoc
  78.      */
  79.     public static function getSubscribedEvents()
  80.     {
  81.         return [
  82.             KernelEvents::REQUEST => 'onKernelRequest',
  83.             KernelEvents::RESPONSE => 'onKernelResponse'
  84.         ];
  85.     }
  86.     public function onKernelRequest(GetResponseEvent $event)
  87.     {
  88.         $request $event->getRequest();
  89.         if (!$event->isMasterRequest()) {
  90.             return; // only resolve editmode in frontend
  91.         }
  92.         if (!$this->matchesPimcoreContext($requestPimcoreContextResolver::CONTEXT_DEFAULT)) {
  93.             return;
  94.         }
  95.         // trigger this once to make sure it is resolved properly
  96.         // TODO is this needed?
  97.         $this->editmodeResolver->isEditmode($request);
  98.     }
  99.     public function onKernelResponse(FilterResponseEvent $event)
  100.     {
  101.         $request $event->getRequest();
  102.         $response $event->getResponse();
  103.         if (!$event->isMasterRequest()) {
  104.             return; // only master requests inject editmode assets
  105.         }
  106.         if (!$this->matchesPimcoreContext($requestPimcoreContextResolver::CONTEXT_DEFAULT)) {
  107.             return;
  108.         }
  109.         if (!$this->editmodeResolver->isEditmode($request)) {
  110.             return;
  111.         }
  112.         if (!$this->contentTypeMatches($response)) {
  113.             return;
  114.         }
  115.         $document $this->documentResolver->getDocument($request);
  116.         if (!$document) {
  117.             return;
  118.         }
  119.         $this->logger->info('Injecting editmode assets into request {request}', [
  120.             'request' => $request->getPathInfo()
  121.         ]);
  122.         $this->addEditmodeAssets($document$response);
  123.         // set sameorigin header for editmode responses
  124.         $response->headers->set('X-Frame-Options''SAMEORIGIN'true);
  125.     }
  126.     /**
  127.      * @param Response $response
  128.      *
  129.      * @return bool
  130.      */
  131.     protected function contentTypeMatches(Response $response)
  132.     {
  133.         $contentType $response->headers->get('Content-Type');
  134.         if (!$contentType) {
  135.             return true;
  136.         }
  137.         // check for substring as the content type could define attributes (e.g. charset)
  138.         foreach ($this->contentTypes as $ct) {
  139.             if (false !== strpos($contentType$ct)) {
  140.                 return true;
  141.             }
  142.         }
  143.         return false;
  144.     }
  145.     /**
  146.      * Inject editmode assets into response HTML
  147.      *
  148.      * @param Document $document
  149.      * @param Response $response
  150.      */
  151.     protected function addEditmodeAssets(Document $documentResponse $response)
  152.     {
  153.         if (Document\Service::isValidType($document->getType())) {
  154.             $html $response->getContent();
  155.             if (!$html) {
  156.                 return;
  157.             }
  158.             $user $this->userLoader->getUser();
  159.             $htmlElement preg_match('/<html[^a-zA-Z]?( [^>]+)?>/'$html);
  160.             $headElement preg_match('/<head[^a-zA-Z]?( [^>]+)?>/'$html);
  161.             $bodyElement preg_match('/<body[^a-zA-Z]?( [^>]+)?>/'$html);
  162.             $skipCheck false;
  163.             // if there's no head and no body, create a wrapper including these elements
  164.             // add html headers for snippets in editmode, so there is no problem with javascript
  165.             if (!$headElement && !$bodyElement && !$htmlElement) {
  166.                 $html "<!DOCTYPE html>\n<html>\n<head></head><body>" $html '</body></html>';
  167.                 $skipCheck true;
  168.             }
  169.             if ($skipCheck || ($headElement && $bodyElement && $htmlElement)) {
  170.                 $startupJavascript '/bundles/pimcoreadmin/js/pimcore/document/edit/startup.js';
  171.                 $headHtml $this->buildHeadHtml($document$user->getLanguage());
  172.                 $bodyHtml "\n\n" '<script src="' $startupJavascript '?_dc=' Version::getRevision() . '"></script>' "\n\n";
  173.                 $html preg_replace('@</head>@i'$headHtml "\n\n</head>"$html1);
  174.                 $html preg_replace('@</body>@i'$bodyHtml "\n\n</body>"$html1);
  175.                 $response->setContent($html);
  176.             } else {
  177.                 $response->setContent('<div style="font-size:30px; font-family: Arial; font-weight:bold; color:red; text-align: center; margin: 40px 0">You have to define a &lt;html&gt;, &lt;head&gt;, &lt;body&gt;<br />HTML-tag in your view/layout markup!</div>');
  178.             }
  179.         }
  180.     }
  181.     /**
  182.      * @param Document $document
  183.      * @param string $language
  184.      *
  185.      * @return string
  186.      */
  187.     protected function buildHeadHtml(Document $document$language)
  188.     {
  189.         $config Config::getSystemConfig();
  190.         $libraries $this->getEditmodeLibraries();
  191.         $scripts $this->getEditmodeScripts();
  192.         $stylesheets $this->getEditmodeStylesheets();
  193.         $headHtml "\n\n\n<!-- pimcore editmode -->\n";
  194.         $headHtml .= '<meta name="google" value="notranslate">';
  195.         $headHtml .= "\n\n";
  196.         // include stylesheets
  197.         foreach ($stylesheets as $stylesheet) {
  198.             $headHtml .= '<link rel="stylesheet" type="text/css" href="' $stylesheet '?_dc=' Version::getRevision() . '" />';
  199.             $headHtml .= "\n";
  200.         }
  201.         $headHtml .= "\n\n";
  202.         // include script libraries
  203.         foreach ($libraries as $script) {
  204.             $headHtml .= '<script src="' $script '?_dc=' Version::getRevision() . '"></script>';
  205.             $headHtml .= "\n";
  206.         }
  207.         // combine the pimcore scripts in non-devmode
  208.         if (\Pimcore::disableMinifyJs()) {
  209.             foreach ($scripts as $script) {
  210.                 $headHtml .= '<script src="' $script '?_dc=' Version::getRevision() . '"></script>';
  211.                 $headHtml .= "\n";
  212.             }
  213.         } else {
  214.             $scriptContents '';
  215.             foreach ($scripts as $scriptUrl) {
  216.                 $scriptContents .= file_get_contents(PIMCORE_WEB_ROOT $scriptUrl) . "\n\n\n";
  217.             }
  218.             $headHtml .= '<script src="' . \Pimcore\Tool\Admin::getMinimizedScriptPath($scriptContents) . '"></script>' "\n";
  219.         }
  220.         $headHtml .= '<script src="/admin/misc/json-translations-system?language=' $language '&_dc=' Version::getRevision() . '"></script>' "\n";
  221.         $headHtml .= "\n\n";
  222.         // set var for editable configurations which is filled by Document\Tag::admin()
  223.         $headHtml .= '<script>
  224.             var editableConfigurations = new Array();
  225.             var pimcore_document_id = ' $document->getId() . ';
  226.         </script>';
  227.         $headHtml .= "\n\n<!-- /pimcore editmode -->\n\n\n";
  228.         return $headHtml;
  229.     }
  230.     /**
  231.      * @return array
  232.      */
  233.     protected function getEditmodeLibraries()
  234.     {
  235.         $disableMinifyJs = \Pimcore::disableMinifyJs();
  236.         return [
  237.             '/bundles/pimcoreadmin/js/pimcore/common.js',
  238.             '/bundles/pimcoreadmin/js/lib/class.js',
  239.             '/bundles/pimcoreadmin/js/lib/ext/ext-all' . ($disableMinifyJs '-debug' '') . '.js',
  240.             '/bundles/pimcoreadmin/js/lib/ckeditor/ckeditor.js'
  241.         ];
  242.     }
  243.     /**
  244.      * @return array
  245.      */
  246.     protected function getEditmodeScripts()
  247.     {
  248.         return array_merge(
  249.             [
  250.                 '/bundles/pimcoreadmin/js/pimcore/functions.js',
  251.                 '/bundles/pimcoreadmin/js/pimcore/overrides.js',
  252.                 '/bundles/pimcoreadmin/js/pimcore/tool/milestoneslider.js',
  253.                 '/bundles/pimcoreadmin/js/pimcore/element/tag/imagehotspotmarkereditor.js',
  254.                 '/bundles/pimcoreadmin/js/pimcore/element/tag/imagecropper.js',
  255.                 '/bundles/pimcoreadmin/js/pimcore/document/edit/helper.js',
  256.                 '/bundles/pimcoreadmin/js/pimcore/elementservice.js',
  257.                 '/bundles/pimcoreadmin/js/pimcore/document/edit/dnd.js',
  258.                 '/bundles/pimcoreadmin/js/pimcore/document/tag.js',
  259.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/block.js',
  260.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/scheduledblock.js',
  261.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/date.js',
  262.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/relation.js',
  263.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/relations.js',
  264.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/checkbox.js',
  265.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/image.js',
  266.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/input.js',
  267.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/link.js',
  268.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/select.js',
  269.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/snippet.js',
  270.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/textarea.js',
  271.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/numeric.js',
  272.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/wysiwyg.js',
  273.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/renderlet.js',
  274.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/table.js',
  275.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/video.js',
  276.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/multiselect.js',
  277.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/areablock.js',
  278.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/area.js',
  279.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/pdf.js',
  280.                 '/bundles/pimcoreadmin/js/pimcore/document/tags/embed.js',
  281.                 '/bundles/pimcoreadmin/js/pimcore/document/edit/helper.js'
  282.             ],
  283.             $this->bundleManager->getEditmodeJsPaths()
  284.         );
  285.     }
  286.     /**
  287.      * @return array
  288.      */
  289.     protected function getEditmodeStylesheets()
  290.     {
  291.         return array_merge(
  292.             [
  293.                 '/bundles/pimcoreadmin/css/icons.css',
  294.                 '/bundles/pimcoreadmin/css/editmode.css?_dc=' time()
  295.             ],
  296.             $this->bundleManager->getEditmodeCssPaths()
  297.         );
  298.     }
  299. }