Spaces:
No application file
No application file
| declare(strict_types=1); | |
| namespace MauticPlugin\GrapesJsBuilderBundle\Controller; | |
| use Mautic\CoreBundle\Controller\CommonController; | |
| use Mautic\CoreBundle\Helper\EmojiHelper; | |
| use Mautic\CoreBundle\Helper\InputHelper; | |
| use Mautic\CoreBundle\Helper\ThemeHelper; | |
| use Mautic\CoreBundle\Twig\Helper\AssetsHelper; | |
| use Mautic\CoreBundle\Twig\Helper\SlotsHelper; | |
| use Mautic\EmailBundle\Entity\Email; | |
| use Mautic\PageBundle\Entity\Page; | |
| use Psr\Log\LoggerInterface; | |
| use Symfony\Component\Form\FormFactoryInterface; | |
| use Symfony\Component\HttpFoundation\Request; | |
| use Symfony\Component\HttpFoundation\Response; | |
| class GrapesJsController extends CommonController | |
| { | |
| public const OBJECT_TYPE = ['email', 'page']; | |
| /** | |
| * Activate the custom builder. | |
| * | |
| * @param string $objectType | |
| * @param int $objectId | |
| * | |
| * @return Response | |
| */ | |
| public function builderAction( | |
| Request $request, | |
| LoggerInterface $mauticLogger, | |
| ThemeHelper $themeHelper, | |
| SlotsHelper $slotsHelper, | |
| AssetsHelper $assetsHelper, | |
| FormFactoryInterface $formFactory, | |
| $objectType, | |
| $objectId | |
| ) { | |
| if (!in_array($objectType, self::OBJECT_TYPE)) { | |
| throw new \Exception('Object not authorized to load custom builder', Response::HTTP_CONFLICT); | |
| } | |
| /** @var \Mautic\EmailBundle\Model\EmailModel|\Mautic\PageBundle\Model\PageModel $model */ | |
| $model = $this->getModel($objectType); | |
| $aclToCheck = 'email:emails:'; | |
| if ('page' === $objectType) { | |
| $aclToCheck = 'page:pages:'; | |
| } | |
| // permission check | |
| if (str_contains((string) $objectId, 'new')) { | |
| $isNew = true; | |
| if (!$this->security->isGranted($aclToCheck.'create')) { | |
| return $this->accessDenied(); | |
| } | |
| /** @var Email|Page $entity */ | |
| $entity = $model->getEntity(); | |
| $entity->setSessionId($objectId); | |
| } else { | |
| /** @var Email|Page $entity */ | |
| $entity = $model->getEntity($objectId); | |
| $isNew = false; | |
| if (null == $entity | |
| || !$this->security->hasEntityAccess( | |
| $aclToCheck.'viewown', | |
| $aclToCheck.'viewother', | |
| $entity->getCreatedBy() | |
| ) | |
| ) { | |
| return $this->accessDenied(); | |
| } | |
| } | |
| $slots = []; | |
| $type = 'html'; | |
| $template = InputHelper::clean($request->query->get('template')); | |
| if (!$template) { | |
| $mauticLogger->warning('Grapesjs: no template in query'); | |
| return $this->json(false); | |
| } | |
| $templateName = '@themes/'.$template.'/html/'.$objectType; | |
| $content = $entity->getContent(); | |
| // Check for MJML template | |
| // @deprecated - use mjml directly in email.html.twig | |
| if ($logicalName = $this->checkForMjmlTemplate($templateName.'.mjml.twig')) { | |
| $type = 'mjml'; | |
| } else { | |
| $logicalName = $themeHelper->checkForTwigTemplate($templateName.'.html.twig'); | |
| $slots = $themeHelper->getTheme($template)->getSlots($objectType); | |
| // merge any existing changes | |
| $newContent = $request->getSession()->get('mautic.'.$objectType.'builder.'.$objectId.'.content', []); | |
| if (is_array($newContent)) { | |
| $content = array_merge($content, $newContent); | |
| // Update the content for processSlots | |
| $entity->setContent($content); | |
| } | |
| if ('page' === $objectType) { | |
| $this->processPageSlots($assetsHelper, $slotsHelper, $formFactory, $slots, $entity); | |
| } else { | |
| $this->processEmailSlots($slotsHelper, $slots, $entity); | |
| } | |
| } | |
| // Replace short codes to emoji | |
| $content = array_map(fn ($text) => EmojiHelper::toEmoji($text, 'short'), $content); | |
| $renderedTemplate = $this->renderView( | |
| $logicalName, | |
| [ | |
| 'isNew' => $isNew, | |
| 'slots' => $slots, | |
| 'content' => $content, | |
| $objectType => $entity, | |
| 'template' => $template, | |
| 'basePath' => $request->getBasePath(), | |
| ] | |
| ); | |
| if (str_contains($renderedTemplate, '<mjml>')) { | |
| $type = 'mjml'; | |
| } | |
| $renderedTemplateHtml = ('html' === $type) ? $renderedTemplate : ''; | |
| $renderedTemplateMjml = ('mjml' === $type) ? $renderedTemplate : ''; | |
| return $this->render( | |
| '@GrapesJsBuilder/Builder/template.html.twig', | |
| [ | |
| 'templateHtml' => $renderedTemplateHtml, | |
| 'templateMjml' => $renderedTemplateMjml, | |
| ] | |
| ); | |
| } | |
| /** | |
| * PreProcess email slots for public view. | |
| * | |
| * @param array $slots | |
| * @param Email $entity | |
| */ | |
| private function processEmailSlots(SlotsHelper $slotsHelper, $slots, $entity): void | |
| { | |
| $content = $entity->getContent(); | |
| // Set the slots | |
| foreach ($slots as $slot => $slotConfig) { | |
| // support previous format where email slots are not defined with config array | |
| if (is_numeric($slot)) { | |
| $slot = $slotConfig; | |
| $slotConfig = []; | |
| } | |
| $value = $content[$slot] ?? ''; | |
| $slotsHelper->set($slot, "<div data-slot=\"text\" id=\"slot-{$slot}\">{$value}</div>"); | |
| } | |
| // add builder toolbar | |
| $slotsHelper->start('builder'); | |
| <input type="hidden" id="builder_entity_id" value="<?php echo $entity->getSessionId(); ?>"/> | |
| $slotsHelper->stop(); | |
| } | |
| /** | |
| * PreProcess page slots for public view. | |
| * | |
| * @param array $slots | |
| * @param Page $entity | |
| */ | |
| private function processPageSlots(AssetsHelper $assetsHelper, SlotsHelper $slotsHelper, FormFactoryInterface $formFactory, $slots, $entity): void | |
| { | |
| $slotsHelper->inBuilder(true); | |
| $content = $entity->getContent(); | |
| foreach ($slots as $slot => $slotConfig) { | |
| // backward compatibility - if slotConfig array does not exist | |
| if (is_numeric($slot)) { | |
| $slot = $slotConfig; | |
| $slotConfig = []; | |
| } | |
| // define default config if does not exist | |
| if (!isset($slotConfig['type'])) { | |
| $slotConfig['type'] = 'html'; | |
| } | |
| if (!isset($slotConfig['placeholder'])) { | |
| $slotConfig['placeholder'] = 'mautic.page.builder.addcontent'; | |
| } | |
| $value = $content[$slot] ?? ''; | |
| if ('slideshow' == $slotConfig['type']) { | |
| if (isset($content[$slot])) { | |
| $options = json_decode($content[$slot], true); | |
| } else { | |
| $options = [ | |
| 'width' => '100%', | |
| 'height' => '250px', | |
| 'background_color' => 'transparent', | |
| 'arrow_navigation' => false, | |
| 'dot_navigation' => true, | |
| 'interval' => 5000, | |
| 'pause' => 'hover', | |
| 'wrap' => true, | |
| 'keyboard' => true, | |
| ]; | |
| } | |
| // Create sample slides for first time or if all slides were deleted | |
| if (empty($options['slides'])) { | |
| $options['slides'] = [ | |
| [ | |
| 'order' => 0, | |
| 'background-image' => $assetsHelper->getOverridableUrl('images/mautic_logo_lb200.png'), | |
| 'captionheader' => 'Caption 1', | |
| ], | |
| [ | |
| 'order' => 1, | |
| 'background-image' => $assetsHelper->getOverridableUrl('images/mautic_logo_db200.png'), | |
| 'captionheader' => 'Caption 2', | |
| ], | |
| ]; | |
| } | |
| // Order slides | |
| usort( | |
| $options['slides'], | |
| fn ($a, $b): int => strcmp($a['order'], $b['order']) | |
| ); | |
| $options['slot'] = $slot; | |
| $options['public'] = false; | |
| // create config form | |
| $options['configForm'] = $formFactory->createNamedBuilder( | |
| '', | |
| 'slideshow_config', | |
| [], | |
| ['data' => $options] | |
| )->getForm()->createView(); | |
| // create slide config forms | |
| foreach ($options['slides'] as $key => &$slide) { | |
| $slide['key'] = $key; | |
| $slide['slot'] = $slot; | |
| $slide['form'] = $formFactory->createNamedBuilder( | |
| '', | |
| 'slideshow_slide_config', | |
| [], | |
| ['data' => $slide] | |
| )->getForm()->createView(); | |
| } | |
| } else { | |
| $slotsHelper->set($slot, "<div data-slot=\"text\" id=\"slot-{$slot}\">{$value}</div>"); | |
| } | |
| } | |
| $slotsHelper->start('builder'); | |
| <input type="hidden" id="builder_entity_id" value="<?php echo $entity->getSessionId(); ?>"/> | |
| $slotsHelper->stop(); | |
| } | |
| /** | |
| * @deprecated deprecated since version 5.0 - use mjml directly in email.html.twig | |
| */ | |
| private function checkForMjmlTemplate($template) | |
| { | |
| $twig = $this->get('twig'); | |
| if ($twig->getLoader()->exists($template)) { | |
| return $template; | |
| } | |
| return null; | |
| } | |
| } | |