[TASK] Moved marker substitution functionality to own class 81/41381/7
authorBenjamin Mack <benni@typo3.org>
Wed, 15 Jul 2015 22:37:05 +0000 (00:37 +0200)
committerBenni Mack <benni@typo3.org>
Wed, 26 Aug 2015 08:21:47 +0000 (10:21 +0200)
The marker substitution functionality has been moved from
core/Classes/Html/HtmlParser.php to own class
core/Classes/Utility/MarkerUtility.php

The following methods within HtmlParser have been marked as deprecated.

* HtmlParser::getSubpart()
* HtmlParser::substituteSubpart()
* HtmlParser::substituteSubpartArray()
* HtmlParser::substituteMarker()
* HtmlParser::substituteMarkerArray()
* HtmlParser::substituteMarkerAndSubpartArrayRecursive()

Resolves: #69262
Releases: master
Change-Id: Ia0ffb3715b3ecef9739db4f6aad53bae9c224b90
Reviewed-on: http://review.typo3.org/41381
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
15 files changed:
typo3/sysext/backend/Classes/Controller/EditDocumentController.php
typo3/sysext/backend/Classes/Form/FormEngine.php
typo3/sysext/backend/Classes/Sprite/SpriteGenerator.php
typo3/sysext/backend/Classes/Template/DocumentTemplate.php
typo3/sysext/core/Classes/Html/HtmlParser.php
typo3/sysext/core/Classes/Messaging/AbstractStandaloneMessage.php
typo3/sysext/core/Classes/Page/PageRenderer.php
typo3/sysext/core/Classes/Utility/MarkerUtility.php [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Deprecation-69262-MoveMarkerSubstitutionFunctionalityToOwnClass.rst [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Html/HtmlParserTest.php
typo3/sysext/core/Tests/Unit/Utility/MarkerUtilityTest.php [new file with mode: 0644]
typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
typo3/sysext/linkvalidator/Classes/Report/LinkValidatorReport.php
typo3/sysext/linkvalidator/Classes/Task/ValidatorTask.php
typo3/sysext/version/Classes/Hook/DataHandlerHook.php

index b80c8c6..edbf419 100644 (file)
@@ -21,17 +21,16 @@ use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
-use TYPO3\CMS\Core\Html\HtmlParser;
 use TYPO3\CMS\Core\Http\Response;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageService;
 use TYPO3\CMS\Core\Page\PageRenderer;
-use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\HttpUtility;
+use TYPO3\CMS\Core\Utility\MarkerUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Frontend\Page\PageRepository;
@@ -1233,8 +1232,8 @@ class EditDocumentController implements \TYPO3\CMS\Core\Http\ControllerInterface
        public function extraFormHeaders() {
                $extraTemplate = '';
                if (is_array($this->tceforms->extraFormHeaders)) {
-                       $extraTemplate = HtmlParser::getSubpart($this->doc->moduleTemplate, '###DOCHEADER_EXTRAHEADER###');
-                       $extraTemplate = HtmlParser::substituteMarker($extraTemplate, '###EXTRAHEADER###', implode(LF, $this->tceforms->extraFormHeaders));
+                       $extraTemplate = MarkerUtility::getSubpart($this->doc->moduleTemplate, '###DOCHEADER_EXTRAHEADER###');
+                       $extraTemplate = MarkerUtility::substituteMarker($extraTemplate, '###EXTRAHEADER###', implode(LF, $this->tceforms->extraFormHeaders));
                }
                return $extraTemplate;
        }
index ce34d96..baf625b 100644 (file)
@@ -27,6 +27,7 @@ use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\MarkerUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Lang\LanguageService;
 
@@ -233,7 +234,7 @@ class FormEngine {
                $this->templateFile = 'sysext/backend/Resources/Private/Templates/FormEngine.html';
                $template = GeneralUtility::getUrl(PATH_typo3 . $this->templateFile);
                // Wrapping all table rows for a particular record being edited:
-               $this->totalWrap = HtmlParser::getSubpart($template, '###TOTALWRAP###');
+               $this->totalWrap = MarkerUtility::getSubpart($template, '###TOTALWRAP###');
                $this->nodeFactory = GeneralUtility::makeInstance(NodeFactory::class);
        }
 
index 110bda8..125b731 100644 (file)
@@ -14,7 +14,7 @@ namespace TYPO3\CMS\Backend\Sprite;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Core\Html\HtmlParser;
+use TYPO3\CMS\Core\Utility\MarkerUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -335,7 +335,7 @@ class SpriteGenerator {
                $markerArray['###SPRITEURL###'] .= $this->spriteName . '.png' . $timestamp;
                foreach ($this->spriteBases as $base) {
                        $markerArray['###SPRITENAME###'] = $base;
-                       $cssData .= HtmlParser::substituteMarkerArray($this->templateSprite, $markerArray);
+                       $cssData .= MarkerUtility::substituteMarkerArray($this->templateSprite, $markerArray);
 
                        if ($this->enableHighDensitySprite) {
                                $highDensityMarkerArray = array_merge($markerArray, array(
@@ -347,7 +347,7 @@ class SpriteGenerator {
                                                $markerArray['###SPRITEURL###']
                                        )
                                ));
-                               $cssData .= HtmlParser::substituteMarkerArray($this->templateSpriteHighDensity, $highDensityMarkerArray);
+                               $cssData .= MarkerUtility::substituteMarkerArray($this->templateSpriteHighDensity, $highDensityMarkerArray);
                        }
                }
 
@@ -368,7 +368,7 @@ class SpriteGenerator {
                        if ($data['width'] != $this->defaultWidth) {
                                $markerArrayIcons['###SIZE_INFO###'] .= TAB . 'width: ' . $data['width'] . 'px;' . LF;
                        }
-                       $cssData .= HtmlParser::substituteMarkerArray($this->templateIcon, $markerArrayIcons);
+                       $cssData .= MarkerUtility::substituteMarkerArray($this->templateIcon, $markerArrayIcons);
                }
                GeneralUtility::writeFile(PATH_site . $this->cssFolder . $this->spriteName . '.css', $cssData);
        }
index e97762c..e38cc66 100644 (file)
@@ -17,7 +17,7 @@ namespace TYPO3\CMS\Backend\Template;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
-use TYPO3\CMS\Core\Html\HtmlParser;
+use TYPO3\CMS\Core\Utility\MarkerUtility;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Page\PageRenderer;
@@ -1692,7 +1692,7 @@ function jumpToUrl(URL) {
         */
        public function moduleBody($pageRecord = array(), $buttons = array(), $markerArray = array(), $subpartArray = array()) {
                // Get the HTML template for the module
-               $moduleBody = HtmlParser::getSubpart($this->moduleTemplate, '###FULLDOC###');
+               $moduleBody = MarkerUtility::getSubpart($this->moduleTemplate, '###FULLDOC###');
                // Add CSS
                $this->inDocStylesArray[] = 'html { overflow: hidden; }';
                // Get the page path for the docheader
@@ -1705,7 +1705,7 @@ function jumpToUrl(URL) {
                $markerArray = array_merge($markerArray, $docHeaderButtons);
                // replacing subparts
                foreach ($subpartArray as $marker => $content) {
-                       $moduleBody = HtmlParser::substituteSubpart($moduleBody, $marker, $content);
+                       $moduleBody = MarkerUtility::substituteSubpart($moduleBody, $marker, $content);
                }
                // adding flash messages
                if ($this->showFlashMessages) {
@@ -1733,7 +1733,7 @@ function jumpToUrl(URL) {
                        }
                }
                // Replacing all markers with the finished markers and return the HTML content
-               return HtmlParser::substituteMarkerArray($moduleBody, $markerArray, '###|###');
+               return MarkerUtility::substituteMarkerArray($moduleBody, $markerArray, '###|###');
        }
 
        /**
@@ -1773,20 +1773,20 @@ function jumpToUrl(URL) {
                $floats = array('left', 'right');
                foreach ($floats as $key) {
                        // Get the template for each float
-                       $buttonTemplate = HtmlParser::getSubpart($this->moduleTemplate, '###BUTTON_GROUPS_' . strtoupper($key) . '###');
+                       $buttonTemplate = MarkerUtility::getSubpart($this->moduleTemplate, '###BUTTON_GROUPS_' . strtoupper($key) . '###');
                        // Fill the button markers in this float
-                       $buttonTemplate = HtmlParser::substituteMarkerArray($buttonTemplate, $buttons, '###|###', TRUE);
+                       $buttonTemplate = MarkerUtility::substituteMarkerArray($buttonTemplate, $buttons, '###|###', TRUE);
                        // getting the wrap for each group
-                       $buttonWrap = HtmlParser::getSubpart($this->moduleTemplate, '###BUTTON_GROUP_WRAP###');
+                       $buttonWrap = MarkerUtility::getSubpart($this->moduleTemplate, '###BUTTON_GROUP_WRAP###');
                        // looping through the groups (max 6) and remove the empty groups
                        for ($groupNumber = 1; $groupNumber < 6; $groupNumber++) {
                                $buttonMarker = '###BUTTON_GROUP' . $groupNumber . '###';
-                               $buttonGroup = HtmlParser::getSubpart($buttonTemplate, $buttonMarker);
+                               $buttonGroup = MarkerUtility::getSubpart($buttonTemplate, $buttonMarker);
                                if (trim($buttonGroup)) {
                                        if ($buttonWrap) {
-                                               $buttonGroup = HtmlParser::substituteMarker($buttonWrap, '###BUTTONS###', $buttonGroup);
+                                               $buttonGroup = MarkerUtility::substituteMarker($buttonWrap, '###BUTTONS###', $buttonGroup);
                                        }
-                                       $buttonTemplate = HtmlParser::substituteSubpart($buttonTemplate, $buttonMarker, trim($buttonGroup));
+                                       $buttonTemplate = MarkerUtility::substituteSubpart($buttonTemplate, $buttonMarker, trim($buttonGroup));
                                }
                        }
                        // Replace the marker with the template and remove all line breaks (for IE compat)
index 770b81f..092051a 100644 (file)
@@ -15,6 +15,8 @@ namespace TYPO3\CMS\Core\Html;
  */
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\MarkerUtility;
+
 
 /**
  * Functions for parsing HTML.
@@ -36,36 +38,13 @@ class HtmlParser {
         *
         * @param string $content Content with subpart wrapped in fx. "###CONTENT_PART###" inside.
         * @param string $marker Marker string, eg. "###CONTENT_PART###
+        *
         * @return string
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the corresponding method in MarkerUtility accordingly
         */
        static public function getSubpart($content, $marker) {
-               $start = strpos($content, $marker);
-               if ($start === FALSE) {
-                       return '';
-               }
-               $start += strlen($marker);
-               $stop = strpos($content, $marker, $start);
-               // Q: What shall get returned if no stop marker is given
-               // Everything till the end or nothing?
-               if ($stop === FALSE) {
-                       return '';
-               }
-               $content = substr($content, $start, $stop - $start);
-               $matches = array();
-               if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $content, $matches) === 1) {
-                       return $matches[2];
-               }
-               // Resetting $matches
-               $matches = array();
-               if (preg_match('/(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $content, $matches) === 1) {
-                       return $matches[1];
-               }
-               // Resetting $matches
-               $matches = array();
-               if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)$/s', $content, $matches) === 1) {
-                       return $matches[2];
-               }
-               return $content;
+               GeneralUtility::logDeprecatedFunction();
+               return MarkerUtility::getSubpart($content, $marker);
        }
 
        /**
@@ -76,70 +55,13 @@ class HtmlParser {
         * @param array $subpartContent If $subpartContent happens to be an array, it's [0] and [1] elements are wrapped around the content of the subpart (fetched by getSubpart())
         * @param bool $recursive If $recursive is set, the function calls itself with the content set to the remaining part of the content after the second marker. This means that proceding subparts are ALSO substituted!
         * @param bool $keepMarker If set, the marker around the subpart is not removed, but kept in the output
+        *
         * @return string Processed input content
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the corresponding method in MarkerUtility accordingly
         */
        static public function substituteSubpart($content, $marker, $subpartContent, $recursive = TRUE, $keepMarker = FALSE) {
-               $start = strpos($content, $marker);
-               if ($start === FALSE) {
-                       return $content;
-               }
-               $startAM = $start + strlen($marker);
-               $stop = strpos($content, $marker, $startAM);
-               if ($stop === FALSE) {
-                       return $content;
-               }
-               $stopAM = $stop + strlen($marker);
-               $before = substr($content, 0, $start);
-               $after = substr($content, $stopAM);
-               $between = substr($content, $startAM, $stop - $startAM);
-               if ($recursive) {
-                       $after = self::substituteSubpart($after, $marker, $subpartContent, $recursive, $keepMarker);
-               }
-               if ($keepMarker) {
-                       $matches = array();
-                       if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
-                               $before .= $marker . $matches[1];
-                               $between = $matches[2];
-                               $after = $matches[3] . $marker . $after;
-                       } elseif (preg_match('/^(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
-                               $before .= $marker;
-                               $between = $matches[1];
-                               $after = $matches[2] . $marker . $after;
-                       } elseif (preg_match('/^([^\\<]*\\-\\-\\>)(.*)$/s', $between, $matches) === 1) {
-                               $before .= $marker . $matches[1];
-                               $between = $matches[2];
-                               $after = $marker . $after;
-                       } else {
-                               $before .= $marker;
-                               $after = $marker . $after;
-                       }
-               } else {
-                       $matches = array();
-                       if (preg_match('/^(.*)\\<\\!\\-\\-[^\\>]*$/s', $before, $matches) === 1) {
-                               $before = $matches[1];
-                       }
-                       if (is_array($subpartContent)) {
-                               $matches = array();
-                               if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
-                                       $between = $matches[2];
-                               } elseif (preg_match('/^(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
-                                       $between = $matches[1];
-                               } elseif (preg_match('/^([^\\<]*\\-\\-\\>)(.*)$/s', $between, $matches) === 1) {
-                                       $between = $matches[2];
-                               }
-                       }
-                       $matches = array();
-                       // resetting $matches
-                       if (preg_match('/^[^\\<]*\\-\\-\\>(.*)$/s', $after, $matches) === 1) {
-                               $after = $matches[1];
-                       }
-               }
-               if (is_array($subpartContent)) {
-                       $between = $subpartContent[0] . $between . $subpartContent[1];
-               } else {
-                       $between = $subpartContent;
-               }
-               return $before . $between . $after;
+               GeneralUtility::logDeprecatedFunction();
+               return MarkerUtility::substituteSubpart($content, $marker, $subpartContent, $recursive, $keepMarker);
        }
 
        /**
@@ -147,13 +69,13 @@ class HtmlParser {
         *
         * @param string $content The content stream, typically HTML template content.
         * @param array $subpartsContent The array of key/value pairs being subpart/content values used in the substitution. For each element in this array the function will substitute a subpart in the content stream with the content.
+        *
         * @return string The processed HTML content string.
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the corresponding method in MarkerUtility accordingly
         */
        static public function substituteSubpartArray($content, array $subpartsContent) {
-               foreach ($subpartsContent as $subpartMarker => $subpartContent) {
-                       $content = self::substituteSubpart($content, $subpartMarker, $subpartContent);
-               }
-               return $content;
+               GeneralUtility::logDeprecatedFunction();
+               return MarkerUtility::substituteSubpartArray($content, $subpartsContent);
        }
 
        /**
@@ -163,11 +85,13 @@ class HtmlParser {
         * @param string $content The content stream, typically HTML template content.
         * @param string $marker The marker string, typically on the form "###[the marker string]###
         * @param mixed $markContent The content to insert instead of the marker string found.
+        *
         * @return string The processed HTML content string.
-        * @see substituteSubpart()
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the corresponding method in MarkerUtility accordingly
         */
        static public function substituteMarker($content, $marker, $markContent) {
-               return str_replace($marker, $markContent, $content);
+               GeneralUtility::logDeprecatedFunction();
+               return MarkerUtility::substituteMarker($content, $marker, $markContent);
        }
 
        /**
@@ -185,35 +109,13 @@ class HtmlParser {
         * @param string $wrap A wrap value - [part 1] | [part 2] - for the markers before substitution
         * @param bool $uppercase If set, all marker string substitution is done with upper-case markers.
         * @param bool $deleteUnused If set, all unused marker are deleted.
+        *
         * @return string The processed output stream
-        * @see substituteMarker(), substituteMarkerInObject(), TEMPLATE()
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the corresponding method in MarkerUtility accordingly
         */
        static public function substituteMarkerArray($content, $markContentArray, $wrap = '', $uppercase = FALSE, $deleteUnused = FALSE) {
-               if (is_array($markContentArray)) {
-                       $wrapArr = GeneralUtility::trimExplode('|', $wrap);
-                       $search = array();
-                       $replace = array();
-                       foreach ($markContentArray as $marker => $markContent) {
-                               if ($uppercase) {
-                                       // use strtr instead of strtoupper to avoid locale problems with Turkish
-                                       $marker = strtr($marker, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
-                               }
-                               if (!empty($wrapArr)) {
-                                       $marker = $wrapArr[0] . $marker . $wrapArr[1];
-                               }
-                               $search[] = $marker;
-                               $replace[] = $markContent;
-                       }
-                       $content = str_replace($search, $replace, $content);
-                       unset($search, $replace);
-                       if ($deleteUnused) {
-                               if (empty($wrap)) {
-                                       $wrapArr = array('###', '###');
-                               }
-                               $content = preg_replace('/' . preg_quote($wrapArr[0], '/') . '([A-Z0-9_|\\-]*)' . preg_quote($wrapArr[1], '/') . '/is', '', $content);
-                       }
-               }
-               return $content;
+               GeneralUtility::logDeprecatedFunction();
+               return MarkerUtility::substituteMarkerArray($content, $markContentArray, $wrap, $uppercase, $deleteUnused);
        }
 
        /**
@@ -227,78 +129,36 @@ class HtmlParser {
         * markers.
         *
         * $markersAndSubparts = array (
-        *      '###SINGLEMARKER1###' => 'value 1',
-        *      '###SUBPARTMARKER1###' => array(
-        *              0 => array(
-        *                      '###SINGLEMARKER2###' => 'value 2',
-        *              ),
-        *              1 => array(
-        *                      '###SINGLEMARKER2###' => 'value 3',
-        *              )
-        *      ),
-        *      '###SUBPARTMARKER2###' => array(
-        *      ),
+        *    '###SINGLEMARKER1###' => 'value 1',
+        *    '###SUBPARTMARKER1###' => array(
+        *        0 => array(
+        *            '###SINGLEMARKER2###' => 'value 2',
+        *        ),
+        *        1 => array(
+        *            '###SINGLEMARKER2###' => 'value 3',
+        *        )
+        *    ),
+        *    '###SUBPARTMARKER2###' => array(
+        *    ),
         * )
         * Subparts can be nested, so below the 'SINGLEMARKER2' it is possible to have another subpart marker with an array as the
         * value, which in its turn contains the elements of the sub-subparts.
         * Empty arrays for Subparts will cause the subtemplate to be cleared.
         *
         * @static
+        *
         * @param string $content The content stream, typically HTML template content.
         * @param array $markersAndSubparts The array of single markers and subpart contents.
         * @param string $wrap A wrap value - [part1] | [part2] - for the markers before substitution.
         * @param bool $uppercase If set, all marker string substitution is done with upper-case markers.
         * @param bool $deleteUnused If set, all unused single markers are deleted.
+        *
         * @return string The processed output stream
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the corresponding method in MarkerUtility accordingly
         */
        static public function substituteMarkerAndSubpartArrayRecursive($content, array $markersAndSubparts, $wrap = '', $uppercase = FALSE, $deleteUnused = FALSE) {
-               $wraps = GeneralUtility::trimExplode('|', $wrap);
-               $singleItems = array();
-               $compoundItems = array();
-               // Split markers and subparts into separate arrays
-               foreach ($markersAndSubparts as $markerName => $markerContent) {
-                       if (is_array($markerContent)) {
-                               $compoundItems[] = $markerName;
-                       } else {
-                               $singleItems[$markerName] = $markerContent;
-                       }
-               }
-               $subTemplates = array();
-               $subpartSubstitutes = array();
-               // Build a cache for the sub template
-               foreach ($compoundItems as $subpartMarker) {
-                       if ($uppercase) {
-                               // Use strtr instead of strtoupper to avoid locale problems with Turkish
-                               $subpartMarker = strtr($subpartMarker, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
-                       }
-                       if (!empty($wraps)) {
-                               $subpartMarker = $wraps[0] . $subpartMarker . $wraps[1];
-                       }
-                       $subTemplates[$subpartMarker] = self::getSubpart($content, $subpartMarker);
-               }
-               // Replace the subpart contents recursively
-               foreach ($compoundItems as $subpartMarker) {
-                       $completeMarker = $subpartMarker;
-                       if ($uppercase) {
-                               // use strtr instead of strtoupper to avoid locale problems with Turkish
-                               $completeMarker = strtr($completeMarker, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
-                       }
-                       if (!empty($wraps)) {
-                               $completeMarker = $wraps[0] . $completeMarker . $wraps[1];
-                       }
-                       if (!empty($markersAndSubparts[$subpartMarker])) {
-                               foreach ($markersAndSubparts[$subpartMarker] as $partialMarkersAndSubparts) {
-                                       $subpartSubstitutes[$completeMarker] .= self::substituteMarkerAndSubpartArrayRecursive($subTemplates[$completeMarker],
-                                               $partialMarkersAndSubparts, $wrap, $uppercase, $deleteUnused);
-                               }
-                       } else {
-                               $subpartSubstitutes[$completeMarker] = '';
-                       }
-               }
-               // Substitute the single markers and subparts
-               $result = self::substituteSubpartArray($content, $subpartSubstitutes);
-               $result = self::substituteMarkerArray($result, $singleItems, $wrap, $uppercase, $deleteUnused);
-               return $result;
+               GeneralUtility::logDeprecatedFunction();
+               return MarkerUtility::substituteMarkerAndSubpartArrayRecursive($content, $markersAndSubparts, $wrap, $uppercase, $deleteUnused);
        }
 
        /************************************
index fc02b23..5f02c15 100644 (file)
@@ -126,7 +126,7 @@ abstract class AbstractStandaloneMessage extends AbstractMessage {
        public function render() {
                $markers = array_merge($this->getDefaultMarkers(), $this->markers);
                $content = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($this->htmlTemplate);
-               $content = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($content, $markers, '', FALSE, TRUE);
+               $content = \TYPO3\CMS\Core\Utility\MarkerUtility::substituteMarkerArray($content, $markers, '', FALSE, TRUE);
                return $content;
        }
 
index cf91ca3..65e8b38 100644 (file)
@@ -1726,7 +1726,7 @@ class PageRenderer implements \TYPO3\CMS\Core\SingletonInterface {
                // This means that you can only register footer files *after* the header has been already rendered.
                // In case you render the footer part first, header files can only be added *after* the footer has been rendered
                $this->reset();
-               return trim(\TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($template, $markerArray, '###|###'));
+               return trim(\TYPO3\CMS\Core\Utility\MarkerUtility::substituteMarkerArray($template, $markerArray, '###|###'));
        }
 
        /**
@@ -1740,7 +1740,7 @@ class PageRenderer implements \TYPO3\CMS\Core\SingletonInterface {
                $this->prepareRendering();
                $markerArray = $this->getPreparedMarkerArrayForPageWithUncachedObjects($substituteHash);
                $template = $this->getTemplateForPart(self::PART_COMPLETE);
-               return trim(\TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($template, $markerArray, '###|###'));
+               return trim(\TYPO3\CMS\Core\Utility\MarkerUtility::substituteMarkerArray($template, $markerArray, '###|###'));
        }
 
        /**
diff --git a/typo3/sysext/core/Classes/Utility/MarkerUtility.php b/typo3/sysext/core/Classes/Utility/MarkerUtility.php
new file mode 100644 (file)
index 0000000..e3097f7
--- /dev/null
@@ -0,0 +1,307 @@
+<?php
+namespace TYPO3\CMS\Core\Utility;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Helper functionality for subparts and marker substitution
+ * ###MYMARKER###
+ */
+class MarkerUtility {
+
+       /**
+        * Returns the first subpart encapsulated in the marker, $marker
+        * (possibly present in $content as a HTML comment)
+        *
+        * @param string $content Content with subpart wrapped in fx. "###CONTENT_PART###" inside.
+        * @param string $marker Marker string, eg. "###CONTENT_PART###
+        *
+        * @return string
+        */
+       static public function getSubpart($content, $marker) {
+               $start = strpos($content, $marker);
+               if ($start === FALSE) {
+                       return '';
+               }
+               $start += strlen($marker);
+               $stop = strpos($content, $marker, $start);
+               // Q: What shall get returned if no stop marker is given
+               // Everything till the end or nothing?
+               if ($stop === FALSE) {
+                       return '';
+               }
+               $content = substr($content, $start, $stop - $start);
+               $matches = array();
+               if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $content, $matches) === 1) {
+                       return $matches[2];
+               }
+               // Resetting $matches
+               $matches = array();
+               if (preg_match('/(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $content, $matches) === 1) {
+                       return $matches[1];
+               }
+               // Resetting $matches
+               $matches = array();
+               if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)$/s', $content, $matches) === 1) {
+                       return $matches[2];
+               }
+
+               return $content;
+       }
+
+       /**
+        * Substitutes a subpart in $content with the content of $subpartContent.
+        *
+        * @param string $content Content with subpart wrapped in fx. "###CONTENT_PART###" inside.
+        * @param string $marker Marker string, eg. "###CONTENT_PART###
+        * @param array $subpartContent If $subpartContent happens to be an array, it's [0] and [1] elements are wrapped around the content of the subpart (fetched by getSubpart())
+        * @param bool $recursive If $recursive is set, the function calls itself with the content set to the remaining part of the content after the second marker. This means that proceding subparts are ALSO substituted!
+        * @param bool $keepMarker If set, the marker around the subpart is not removed, but kept in the output
+        *
+        * @return string Processed input content
+        */
+       static public function substituteSubpart($content, $marker, $subpartContent, $recursive = TRUE, $keepMarker = FALSE) {
+               $start = strpos($content, $marker);
+               if ($start === FALSE) {
+                       return $content;
+               }
+               $startAM = $start + strlen($marker);
+               $stop = strpos($content, $marker, $startAM);
+               if ($stop === FALSE) {
+                       return $content;
+               }
+               $stopAM = $stop + strlen($marker);
+               $before = substr($content, 0, $start);
+               $after = substr($content, $stopAM);
+               $between = substr($content, $startAM, $stop - $startAM);
+               if ($recursive) {
+                       $after = self::substituteSubpart($after, $marker, $subpartContent, $recursive, $keepMarker);
+               }
+               if ($keepMarker) {
+                       $matches = array();
+                       if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
+                               $before .= $marker . $matches[1];
+                               $between = $matches[2];
+                               $after = $matches[3] . $marker . $after;
+                       } elseif (preg_match('/^(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
+                               $before .= $marker;
+                               $between = $matches[1];
+                               $after = $matches[2] . $marker . $after;
+                       } elseif (preg_match('/^([^\\<]*\\-\\-\\>)(.*)$/s', $between, $matches) === 1) {
+                               $before .= $marker . $matches[1];
+                               $between = $matches[2];
+                               $after = $marker . $after;
+                       } else {
+                               $before .= $marker;
+                               $after = $marker . $after;
+                       }
+               } else {
+                       $matches = array();
+                       if (preg_match('/^(.*)\\<\\!\\-\\-[^\\>]*$/s', $before, $matches) === 1) {
+                               $before = $matches[1];
+                       }
+                       if (is_array($subpartContent)) {
+                               $matches = array();
+                               if (preg_match('/^([^\\<]*\\-\\-\\>)(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
+                                       $between = $matches[2];
+                               } elseif (preg_match('/^(.*)(\\<\\!\\-\\-[^\\>]*)$/s', $between, $matches) === 1) {
+                                       $between = $matches[1];
+                               } elseif (preg_match('/^([^\\<]*\\-\\-\\>)(.*)$/s', $between, $matches) === 1) {
+                                       $between = $matches[2];
+                               }
+                       }
+                       $matches = array();
+                       // resetting $matches
+                       if (preg_match('/^[^\\<]*\\-\\-\\>(.*)$/s', $after, $matches) === 1) {
+                               $after = $matches[1];
+                       }
+               }
+               if (is_array($subpartContent)) {
+                       $between = $subpartContent[0] . $between . $subpartContent[1];
+               } else {
+                       $between = $subpartContent;
+               }
+
+               return $before . $between . $after;
+       }
+
+       /**
+        * Substitues multiple subparts at once
+        *
+        * @param string $content The content stream, typically HTML template content.
+        * @param array $subpartsContent The array of key/value pairs being subpart/content values used in the substitution. For each element in this array the function will substitute a subpart in the content stream with the content.
+        *
+        * @return string The processed HTML content string.
+        */
+       static public function substituteSubpartArray($content, array $subpartsContent) {
+               foreach ($subpartsContent as $subpartMarker => $subpartContent) {
+                       $content = self::substituteSubpart($content, $subpartMarker, $subpartContent);
+               }
+
+               return $content;
+       }
+
+       /**
+        * Substitutes a marker string in the input content
+        * (by a simple str_replace())
+        *
+        * @param string $content The content stream, typically HTML template content.
+        * @param string $marker The marker string, typically on the form "###[the marker string]###
+        * @param mixed $markContent The content to insert instead of the marker string found.
+        *
+        * @return string The processed HTML content string.
+        * @see substituteSubpart()
+        */
+       static public function substituteMarker($content, $marker, $markContent) {
+               return str_replace($marker, $markContent, $content);
+       }
+
+       /**
+        * Traverses the input $markContentArray array and for each key the marker
+        * by the same name (possibly wrapped and in upper case) will be
+        * substituted with the keys value in the array. This is very useful if you
+        * have a data-record to substitute in some content. In particular when you
+        * use the $wrap and $uppercase values to pre-process the markers. Eg. a
+        * key name like "myfield" could effectively be represented by the marker
+        * "###MYFIELD###" if the wrap value was "###|###" and the $uppercase
+        * boolean TRUE.
+        *
+        * @param string $content The content stream, typically HTML template content.
+        * @param array $markContentArray The array of key/value pairs being marker/content values used in the substitution. For each element in this array the function will substitute a marker in the content stream with the content.
+        * @param string $wrap A wrap value - [part 1] | [part 2] - for the markers before substitution
+        * @param bool $uppercase If set, all marker string substitution is done with upper-case markers.
+        * @param bool $deleteUnused If set, all unused marker are deleted.
+        *
+        * @return string The processed output stream
+        * @see substituteMarker(), substituteMarkerInObject(), TEMPLATE()
+        */
+       static public function substituteMarkerArray($content, $markContentArray, $wrap = '', $uppercase = FALSE, $deleteUnused = FALSE) {
+               if (is_array($markContentArray)) {
+                       $wrapArr = GeneralUtility::trimExplode('|', $wrap);
+                       $search = array();
+                       $replace = array();
+                       foreach ($markContentArray as $marker => $markContent) {
+                               if ($uppercase) {
+                                       // use strtr instead of strtoupper to avoid locale problems with Turkish
+                                       $marker = strtr($marker, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
+                               }
+                               if (!empty($wrapArr)) {
+                                       $marker = $wrapArr[0] . $marker . $wrapArr[1];
+                               }
+                               $search[] = $marker;
+                               $replace[] = $markContent;
+                       }
+                       $content = str_replace($search, $replace, $content);
+                       unset($search, $replace);
+                       if ($deleteUnused) {
+                               if (empty($wrap)) {
+                                       $wrapArr = array('###', '###');
+                               }
+                               $content = preg_replace('/' . preg_quote($wrapArr[0], '/') . '([A-Z0-9_|\\-]*)' . preg_quote($wrapArr[1], '/') . '/is', '', $content);
+                       }
+               }
+
+               return $content;
+       }
+
+       /**
+        * Replaces all markers and subparts in a template with the content provided in the structured array.
+        *
+        * The array is built like the template with its markers and subparts. Keys represent the marker name and the values the
+        * content.
+        * If the value is not an array the key will be treated as a single marker.
+        * If the value is an array the key will be treated as a subpart marker.
+        * Repeated subpart contents are of course elements in the array, so every subpart value must contain an array with its
+        * markers.
+        *
+        * $markersAndSubparts = array (
+        *    '###SINGLEMARKER1###' => 'value 1',
+        *    '###SUBPARTMARKER1###' => array(
+        *        0 => array(
+        *            '###SINGLEMARKER2###' => 'value 2',
+        *        ),
+        *        1 => array(
+        *            '###SINGLEMARKER2###' => 'value 3',
+        *        )
+        *    ),
+        *    '###SUBPARTMARKER2###' => array(
+        *    ),
+        * )
+        * Subparts can be nested, so below the 'SINGLEMARKER2' it is possible to have another subpart marker with an array as the
+        * value, which in its turn contains the elements of the sub-subparts.
+        * Empty arrays for Subparts will cause the subtemplate to be cleared.
+        *
+        * @static
+        *
+        * @param string $content The content stream, typically HTML template content.
+        * @param array $markersAndSubparts The array of single markers and subpart contents.
+        * @param string $wrap A wrap value - [part1] | [part2] - for the markers before substitution.
+        * @param bool $uppercase If set, all marker string substitution is done with upper-case markers.
+        * @param bool $deleteUnused If set, all unused single markers are deleted.
+        *
+        * @return string The processed output stream
+        */
+       static public function substituteMarkerAndSubpartArrayRecursive($content, array $markersAndSubparts, $wrap = '', $uppercase = FALSE, $deleteUnused = FALSE) {
+               $wraps = GeneralUtility::trimExplode('|', $wrap);
+               $singleItems = array();
+               $compoundItems = array();
+               // Split markers and subparts into separate arrays
+               foreach ($markersAndSubparts as $markerName => $markerContent) {
+                       if (is_array($markerContent)) {
+                               $compoundItems[] = $markerName;
+                       } else {
+                               $singleItems[$markerName] = $markerContent;
+                       }
+               }
+               $subTemplates = array();
+               $subpartSubstitutes = array();
+               // Build a cache for the sub template
+               foreach ($compoundItems as $subpartMarker) {
+                       if ($uppercase) {
+                               // Use strtr instead of strtoupper to avoid locale problems with Turkish
+                               $subpartMarker = strtr($subpartMarker, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
+                       }
+                       if (!empty($wraps)) {
+                               $subpartMarker = $wraps[0] . $subpartMarker . $wraps[1];
+                       }
+                       $subTemplates[$subpartMarker] = self::getSubpart($content, $subpartMarker);
+               }
+               // Replace the subpart contents recursively
+               foreach ($compoundItems as $subpartMarker) {
+                       $completeMarker = $subpartMarker;
+                       if ($uppercase) {
+                               // use strtr instead of strtoupper to avoid locale problems with Turkish
+                               $completeMarker = strtr($completeMarker, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
+                       }
+                       if (!empty($wraps)) {
+                               $completeMarker = $wraps[0] . $completeMarker . $wraps[1];
+                       }
+                       if (!empty($markersAndSubparts[$subpartMarker])) {
+                               foreach ($markersAndSubparts[$subpartMarker] as $partialMarkersAndSubparts) {
+                                       $subpartSubstitutes[$completeMarker] .= self::substituteMarkerAndSubpartArrayRecursive($subTemplates[$completeMarker],
+                                               $partialMarkersAndSubparts, $wrap, $uppercase, $deleteUnused);
+                               }
+                       } else {
+                               $subpartSubstitutes[$completeMarker] = '';
+                       }
+               }
+               // Substitute the single markers and subparts
+               $result = self::substituteSubpartArray($content, $subpartSubstitutes);
+               $result = self::substituteMarkerArray($result, $singleItems, $wrap, $uppercase, $deleteUnused);
+
+               return $result;
+       }
+}
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-69262-MoveMarkerSubstitutionFunctionalityToOwnClass.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-69262-MoveMarkerSubstitutionFunctionalityToOwnClass.rst
new file mode 100644 (file)
index 0000000..06af2c6
--- /dev/null
@@ -0,0 +1,46 @@
+=========================================================================
+Deprecation: #69262 - Move marker substitution functionality to own class
+=========================================================================
+
+Description
+===========
+
+The marker substitution functionality has been moved from core/Classes/Html/HtmlParser.php to it's own class core/Classes/Utility/MarkerUtility.php
+
+The following methods within HtmlParser have been marked as deprecated.
+
+.. code-block:: php
+
+       HtmlParser::getSubpart()
+       HtmlParser::substituteSubpart()
+       HtmlParser::substituteSubpartArray()
+       HtmlParser::substituteMarker()
+       HtmlParser::substituteMarkerArray()
+       HtmlParser::substituteMarkerAndSubpartArrayRecursive()
+
+
+Impact
+======
+
+Any usage of these methods will throw a deprecation warning.
+
+
+Affected Installations
+======================
+
+Extensions that call these PHP methods directly.
+
+
+Migration
+=========
+
+Change the use statement from TYPO3\CMS\Core\Html\HtmlParser to TYPO3\CMS\Core\Utility\MarkerUtility and change the class name of the static function calls from HtmlParser to MarkerUtility.
+
+.. code-block:: php
+
+       MarkerUtility::getSubpart()
+       MarkerUtility::substituteSubpart()
+       MarkerUtility::substituteSubpartArray()
+       MarkerUtility::substituteMarker()
+       MarkerUtility::substituteMarkerArray()
+       MarkerUtility::substituteMarkerAndSubpartArrayRecursive()
index 8cde01d..cce5d04 100644 (file)
@@ -31,568 +31,6 @@ class HtmlParserTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        }
 
        /**
-        * Data provider for getSubpart
-        *
-        * @return array
-        */
-       public function getSubpartDataProvider() {
-               return array(
-                       'No start marker' => array(
-                               '<body>text</body>',
-                               '###SUBPART###',
-                               ''
-                       ),
-                       'No stop marker' => array(
-                               '<body>
-<!-- ###SUBPART### Start -->
-text
-</body>',
-                               '###SUBPART###',
-                               ''
-                       ),
-                       'Start and stop marker in HTML comment' => array(
-                               '<body>
-<!-- ###SUBPART### Start -->
-text
-<!-- ###SUBPART### End -->
-</body>',
-                               '###SUBPART###',
-                               '
-text
-'
-                       ),
-                       'Stop marker in HTML comment' => array(
-                               '<body>
-###SUBPART###
-text
-<!-- ###SUBPART### End -->
-</body>',
-                               '###SUBPART###',
-                               '
-text
-'
-                       ),
-                       'Start marker in HTML comment' => array(
-                               '<body>
-<!-- ###SUBPART### Start -->
-text
-###SUBPART###
-</body>',
-                               '###SUBPART###',
-                               '
-text
-'
-                       ),
-                       'Start and stop marker direct' => array(
-                               '<body>
-###SUBPART###
-text
-###SUBPART###
-</body>',
-                               '###SUBPART###',
-                               '
-text
-'
-                       ),
-               );
-       }
-
-       /**
-        * @test
-        * @param string $content
-        * @param string $marker
-        * @param string $expected
-        * @dataProvider getSubpartDataProvider
-        */
-       public function getSubpart($content, $marker, $expected) {
-               $this->assertSame($expected, HtmlParser::getSubpart($content, $marker));
-       }
-
-       /**
-        * Data provider for substituteSubpart
-        *
-        * @return array
-        */
-       public function substituteSubpartDataProvider() {
-               return array(
-                       'No start marker' => array(
-                               '<body>text</body>',
-                               '###SUBPART###',
-                               'hello',
-                               FALSE,
-                               FALSE,
-                               '<body>text</body>'
-                       ),
-                       'No stop marker' => array(
-                               '<body>
-<!-- ###SUBPART### Start -->
-text
-</body>',
-                               '###SUBPART###',
-                               'hello',
-                               FALSE,
-                               FALSE,
-                               '<body>
-<!-- ###SUBPART### Start -->
-text
-</body>',
-                       ),
-                       'Start and stop marker in HTML comment' => array(
-                               '<body>
-<!-- ###SUBPART### Start -->
-text
-<!-- ###SUBPART### End -->
-</body>',
-                               '###SUBPART###',
-                               'hello',
-                               FALSE,
-                               FALSE,
-                               '<body>
-hello
-</body>'
-                       ),
-                       'Recursive subpart' => array(
-                               '<body>
-<!-- ###SUBPART### Start -->text1<!-- ###SUBPART### End -->
-<!-- ###SUBPART### Start -->text2<!-- ###SUBPART### End -->
-</body>',
-                               '###SUBPART###',
-                               'hello',
-                               TRUE,
-                               FALSE,
-                               '<body>
-hello
-hello
-</body>'
-                       ),
-                       'Keep HTML marker' => array(
-                               '<body>
-<!-- ###SUBPART### Start -->text<!-- ###SUBPART### End -->
-</body>',
-                               '###SUBPART###',
-                               'hello',
-                               FALSE,
-                               TRUE,
-                               '<body>
-<!-- ###SUBPART### Start -->hello<!-- ###SUBPART### End -->
-</body>'
-                       ),
-                       'Keep HTML begin marker' => array(
-                               '<body>
-<!-- ###SUBPART### Start -->text###SUBPART###
-</body>',
-                               '###SUBPART###',
-                               'hello',
-                               FALSE,
-                               TRUE,
-                               '<body>
-<!-- ###SUBPART### Start -->hello###SUBPART###
-</body>'
-                       ),
-                       'Keep HTML end marker' => array(
-                               '<body>
-###SUBPART###text<!-- ###SUBPART### End -->
-</body>',
-                               '###SUBPART###',
-                               'hello',
-                               FALSE,
-                               TRUE,
-                               '<body>
-###SUBPART###hello<!-- ###SUBPART### End -->
-</body>'
-                       ),
-                       'Keep plain marker' => array(
-                               '<body>
-###SUBPART###text###SUBPART###
-</body>',
-                               '###SUBPART###',
-                               'hello',
-                               FALSE,
-                               TRUE,
-                               '<body>
-###SUBPART###hello###SUBPART###
-</body>'
-                       ),
-                       'Wrap around' => array(
-                               '<body>
-###SUBPART###text###SUBPART###
-</body>',
-                               '###SUBPART###',
-                               array('before-', '-after'),
-                               FALSE,
-                               TRUE,
-                               '<body>
-###SUBPART###before-text-after###SUBPART###
-</body>'
-                       ),
-               );
-       }
-
-       /**
-        * @test
-        * @param string $content
-        * @param string $marker
-        * @param array $subpartContent
-        * @param bool $recursive
-        * @param bool $keepMarker
-        * @param string $expected
-        * @dataProvider substituteSubpartDataProvider
-        */
-       public function substituteSubpart($content, $marker, $subpartContent, $recursive, $keepMarker, $expected) {
-               $this->assertSame($expected, HtmlParser::substituteSubpart($content, $marker, $subpartContent, $recursive, $keepMarker));
-       }
-
-       /**
-        * Data provider for substituteMarkerArray
-        */
-       public function substituteMarkerArrayDataProvider() {
-               return array(
-                       'Upper case marker' => array(
-                               'This is ###MARKER1### and this is ###MARKER2###',
-                               array('###MARKER1###' => 'marker 1',
-                                       '###MARKER2###' => 'marker 2'),
-                               '',
-                               FALSE,
-                               FALSE,
-                               'This is marker 1 and this is marker 2'
-                       ),
-                       'Lower case marker' => array(
-                               'This is ###MARKER1### and this is ###MARKER2###',
-                               array('###marker1###' => 'marker 1',
-                                       '###marker2###' => 'marker 2'),
-                               '',
-                               TRUE,
-                               FALSE,
-                               'This is marker 1 and this is marker 2'
-                       ),
-                       'Upper case marker without hash mark' => array(
-                               'This is ###MARKER1### and this is ###MARKER2###',
-                               array('MARKER1' => 'marker 1',
-                                       'MARKER2' => 'marker 2'),
-                               '###|###',
-                               FALSE,
-                               FALSE,
-                               'This is marker 1 and this is marker 2'
-                       ),
-                       'Upper case marker with another hash mark' => array(
-                               'This is *MARKER1* and this is *MARKER2*',
-                               array('MARKER1' => 'marker 1',
-                                       'MARKER2' => 'marker 2'),
-                               '*|*',
-                               FALSE,
-                               FALSE,
-                               'This is marker 1 and this is marker 2'
-                       ),
-                       'Upper case marker with unused marker' => array(
-                               'This is ###MARKER1### and this is ###MARKER2### ###UNUSED###',
-                               array('###MARKER1###' => 'marker 1',
-                                       '###MARKER2###' => 'marker 2'),
-                               '',
-                               FALSE,
-                               FALSE,
-                               'This is marker 1 and this is marker 2 ###UNUSED###'
-                       ),
-                       'Upper case marker with unused marker deleted' => array(
-                               'This is ###MARKER1### and this is ###MARKER2### ###UNUSED###',
-                               array('###MARKER1###' => 'marker 1',
-                                       '###MARKER2###' => 'marker 2'),
-                               '',
-                               FALSE,
-                               TRUE,
-                               'This is marker 1 and this is marker 2 '
-                       ),
-               );
-       }
-
-       /**
-        * @test
-        * @dataProvider substituteMarkerArrayDataProvider
-        * @param string $content The content stream, typically HTML template content.
-        * @param array $markContentArray The array of key/value pairs being marker/content values used in the substitution. For each element in this array the function will substitute a marker in the content stream with the content.
-        * @param string $wrap A wrap value - [part 1] | [part 2] - for the markers before substitution
-        * @param bool $uppercase If set, all marker string substitution is done with upper-case markers.
-        * @param bool $deleteUnused If set, all unused marker are deleted.
-        * @param string $expected
-        */
-       public function substituteMarkerArray($content, $markContentArray, $wrap, $uppercase, $deleteUnused, $expected) {
-               $this->assertSame($expected, HtmlParser::substituteMarkerArray($content, $markContentArray, $wrap, $uppercase, $deleteUnused));
-       }
-
-       /**
-        * Data provider for substituteMarker
-        */
-       public function substituteMarkerDataProvider() {
-               return array(
-                       'Single marker' => array(
-                               'This is a ###SAMPLE### text',
-                               '###SAMPLE###',
-                               'simple',
-                               'This is a simple text'
-                       ),
-                       'Double marker' => array(
-                               'This is a ###SAMPLE### text with a ###SAMPLE### content',
-                               '###SAMPLE###',
-                               'simple',
-                               'This is a simple text with a simple content'
-                       ),
-               );
-       }
-
-       /**
-        * @dataProvider substituteMarkerDataProvider
-        * @param string $content The content stream, typically HTML template content.
-        * @param string $marker The marker string, typically on the form "###[the marker string]###
-        * @param mixed $markContent The content to insert instead of the marker string found.
-        * @param string $expected The expected result of the substitution
-        */
-       public function substituteMarker($content, $marker, $markContent, $expected) {
-               $this->assertSame($expected, HtmlParser::substituteMarker($content, $marker, $markContent));
-       }
-
-       /**
-        * Data provider for substituteSubpartArray
-        *
-        * @return array
-        */
-       public function substituteSubpartArrayDataProvider() {
-               return array(
-                       'Substitute multiple subparts at once with plain marker' => array(
-                               '<body>
-###SUBPART1###text1###SUBPART1###
-###SUBPART2###text2###SUBPART2###
-</body>',
-                               array ('###SUBPART1###' => 'hello',
-                                       '###SUBPART2###' => 'world'),
-                               '<body>
-hello
-world
-</body>'
-                       ),
-               );
-       }
-
-       /**
-        * @test
-        * @param string $content
-        * @param array $subpartsContent
-        * @param string $expected
-        * @dataProvider substituteSubpartArrayDataProvider
-        */
-       public function substituteSubpartArray($content, array $subpartsContent, $expected) {
-               $this->assertSame($expected, HtmlParser::substituteSubpartArray($content, $subpartsContent));
-       }
-
-       /**
-        * Data provider for substituteMarkerAndSubpartArrayRecursiveResolvesMarkersAndSubpartsArray
-        *
-        * @return array
-        */
-       public function substituteMarkerAndSubpartArrayRecursiveResolvesMarkersAndSubpartsArrayDataProvider() {
-               $template = '###SINGLEMARKER1###
-<!-- ###FOO### begin -->
-<!-- ###BAR### begin -->
-###SINGLEMARKER2###
-<!-- ###BAR### end -->
-<!-- ###FOOTER### begin -->
-###SINGLEMARKER3###
-<!-- ###FOOTER### end -->
-<!-- ###FOO### end -->';
-
-               $expected ='Value 1
-
-
-Value 2.1
-
-Value 2.2
-
-
-Value 3.1
-
-Value 3.2
-
-';
-
-               return array(
-                       'Single marker' => array(
-                               '###SINGLEMARKER###',
-                               array(
-                                       '###SINGLEMARKER###' => 'Value 1'
-                               ),
-                               '',
-                               FALSE,
-                               FALSE,
-                               'Value 1'
-                       ),
-                       'Subpart marker' => array(
-                               $template,
-                               array(
-                                       '###SINGLEMARKER1###' => 'Value 1',
-                                       '###FOO###' => array(
-                                               array(
-                                                       '###BAR###' => array(
-                                                               array(
-                                                                       '###SINGLEMARKER2###' => 'Value 2.1'
-                                                               ),
-                                                               array(
-                                                                       '###SINGLEMARKER2###' => 'Value 2.2'
-                                                               )
-                                                       ),
-                                                       '###FOOTER###' => array(
-                                                               array(
-                                                                       '###SINGLEMARKER3###' => 'Value 3.1'
-                                                               ),
-                                                               array(
-                                                                       '###SINGLEMARKER3###' => 'Value 3.2'
-                                                               )
-                                                       )
-                                               )
-                                       )
-                               ),
-                               '',
-                               FALSE,
-                               FALSE,
-                               $expected
-                       ),
-                       'Subpart marker with wrap' => array(
-                               $template,
-                               array(
-                                       'SINGLEMARKER1' => 'Value 1',
-                                       'FOO' => array(
-                                               array(
-                                                       'BAR' => array(
-                                                               array(
-                                                                       'SINGLEMARKER2' => 'Value 2.1'
-                                                               ),
-                                                               array(
-                                                                       'SINGLEMARKER2' => 'Value 2.2'
-                                                               )
-                                                       ),
-                                                       'FOOTER' => array(
-                                                               array(
-                                                                       'SINGLEMARKER3' => 'Value 3.1'
-                                                               ),
-                                                               array(
-                                                                       'SINGLEMARKER3' => 'Value 3.2'
-                                                               )
-                                                       )
-                                               )
-                                       )
-                               ),
-                               '###|###',
-                               FALSE,
-                               FALSE,
-                               $expected
-                       ),
-                       'Subpart marker with lower marker array keys' => array(
-                               $template,
-                               array(
-                                       '###singlemarker1###' => 'Value 1',
-                                       '###foo###' => array(
-                                               array(
-                                                       '###bar###' => array(
-                                                               array(
-                                                                       '###singlemarker2###' => 'Value 2.1'
-                                                               ),
-                                                               array(
-                                                                       '###singlemarker2###' => 'Value 2.2'
-                                                               )
-                                                       ),
-                                                       '###footer###' => array(
-                                                               array(
-                                                                       '###singlemarker3###' => 'Value 3.1'
-                                                               ),
-                                                               array(
-                                                                       '###singlemarker3###' => 'Value 3.2'
-                                                               )
-                                                       )
-                                               )
-                                       )
-                               ),
-                               '',
-                               TRUE,
-                               FALSE,
-                               $expected
-                       ),
-                       'Subpart marker with unused markers' => array(
-                               $template,
-                               array(
-                                       '###FOO###' => array(
-                                               array(
-                                                       '###BAR###' => array(
-                                                               array(
-                                                                       '###SINGLEMARKER2###' => 'Value 2.1'
-                                                               )
-                                                       ),
-                                                       '###FOOTER###' => array(
-                                                               array(
-                                                                       '###SINGLEMARKER3###' => 'Value 3.1'
-                                                               )
-                                                       )
-                                               )
-                                       )
-                               ),
-                               '',
-                               FALSE,
-                               TRUE,
-                               '
-
-
-Value 2.1
-
-
-Value 3.1
-
-'
-                       ),
-                       'Subpart marker with empty subpart' => array(
-                               $template,
-                               array(
-                                       '###SINGLEMARKER1###' => 'Value 1',
-                                       '###FOO###' => array(
-                                               array(
-                                                       '###BAR###' => array(
-                                                               array(
-                                                                       '###SINGLEMARKER2###' => 'Value 2.1'
-                                                               ),
-                                                               array(
-                                                                       '###SINGLEMARKER2###' => 'Value 2.2'
-                                                               )
-                                                       ),
-                                                       '###FOOTER###' => array()
-                                               )
-                                       )
-                               ),
-                               '',
-                               FALSE,
-                               FALSE,
-                               'Value 1
-
-
-Value 2.1
-
-Value 2.2
-
-
-'
-                       )
-               );
-       }
-
-       /**
-        * @test
-        * @param string $template
-        * @param array $markersAndSubparts
-        * @param string $wrap
-        * @param bool $uppercase
-        * @param bool $deleteUnused
-        * @param string $expected
-        * @dataProvider substituteMarkerAndSubpartArrayRecursiveResolvesMarkersAndSubpartsArrayDataProvider
-        */
-       public function substituteMarkerAndSubpartArrayRecursiveResolvesMarkersAndSubpartsArray($template, $markersAndSubparts, $wrap, $uppercase, $deleteUnused, $expected) {
-               $this->assertSame($expected, HtmlParser::substituteMarkerAndSubpartArrayRecursive($template, $markersAndSubparts, $wrap, $uppercase, $deleteUnused));
-       }
-
-       /**
         * @return array
         */
        public function cDataWillRemainUnmodifiedDataProvider() {
diff --git a/typo3/sysext/core/Tests/Unit/Utility/MarkerUtilityTest.php b/typo3/sysext/core/Tests/Unit/Utility/MarkerUtilityTest.php
new file mode 100644 (file)
index 0000000..a65dd57
--- /dev/null
@@ -0,0 +1,586 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Utility;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\MarkerUtility;
+
+/**
+ * Unit test for marker utility
+ */
+class MarkerUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
+
+       /**
+        * Data provider for getSubpart
+        *
+        * @return array
+        */
+       public function getSubpartDataProvider() {
+               return array(
+                       'No start marker' => array(
+                               '<body>text</body>',
+                               '###SUBPART###',
+                               ''
+                       ),
+                       'No stop marker' => array(
+                               '<body>
+<!-- ###SUBPART### Start -->
+text
+</body>',
+                               '###SUBPART###',
+                               ''
+                       ),
+                       'Start and stop marker in HTML comment' => array(
+                               '<body>
+<!-- ###SUBPART### Start -->
+text
+<!-- ###SUBPART### End -->
+</body>',
+                               '###SUBPART###',
+                               '
+text
+'
+                       ),
+                       'Stop marker in HTML comment' => array(
+                               '<body>
+###SUBPART###
+text
+<!-- ###SUBPART### End -->
+</body>',
+                               '###SUBPART###',
+                               '
+text
+'
+                       ),
+                       'Start marker in HTML comment' => array(
+                               '<body>
+<!-- ###SUBPART### Start -->
+text
+###SUBPART###
+</body>',
+                               '###SUBPART###',
+                               '
+text
+'
+                       ),
+                       'Start and stop marker direct' => array(
+                               '<body>
+###SUBPART###
+text
+###SUBPART###
+</body>',
+                               '###SUBPART###',
+                               '
+text
+'
+                       ),
+               );
+       }
+
+       /**
+        * @test
+        * @param string $content
+        * @param string $marker
+        * @param string $expected
+        * @dataProvider getSubpartDataProvider
+        */
+       public function getSubpart($content, $marker, $expected) {
+               $this->assertSame($expected, MarkerUtility::getSubpart($content, $marker));
+       }
+
+       /**
+        * Data provider for substituteSubpart
+        *
+        * @return array
+        */
+       public function substituteSubpartDataProvider() {
+               return array(
+                       'No start marker' => array(
+                               '<body>text</body>',
+                               '###SUBPART###',
+                               'hello',
+                               FALSE,
+                               FALSE,
+                               '<body>text</body>'
+                       ),
+                       'No stop marker' => array(
+                               '<body>
+<!-- ###SUBPART### Start -->
+text
+</body>',
+                               '###SUBPART###',
+                               'hello',
+                               FALSE,
+                               FALSE,
+                               '<body>
+<!-- ###SUBPART### Start -->
+text
+</body>',
+                       ),
+                       'Start and stop marker in HTML comment' => array(
+                               '<body>
+<!-- ###SUBPART### Start -->
+text
+<!-- ###SUBPART### End -->
+</body>',
+                               '###SUBPART###',
+                               'hello',
+                               FALSE,
+                               FALSE,
+                               '<body>
+hello
+</body>'
+                       ),
+                       'Recursive subpart' => array(
+                               '<body>
+<!-- ###SUBPART### Start -->text1<!-- ###SUBPART### End -->
+<!-- ###SUBPART### Start -->text2<!-- ###SUBPART### End -->
+</body>',
+                               '###SUBPART###',
+                               'hello',
+                               TRUE,
+                               FALSE,
+                               '<body>
+hello
+hello
+</body>'
+                       ),
+                       'Keep HTML marker' => array(
+                               '<body>
+<!-- ###SUBPART### Start -->text<!-- ###SUBPART### End -->
+</body>',
+                               '###SUBPART###',
+                               'hello',
+                               FALSE,
+                               TRUE,
+                               '<body>
+<!-- ###SUBPART### Start -->hello<!-- ###SUBPART### End -->
+</body>'
+                       ),
+                       'Keep HTML begin marker' => array(
+                               '<body>
+<!-- ###SUBPART### Start -->text###SUBPART###
+</body>',
+                               '###SUBPART###',
+                               'hello',
+                               FALSE,
+                               TRUE,
+                               '<body>
+<!-- ###SUBPART### Start -->hello###SUBPART###
+</body>'
+                       ),
+                       'Keep HTML end marker' => array(
+                               '<body>
+###SUBPART###text<!-- ###SUBPART### End -->
+</body>',
+                               '###SUBPART###',
+                               'hello',
+                               FALSE,
+                               TRUE,
+                               '<body>
+###SUBPART###hello<!-- ###SUBPART### End -->
+</body>'
+                       ),
+                       'Keep plain marker' => array(
+                               '<body>
+###SUBPART###text###SUBPART###
+</body>',
+                               '###SUBPART###',
+                               'hello',
+                               FALSE,
+                               TRUE,
+                               '<body>
+###SUBPART###hello###SUBPART###
+</body>'
+                       ),
+                       'Wrap around' => array(
+                               '<body>
+###SUBPART###text###SUBPART###
+</body>',
+                               '###SUBPART###',
+                               array('before-', '-after'),
+                               FALSE,
+                               TRUE,
+                               '<body>
+###SUBPART###before-text-after###SUBPART###
+</body>'
+                       ),
+               );
+       }
+
+       /**
+        * @test
+        * @param string $content
+        * @param string $marker
+        * @param array $subpartContent
+        * @param bool $recursive
+        * @param bool $keepMarker
+        * @param string $expected
+        * @dataProvider substituteSubpartDataProvider
+        */
+       public function substituteSubpart($content, $marker, $subpartContent, $recursive, $keepMarker, $expected) {
+               $this->assertSame($expected, MarkerUtility::substituteSubpart($content, $marker, $subpartContent, $recursive, $keepMarker));
+       }
+
+       /**
+        * Data provider for substituteMarkerArray
+        */
+       public function substituteMarkerArrayDataProvider() {
+               return array(
+                       'Upper case marker' => array(
+                               'This is ###MARKER1### and this is ###MARKER2###',
+                               array('###MARKER1###' => 'marker 1',
+                                       '###MARKER2###' => 'marker 2'),
+                               '',
+                               FALSE,
+                               FALSE,
+                               'This is marker 1 and this is marker 2'
+                       ),
+                       'Lower case marker' => array(
+                               'This is ###MARKER1### and this is ###MARKER2###',
+                               array('###marker1###' => 'marker 1',
+                                       '###marker2###' => 'marker 2'),
+                               '',
+                               TRUE,
+                               FALSE,
+                               'This is marker 1 and this is marker 2'
+                       ),
+                       'Upper case marker without hash mark' => array(
+                               'This is ###MARKER1### and this is ###MARKER2###',
+                               array('MARKER1' => 'marker 1',
+                                       'MARKER2' => 'marker 2'),
+                               '###|###',
+                               FALSE,
+                               FALSE,
+                               'This is marker 1 and this is marker 2'
+                       ),
+                       'Upper case marker with another hash mark' => array(
+                               'This is *MARKER1* and this is *MARKER2*',
+                               array('MARKER1' => 'marker 1',
+                                       'MARKER2' => 'marker 2'),
+                               '*|*',
+                               FALSE,
+                               FALSE,
+                               'This is marker 1 and this is marker 2'
+                       ),
+                       'Upper case marker with unused marker' => array(
+                               'This is ###MARKER1### and this is ###MARKER2### ###UNUSED###',
+                               array('###MARKER1###' => 'marker 1',
+                                       '###MARKER2###' => 'marker 2'),
+                               '',
+                               FALSE,
+                               FALSE,
+                               'This is marker 1 and this is marker 2 ###UNUSED###'
+                       ),
+                       'Upper case marker with unused marker deleted' => array(
+                               'This is ###MARKER1### and this is ###MARKER2### ###UNUSED###',
+                               array('###MARKER1###' => 'marker 1',
+                                       '###MARKER2###' => 'marker 2'),
+                               '',
+                               FALSE,
+                               TRUE,
+                               'This is marker 1 and this is marker 2 '
+                       ),
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider substituteMarkerArrayDataProvider
+        * @param string $content The content stream, typically HTML template content.
+        * @param array $markContentArray The array of key/value pairs being marker/content values used in the substitution. For each element in this array the function will substitute a marker in the content stream with the content.
+        * @param string $wrap A wrap value - [part 1] | [part 2] - for the markers before substitution
+        * @param bool $uppercase If set, all marker string substitution is done with upper-case markers.
+        * @param bool $deleteUnused If set, all unused marker are deleted.
+        * @param string $expected
+        */
+       public function substituteMarkerArray($content, $markContentArray, $wrap, $uppercase, $deleteUnused, $expected) {
+               $this->assertSame($expected, MarkerUtility::substituteMarkerArray($content, $markContentArray, $wrap, $uppercase, $deleteUnused));
+       }
+
+       /**
+        * Data provider for substituteMarker
+        */
+       public function substituteMarkerDataProvider() {
+               return array(
+                       'Single marker' => array(
+                               'This is a ###SAMPLE### text',
+                               '###SAMPLE###',
+                               'simple',
+                               'This is a simple text'
+                       ),
+                       'Double marker' => array(
+                               'This is a ###SAMPLE### text with a ###SAMPLE### content',
+                               '###SAMPLE###',
+                               'simple',
+                               'This is a simple text with a simple content'
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider substituteMarkerDataProvider
+        * @param string $content The content stream, typically HTML template content.
+        * @param string $marker The marker string, typically on the form "###[the marker string]###
+        * @param mixed $markContent The content to insert instead of the marker string found.
+        * @param string $expected The expected result of the substitution
+        */
+       public function substituteMarker($content, $marker, $markContent, $expected) {
+               $this->assertSame($expected, MarkerUtility::substituteMarker($content, $marker, $markContent));
+       }
+
+       /**
+        * Data provider for substituteSubpartArray
+        *
+        * @return array
+        */
+       public function substituteSubpartArrayDataProvider() {
+               return array(
+                       'Substitute multiple subparts at once with plain marker' => array(
+                               '<body>
+###SUBPART1###text1###SUBPART1###
+###SUBPART2###text2###SUBPART2###
+</body>',
+                               array ('###SUBPART1###' => 'hello',
+                                       '###SUBPART2###' => 'world'),
+                               '<body>
+hello
+world
+</body>'
+                       ),
+               );
+       }
+
+       /**
+        * @test
+        * @param string $content
+        * @param array $subpartsContent
+        * @param string $expected
+        * @dataProvider substituteSubpartArrayDataProvider
+        */
+       public function substituteSubpartArray($content, array $subpartsContent, $expected) {
+               $this->assertSame($expected, MarkerUtility::substituteSubpartArray($content, $subpartsContent));
+       }
+
+       /**
+        * Data provider for substituteMarkerAndSubpartArrayRecursiveResolvesMarkersAndSubpartsArray
+        *
+        * @return array
+        */
+       public function substituteMarkerAndSubpartArrayRecursiveResolvesMarkersAndSubpartsArrayDataProvider() {
+               $template = '###SINGLEMARKER1###
+<!-- ###FOO### begin -->
+<!-- ###BAR### begin -->
+###SINGLEMARKER2###
+<!-- ###BAR### end -->
+<!-- ###FOOTER### begin -->
+###SINGLEMARKER3###
+<!-- ###FOOTER### end -->
+<!-- ###FOO### end -->';
+
+               $expected ='Value 1
+
+
+Value 2.1
+
+Value 2.2
+
+
+Value 3.1
+
+Value 3.2
+
+';
+
+               return array(
+                       'Single marker' => array(
+                               '###SINGLEMARKER###',
+                               array(
+                                       '###SINGLEMARKER###' => 'Value 1'
+                               ),
+                               '',
+                               FALSE,
+                               FALSE,
+                               'Value 1'
+                       ),
+                       'Subpart marker' => array(
+                               $template,
+                               array(
+                                       '###SINGLEMARKER1###' => 'Value 1',
+                                       '###FOO###' => array(
+                                               array(
+                                                       '###BAR###' => array(
+                                                               array(
+                                                                       '###SINGLEMARKER2###' => 'Value 2.1'
+                                                               ),
+                                                               array(
+                                                                       '###SINGLEMARKER2###' => 'Value 2.2'
+                                                               )
+                                                       ),
+                                                       '###FOOTER###' => array(
+                                                               array(
+                                                                       '###SINGLEMARKER3###' => 'Value 3.1'
+                                                               ),
+                                                               array(
+                                                                       '###SINGLEMARKER3###' => 'Value 3.2'
+                                                               )
+                                                       )
+                                               )
+                                       )
+                               ),
+                               '',
+                               FALSE,
+                               FALSE,
+                               $expected
+                       ),
+                       'Subpart marker with wrap' => array(
+                               $template,
+                               array(
+                                       'SINGLEMARKER1' => 'Value 1',
+                                       'FOO' => array(
+                                               array(
+                                                       'BAR' => array(
+                                                               array(
+                                                                       'SINGLEMARKER2' => 'Value 2.1'
+                                                               ),
+                                                               array(
+                                                                       'SINGLEMARKER2' => 'Value 2.2'
+                                                               )
+                                                       ),
+                                                       'FOOTER' => array(
+                                                               array(
+                                                                       'SINGLEMARKER3' => 'Value 3.1'
+                                                               ),
+                                                               array(
+                                                                       'SINGLEMARKER3' => 'Value 3.2'
+                                                               )
+                                                       )
+                                               )
+                                       )
+                               ),
+                               '###|###',
+                               FALSE,
+                               FALSE,
+                               $expected
+                       ),
+                       'Subpart marker with lower marker array keys' => array(
+                               $template,
+                               array(
+                                       '###singlemarker1###' => 'Value 1',
+                                       '###foo###' => array(
+                                               array(
+                                                       '###bar###' => array(
+                                                               array(
+                                                                       '###singlemarker2###' => 'Value 2.1'
+                                                               ),
+                                                               array(
+                                                                       '###singlemarker2###' => 'Value 2.2'
+                                                               )
+                                                       ),
+                                                       '###footer###' => array(
+                                                               array(
+                                                                       '###singlemarker3###' => 'Value 3.1'
+                                                               ),
+                                                               array(
+                                                                       '###singlemarker3###' => 'Value 3.2'
+                                                               )
+                                                       )
+                                               )
+                                       )
+                               ),
+                               '',
+                               TRUE,
+                               FALSE,
+                               $expected
+                       ),
+                       'Subpart marker with unused markers' => array(
+                               $template,
+                               array(
+                                       '###FOO###' => array(
+                                               array(
+                                                       '###BAR###' => array(
+                                                               array(
+                                                                       '###SINGLEMARKER2###' => 'Value 2.1'
+                                                               )
+                                                       ),
+                                                       '###FOOTER###' => array(
+                                                               array(
+                                                                       '###SINGLEMARKER3###' => 'Value 3.1'
+                                                               )
+                                                       )
+                                               )
+                                       )
+                               ),
+                               '',
+                               FALSE,
+                               TRUE,
+                               '
+
+
+Value 2.1
+
+
+Value 3.1
+
+'
+                       ),
+                       'Subpart marker with empty subpart' => array(
+                               $template,
+                               array(
+                                       '###SINGLEMARKER1###' => 'Value 1',
+                                       '###FOO###' => array(
+                                               array(
+                                                       '###BAR###' => array(
+                                                               array(
+                                                                       '###SINGLEMARKER2###' => 'Value 2.1'
+                                                               ),
+                                                               array(
+                                                                       '###SINGLEMARKER2###' => 'Value 2.2'
+                                                               )
+                                                       ),
+                                                       '###FOOTER###' => array()
+                                               )
+                                       )
+                               ),
+                               '',
+                               FALSE,
+                               FALSE,
+                               'Value 1
+
+
+Value 2.1
+
+Value 2.2
+
+
+'
+                       )
+               );
+       }
+
+       /**
+        * @test
+        * @param string $template
+        * @param array $markersAndSubparts
+        * @param string $wrap
+        * @param bool $uppercase
+        * @param bool $deleteUnused
+        * @param string $expected
+        * @dataProvider substituteMarkerAndSubpartArrayRecursiveResolvesMarkersAndSubpartsArrayDataProvider
+        */
+       public function substituteMarkerAndSubpartArrayRecursiveResolvesMarkersAndSubpartsArray($template, $markersAndSubparts, $wrap, $uppercase, $deleteUnused, $expected) {
+               $this->assertSame($expected, MarkerUtility::substituteMarkerAndSubpartArrayRecursive($template, $markersAndSubparts, $wrap, $uppercase, $deleteUnused));
+       }
+
+}
\ No newline at end of file
index 4e1165b..4cbd90e 100755 (executable)
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Frontend\ContentObject;
 use TYPO3\CMS\Core\Cache\CacheManager;
 use TYPO3\CMS\Core\FrontendEditing\FrontendEditingController;
 use TYPO3\CMS\Core\Html\HtmlParser;
+use TYPO3\CMS\Core\Utility\MarkerUtility;
 use TYPO3\CMS\Core\Imaging\GraphicalFunctions;
 use TYPO3\CMS\Core\Log\LogManager;
 use TYPO3\CMS\Core\Mail\MailMessage;
@@ -1958,21 +1959,21 @@ class ContentObjectRenderer {
         * " World. How are ". The input content string could just as well have
         * been "Hello ###sub1### World. How are ###sub1### you?" and the result
         * would be the same
-        * Wrapper for \TYPO3\CMS\Core\Html\HtmlParser::getSubpart which behaves identical
+        * Wrapper for \TYPO3\CMS\Core\Utility\MarkerUtility::getSubpart which behaves identical
         *
         * @param string $content The content stream, typically HTML template content.
         * @param string $marker The marker string, typically on the form "###[the marker string]###
         * @return string The subpart found, if found.
         */
        public function getSubpart($content, $marker) {
-               return HtmlParser::getSubpart($content, $marker);
+               return MarkerUtility::getSubpart($content, $marker);
        }
 
        /**
         * Substitute subpart in input template stream.
         * This function substitutes a subpart in $content with the content of
         * $subpartContent.
-        * Wrapper for \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart which behaves identical
+        * Wrapper for \TYPO3\CMS\Core\Utility\MarkerUtility::substituteSubpart which behaves identical
         *
         * @param string $content The content stream, typically HTML template content.
         * @param string $marker The marker string, typically on the form "###[the marker string]###
@@ -1981,7 +1982,7 @@ class ContentObjectRenderer {
         * @return string The processed HTML content string.
         */
        public function substituteSubpart($content, $marker, $subpartContent, $recursive = 1) {
-               return HtmlParser::substituteSubpart($content, $marker, $subpartContent, $recursive);
+               return MarkerUtility::substituteSubpart($content, $marker, $subpartContent, $recursive);
        }
 
        /**
@@ -1992,7 +1993,7 @@ class ContentObjectRenderer {
         * @return string The processed HTML content string.
         */
        public function substituteSubpartArray($content, array $subpartsContent) {
-               return HtmlParser::substituteSubpartArray($content, $subpartsContent);
+               return MarkerUtility::substituteSubpartArray($content, $subpartsContent);
        }
 
        /**
@@ -2006,7 +2007,7 @@ class ContentObjectRenderer {
         * @see substituteSubpart()
         */
        public function substituteMarker($content, $marker, $markContent) {
-               return HtmlParser::substituteMarker($content, $marker, $markContent);
+               return MarkerUtility::substituteMarker($content, $marker, $markContent);
        }
 
        /**
@@ -2149,7 +2150,7 @@ class ContentObjectRenderer {
         * @see substituteMarker(), substituteMarkerInObject(), TEMPLATE()
         */
        public function substituteMarkerArray($content, array $markContentArray, $wrap = '', $uppercase = FALSE, $deleteUnused = FALSE) {
-               return HtmlParser::substituteMarkerArray($content, $markContentArray, $wrap, $uppercase, $deleteUnused);
+               return MarkerUtility::substituteMarkerArray($content, $markContentArray, $wrap, $uppercase, $deleteUnused);
        }
 
        /**
@@ -2182,7 +2183,7 @@ class ContentObjectRenderer {
         * @return string
         */
        public function substituteMarkerAndSubpartArrayRecursive($content, array $markersAndSubparts, $wrap = '', $uppercase = FALSE, $deleteUnused = FALSE) {
-               return HtmlParser::substituteMarkerAndSubpartArrayRecursive($content, $markersAndSubparts, $wrap, $uppercase, $deleteUnused);
+               return MarkerUtility::substituteMarkerAndSubpartArrayRecursive($content, $markersAndSubparts, $wrap, $uppercase, $deleteUnused);
        }
 
        /**
index 0c67739..a75ab25 100644 (file)
@@ -20,7 +20,7 @@ use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Core\Html\HtmlParser;
+use TYPO3\CMS\Core\Utility\MarkerUtility;
 use TYPO3\CMS\Linkvalidator\LinkAnalyzer;
 
 /**
@@ -347,7 +347,7 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
         */
        protected function renderBrokenLinksTable() {
                $brokenLinkItems = '';
-               $brokenLinksTemplate = HtmlParser::getSubpart($this->doc->moduleTemplate, '###NOBROKENLINKS_CONTENT###');
+               $brokenLinksTemplate = MarkerUtility::getSubpart($this->doc->moduleTemplate, '###NOBROKENLINKS_CONTENT###');
                $keyOpt = array();
                if (is_array($this->checkOpt)) {
                        $keyOpt = array_keys($this->checkOpt);
@@ -377,8 +377,8 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
                        );
                        if (!empty($records)) {
                                // Display table with broken links
-                               $brokenLinksTemplate = HtmlParser::getSubpart($this->doc->moduleTemplate, '###BROKENLINKS_CONTENT###');
-                               $brokenLinksItemTemplate = HtmlParser::getSubpart($this->doc->moduleTemplate, '###BROKENLINKS_ITEM###');
+                               $brokenLinksTemplate = MarkerUtility::getSubpart($this->doc->moduleTemplate, '###BROKENLINKS_CONTENT###');
+                               $brokenLinksItemTemplate = MarkerUtility::getSubpart($this->doc->moduleTemplate, '###BROKENLINKS_ITEM###');
 
                                // Table rows containing the broken links
                                $items = array();
@@ -392,12 +392,12 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
                } else {
                        $brokenLinksMarker = $this->getNoBrokenLinkMessage($brokenLinksMarker);
                }
-               $brokenLinksTemplate = HtmlParser::substituteMarkerArray(
+               $brokenLinksTemplate = MarkerUtility::substituteMarkerArray(
                        $brokenLinksTemplate,
                        $brokenLinksMarker, '###|###',
                        TRUE
                );
-               return HtmlParser::substituteSubpart($brokenLinksTemplate, '###BROKENLINKS_ITEM', $brokenLinkItems);
+               return MarkerUtility::substituteSubpart($brokenLinksTemplate, '###BROKENLINKS_ITEM', $brokenLinkItems);
        }
 
        /**
@@ -511,7 +511,7 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
                $markerArray['lastcheck'] = sprintf($this->getLanguageService()->getLL('list.msg.lastRun'), $lastRunDate, $lastRunTime);
 
                // Return the table html code as string
-               return HtmlParser::substituteMarkerArray($brokenLinksItemTemplate, $markerArray, '###|###', TRUE, TRUE);
+               return MarkerUtility::substituteMarkerArray($brokenLinksItemTemplate, $markerArray, '###|###', TRUE, TRUE);
        }
 
        /**
@@ -528,8 +528,8 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
                } else {
                        $additionalAttr = ' class="refresh"';
                }
-               $checkOptionsTemplate = HtmlParser::getSubpart($this->doc->moduleTemplate, '###CHECKOPTIONS_SECTION###');
-               $hookSectionTemplate = HtmlParser::getSubpart($checkOptionsTemplate, '###HOOK_SECTION###');
+               $checkOptionsTemplate = MarkerUtility::getSubpart($this->doc->moduleTemplate, '###CHECKOPTIONS_SECTION###');
+               $hookSectionTemplate = MarkerUtility::getSubpart($checkOptionsTemplate, '###HOOK_SECTION###');
                $markerArray['statistics_header'] = $this->doc->sectionHeader($this->getLanguageService()->getLL('report.statistics.header'));
                $markerArray['total_count_label'] = BackendUtility::wrapInHelp('linkvalidator', 'checkboxes', $this->getLanguageService()->getLL('overviews.nbtotal'));
                $markerArray['total_count'] = $brokenLinkOverView['brokenlinkCount'] ?: '0';
@@ -552,7 +552,7 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
                                                        . 'SET[' . $type . ']" value="1"' . ($this->pObj->MOD_SETTINGS[$type] ? ' checked="checked"' : '') . '/>' . '<label for="'
                                                        . $prefix . 'SET_' . $type . '">&nbsp;' . htmlspecialchars($translation) . '</label>';
 
-                                               $hookSectionContent .= HtmlParser::substituteMarkerArray(
+                                               $hookSectionContent .= MarkerUtility::substituteMarkerArray(
                                                        $hookSectionTemplate,
                                                        $hookSectionMarker, '###|###',
                                                        TRUE,
@@ -562,12 +562,12 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
                                }
                        }
                }
-               $checkOptionsTemplate = HtmlParser::substituteSubpart(
+               $checkOptionsTemplate = MarkerUtility::substituteSubpart(
                        $checkOptionsTemplate,
                        '###HOOK_SECTION###',
                        $hookSectionContent
                );
-               return HtmlParser::substituteMarkerArray($checkOptionsTemplate, $markerArray, '###|###', TRUE, TRUE);
+               return MarkerUtility::substituteMarkerArray($checkOptionsTemplate, $markerArray, '###|###', TRUE, TRUE);
        }
 
        /**
index 47c8500..53dc8c6 100644 (file)
@@ -19,7 +19,7 @@ use TYPO3\CMS\Core\Mail\MailMessage;
 use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Core\Html\HtmlParser;
+use TYPO3\CMS\Core\Utility\MarkerUtility;
 use TYPO3\CMS\Core\Utility\MailUtility;
 use TYPO3\CMS\Lang\LanguageService;
 use TYPO3\CMS\Linkvalidator\LinkAnalyzer;
@@ -253,7 +253,7 @@ class ValidatorTask extends \TYPO3\CMS\Scheduler\Task\AbstractTask {
                        }
                }
                $htmlFile = GeneralUtility::getURL($file);
-               $this->templateMail = HtmlParser::getSubpart($htmlFile, '###REPORT_TEMPLATE###');
+               $this->templateMail = MarkerUtility::getSubpart($htmlFile, '###REPORT_TEMPLATE###');
                // The array to put the content into
                $pageSections = '';
                $this->isDifferentToLastRun = FALSE;
@@ -398,7 +398,7 @@ class ValidatorTask extends \TYPO3\CMS\Scheduler\Task\AbstractTask {
         * @throws \Exception if required modTsConfig settings are missing
         */
        protected function reportEmail($pageSections, array $modTsConfig) {
-               $content = HtmlParser::substituteSubpart($this->templateMail, '###PAGE_SECTION###', $pageSections);
+               $content = MarkerUtility::substituteSubpart($this->templateMail, '###PAGE_SECTION###', $pageSections);
                /** @var array $markerArray */
                $markerArray = array();
                /** @var array $validEmailList */
@@ -421,7 +421,7 @@ class ValidatorTask extends \TYPO3\CMS\Scheduler\Task\AbstractTask {
                                unset($params);
                        }
                }
-               $content = HtmlParser::substituteMarkerArray($content, $markerArray, '###|###', TRUE, TRUE);
+               $content = MarkerUtility::substituteMarkerArray($content, $markerArray, '###|###', TRUE, TRUE);
                /** @var $mail MailMessage */
                $mail = GeneralUtility::makeInstance(MailMessage::class);
                if (empty($modTsConfig['mail.']['fromemail'])) {
@@ -483,7 +483,7 @@ class ValidatorTask extends \TYPO3\CMS\Scheduler\Task\AbstractTask {
         * @return string Content of the mail
         */
        protected function buildMail($curPage, $pageList, array $markerArray, array $oldBrokenLink) {
-               $pageSectionHtml = HtmlParser::getSubpart($this->templateMail, '###PAGE_SECTION###');
+               $pageSectionHtml = MarkerUtility::getSubpart($this->templateMail, '###PAGE_SECTION###');
                // Hook
                if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['buildMailMarkers'])) {
                        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['linkvalidator']['buildMailMarkers'] as $userFunc) {
@@ -518,7 +518,7 @@ class ValidatorTask extends \TYPO3\CMS\Scheduler\Task\AbstractTask {
                );
                $content = '';
                if ($markerArray['brokenlinkCount'] > 0) {
-                       $content = HtmlParser::substituteMarkerArray($pageSectionHtml, $markerArray, '###|###', TRUE, TRUE);
+                       $content = MarkerUtility::substituteMarkerArray($pageSectionHtml, $markerArray, '###|###', TRUE, TRUE);
                }
                return $content;
        }
index f05bdca..02b4241 100644 (file)
@@ -589,8 +589,8 @@ class DataHandlerHook {
                                                $emailMessage = $languageObject->sL($emailMessage);
                                        }
                                }
-                               $emailSubject = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($emailSubject, $markers, '', TRUE, TRUE);
-                               $emailMessage = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($emailMessage, $markers, '', TRUE, TRUE);
+                               $emailSubject = \TYPO3\CMS\Core\Utility\MarkerUtility::substituteMarkerArray($emailSubject, $markers, '', TRUE, TRUE);
+                               $emailMessage = \TYPO3\CMS\Core\Utility\MarkerUtility::substituteMarkerArray($emailMessage, $markers, '', TRUE, TRUE);
                                // Send an email to the recipient
                                /** @var $mail \TYPO3\CMS\Core\Mail\MailMessage */
                                $mail = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Mail\MailMessage::class);