/**
  * Render a complete message.
  *
  * @param Message $message
  *
  * @param Layout  $layout
  *
  * @return PreRenderedMessageTemplateInterface
  * @throws \Exception
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  * @SuppressWarnings(PHPMD.NPathComplexity)
  * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
  * @SuppressWarnings(PHPMD.Superglobals)
  * @SuppressWarnings(PHPMD.LongVariables)
  */
 public function renderMessage(Message $message, Layout $layout = null)
 {
     if (!$layout || $layout->getType() != 'mailChimp') {
         return null;
     }
     try {
         $libxmlUseInternalErrors = libxml_use_internal_errors(true);
         /** @var EventDispatcher $eventDispatcher */
         $eventDispatcher = $GLOBALS['container']['event-dispatcher'];
         $environment = \Environment::getInstance();
         list($templateGroup, $templateName) = explode(':', $layout->getMailchimpTemplate());
         if (!isset($GLOBALS['AVISOTA_MAILCHIMP_TEMPLATE'][$templateGroup][$templateName])) {
             throw new \RuntimeException('Mailchimp blueprint ' . $templateGroup . '/' . $templateName . ' was not found!');
         }
         $blueprint = $GLOBALS['AVISOTA_MAILCHIMP_TEMPLATE'][$templateGroup][$templateName];
         $cells = $blueprint['cells'];
         /** @var array[]|\ArrayObject[] $cellContents */
         $cellContents = array();
         foreach ($cells as $cellName => $cellConfig) {
             if (isset($cellConfig['content'])) {
                 $cellContents[$cellName] = array($cellConfig['content']);
             } else {
                 $cellContents[$cellName] = $this->renderCell($message, $cellName, $layout);
             }
         }
         $template = file_get_contents(TL_ROOT . '/' . $blueprint['template']);
         $template = str_replace('mc:', 'mc__', $template);
         $template = mb_convert_encoding($template, 'HTML-ENTITIES', 'UTF-8');
         $document = new \DOMDocument('1.0', 'UTF-8');
         $document->formatOutput = true;
         $document->loadHTML($template);
         $xpath = new \DOMXPath($document);
         if ($layout->getClearStyles()) {
             $styles = $xpath->query('/html/head/style');
             for ($i = 0; $i < $styles->length; $i++) {
                 $style = $styles->item($i);
                 $style->parentNode->removeChild($style);
             }
         }
         $clearedCells = array();
         foreach ($cells as $cellName => $cellConfig) {
             $replace = isset($cellConfig['replace']) && $cellConfig['replace'];
             // remove empty nodes
             if (is_array($cellContents[$cellName]) && !count(array_filter($cellContents[$cellName])) || $cellContents[$cellName] instanceof \ArrayObject && $cellContents[$cellName]->count() == 0) {
                 if (isset($cellConfig['ifEmptyRemove'])) {
                     $expression = $cellConfig['ifEmptyRemove'];
                 } else {
                     if (isset($cellConfig['xpath'])) {
                         $expression = $cellConfig['xpath'];
                     } else {
                         throw new \RuntimeException(sprintf('The cell "%s" does not have a valid selector', $cellName));
                     }
                 }
                 $nodes = $xpath->query(str_replace('mc:', 'mc__', $expression), $document->documentElement);
                 if (!$nodes->length) {
                     throw new \RuntimeException('Node "' . $expression . '" not found in ' . $blueprint['template']);
                 }
                 for ($i = 0; $i < $nodes->length; $i++) {
                     $node = $nodes->item(0);
                     $node->parentNode->removeChild($node);
                 }
             } else {
                 if (!empty($cellContents[$cellName])) {
                     /** @var StringBuilder $cellContentRow */
                     foreach ($cellContents[$cellName] as $index => $cellContentRow) {
                         $cellContentRow = mb_convert_encoding($cellContentRow, 'HTML-ENTITIES', 'UTF-8');
                         $cellContentRowDoc = new \DOMDocument('1.0', 'UTF-8');
                         $cellContentRowDoc->loadHTML('<html><body>' . $cellContentRow . '</body></html>');
                         if (isset($cellConfig['wrapRow'])) {
                             $cellConfig['wrapRow'] = mb_convert_encoding($cellConfig['wrapRow'], 'HTML-ENTITIES', 'UTF-8');
                             $wrapRowDoc = new \DOMDocument('1.0', 'UTF-8');
                             $wrapRowDoc->loadHTML('<html><body>' . $cellConfig['wrapRow'] . '</body></html>');
                             $wrapElement = $wrapRowDoc->documentElement;
                             while ($wrapElement->firstChild) {
                                 $wrapElement = $wrapElement->firstChild;
                             }
                             $length = $cellContentRowDoc->documentElement->firstChild->childNodes->length;
                             for ($i = 0; $i < $length; $i++) {
                                 $childNode = $cellContentRowDoc->documentElement->firstChild->childNodes->item($i);
                                 $childNode = $wrapRowDoc->importNode($childNode, true);
                                 $wrapElement->appendChild($childNode);
                             }
                             $cellContentRowDoc = $wrapRowDoc;
                         }
                         $cellContents[$cellName][$index] = $cellContentRowDoc;
                     }
                     $cellContentDoc = new \DOMDocument('1.0', 'UTF-8');
                     $cellContentDoc->appendChild($cellContentDoc->createElement('html'));
                     $cellContentDoc->documentElement->appendChild($cellContentDoc->createElement('body'));
                     foreach ($cellContents[$cellName] as $cellContentRowDoc) {
                         $length = $cellContentRowDoc->documentElement->firstChild->childNodes->length;
                         for ($i = 0; $i < $length; $i++) {
                             $childNode = $cellContentRowDoc->documentElement->firstChild->childNodes->item($i);
                             $childNode = $cellContentDoc->importNode($childNode, true);
                             $cellContentDoc->documentElement->firstChild->appendChild($childNode);
                         }
                     }
                     if (isset($cellConfig['wrapContent'])) {
                         $cellConfig['wrapContent'] = mb_convert_encoding($cellConfig['wrapContent'], 'HTML-ENTITIES', 'UTF-8');
                         $wrapContentDoc = new \DOMDocument('1.0', 'UTF-8');
                         $wrapContentDoc->loadHTML('<html><body>' . $cellConfig['wrapContent'] . '</body></html>');
                         $wrapElement = $wrapContentDoc->documentElement;
                         while ($wrapElement->firstChild) {
                             $wrapElement = $wrapElement->firstChild;
                         }
                         for ($i = 0; $i < $cellContentDoc->documentElement->firstChild->childNodes->length; $i++) {
                             $childNode = $cellContentDoc->documentElement->firstChild->childNodes->item($i);
                             $childNode = $wrapContentDoc->importNode($childNode, true);
                             $wrapElement->appendChild($childNode);
                         }
                         $cellContentDoc = $wrapContentDoc;
                     }
                     $expression = $cellConfig['xpath'];
                     if (empty($expression)) {
                         throw new \RuntimeException(sprintf('The cell "%s" does not have a valid selector', $cellName));
                     }
                     $targetNodes = $xpath->query(str_replace('mc:', 'mc__', $expression), $document->documentElement);
                     if (!$targetNodes->length) {
                         throw new \RuntimeException('Node "' . $expression . '" not found in ' . $blueprint['template']);
                     }
                     for ($i = 0; $i < $targetNodes->length; $i++) {
                         $targetNode = $targetNodes->item($i);
                         if ($targetNode->nodeType == XML_ATTRIBUTE_NODE) {
                             $cellContent = $cellContentDoc->saveHTML();
                             $cellContent = trim($cellContent);
                             $cellContent = preg_replace('#^<html><body>#', '', $cellContent);
                             $cellContent = preg_replace('#</body></html>$#', '', $cellContent);
                             /** @var \DOMAttr $targetNode */
                             $targetNode->value = $cellContent;
                         } else {
                             // if not replace, empty target node
                             if (!$replace) {
                                 if (!in_array($cellName . '__' . $i, $clearedCells)) {
                                     while ($targetNode->childNodes->length) {
                                         $childNode = $targetNode->childNodes->item(0);
                                         $targetNode->removeChild($childNode);
                                     }
                                     $clearedCells[] = $cellName . '__' . $i;
                                 }
                             }
                             $length = $cellContentDoc->documentElement->firstChild->childNodes->length;
                             for ($j = 0; $j < $length; $j++) {
                                 $childNode = $cellContentDoc->documentElement->firstChild->childNodes->item($j);
                                 $childNode = $document->importNode($childNode, true);
                                 // if replace, insert before target node
                                 if ($replace) {
                                     $targetNode->parentNode->insertBefore($childNode, $targetNode);
                                 } else {
                                     $targetNode->appendChild($childNode);
                                 }
                             }
                             // if replace it, remove the target node
                             if ($replace) {
                                 $targetNode->parentNode->removeChild($targetNode);
                             }
                         }
                     }
                 }
             }
         }
         $headers = new \ArrayObject();
         $styles = new StringBuilder();
         $stylesheets = $layout->getStylesheetPaths();
         foreach ($stylesheets as $stylesheet) {
             $file = new \File($stylesheet);
             $css = $file->getContent();
             $styles->append($css)->append("\n");
         }
         $styles->trim();
         if ($styles->length()) {
             $styles->insert(0, " <style> {% raw %} \n");
             $styles->append("\n {% endraw %} </style> ");
             $headers['styles'] = $styles;
         }
         $eventDispatcher->dispatch(AvisotaMessageEvents::RENDER_MESSAGE_HEADERS, new RenderMessageHeadersEvent($this, $message, $headers));
         $headElements = $xpath->query('/html/head', $document->documentElement);
         $headElement = $headElements->item(0);
         $headerCode = trim(implode("\n", $headers->getArrayCopy()));
         if ($headerCode) {
             $headerCode = mb_convert_encoding($headerCode, 'HTML-ENTITIES', 'UTF-8');
             $headerDoc = new \DOMDocument('1.0', 'UTF-8');
             $headerDoc->loadHTML('<html><head>' . $headerCode . '</head></html>');
             for ($i = 0; $i < $headerDoc->documentElement->firstChild->childNodes->length; $i++) {
                 $childNode = $headerDoc->documentElement->firstChild->childNodes->item($i);
                 $childNode = $document->importNode($childNode, true);
                 $headElement->appendChild($childNode);
             }
         }
         $html = $document->saveHTML();
         $html = str_replace(array('%5B', '%5D', '%7B', '%7D', '%20'), array('[', ']', '{', '}', ' '), $html);
         $html = preg_replace_callback('~\\{%.*%\\}~U', function ($matches) {
             return html_entity_decode($matches[0], ENT_QUOTES, 'UTF-8');
         }, $html);
         $html = preg_replace_callback('~##.*##~U', function ($matches) {
             return html_entity_decode($matches[0], ENT_QUOTES, 'UTF-8');
         }, $html);
         $replaceInsertTags = new ReplaceInsertTagsEvent($html, false);
         $eventDispatcher->dispatch(ContaoEvents::CONTROLLER_REPLACE_INSERT_TAGS, $replaceInsertTags);
         $html = $replaceInsertTags->getBuffer();
         $document->loadHTML($html);
         $xpath = new \DOMXPath($document);
         $baseUrl = $environment->base;
         $links = $xpath->query('//@href|//@src');
         for ($i = 0; $i < $links->length; $i++) {
             /** @var \DOMAttr $link */
             $link = $links->item($i);
             if (!preg_match('~(^\\w+:|^#[^#]|##)~', $link->value)) {
                 $link->value = $baseUrl . $link->value;
             }
         }
         $html = $document->saveHTML();
         $html = str_replace(array('%5B', '%5D', '%7B', '%7D', '%20'), array('[', ']', '{', '}', ' '), $html);
         $html = preg_replace_callback('~\\{%.*%\\}~U', function ($matches) {
             return html_entity_decode($matches[0], ENT_QUOTES, 'UTF-8');
         }, $html);
         $html = preg_replace_callback('~##.*##~U', function ($matches) {
             return html_entity_decode($matches[0], ENT_QUOTES, 'UTF-8');
         }, $html);
         $response = new MutablePreRenderedMessageTemplate($message, $html, standardize($message->getSubject()) . '.html', 'text/html', 'utf-8');
         libxml_use_internal_errors($libxmlUseInternalErrors);
         return $response;
     } catch (\Exception $exception) {
         libxml_use_internal_errors($libxmlUseInternalErrors);
         throw $exception;
     }
 }
Пример #2
0
 public function testLength()
 {
     $this->assertEquals(14, $this->stringBuilder->length());
     $this->stringBuilder->changeEncoding('ISO-8859-1');
     $this->assertEquals(14, $this->stringBuilder->length());
 }