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

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