1<?php
2namespace TYPO3\CMS\Fluid\ViewHelpers\Format;
3
4/*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17use TYPO3\CMS\Core\Utility\GeneralUtility;
18use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
19use TYPO3\CMS\Extbase\Object\ObjectManager;
20use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
21use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
22use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
23use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
24
25/**
26 * Renders a string by passing it to a TYPO3 `parseFunc`_.
27 * You can either specify a path to the TypoScript setting or set the `parseFunc`_ options directly.
28 * By default :ts:`lib.parseFunc_RTE` is used to parse the string.
29 *
30 * Examples
31 * ========
32 *
33 * Default parameters
34 * ------------------
35 *
36 * ::
37 *
38 *    <f:format.html>foo <b>bar</b>. Some <LINK 1>link</LINK>.</f:format.html>
39 *
40 * Output::
41 *
42 *    <p class="bodytext">foo <b>bar</b>. Some <a href="index.php?id=1" >link</a>.</p>
43 *
44 * Depending on TYPO3 setup.
45 *
46 * Custom parseFunc
47 * ----------------
48 *
49 * ::
50 *
51 *    <f:format.html parseFuncTSPath="lib.parseFunc">foo <b>bar</b>. Some <LINK 1>link</LINK>.</f:format.html>
52 *
53 * Output::
54 *
55 *    foo <b>bar</b>. Some <a href="index.php?id=1" >link</a>.
56 *
57 * Inline notation
58 * ---------------
59 *
60 * ::
61 *
62 *    {someText -> f:format.html(parseFuncTSPath: 'lib.parseFunc')}
63 *
64 * Output::
65 *
66 *    foo <b>bar</b>. Some <a href="index.php?id=1" >link</a>.
67 *
68 * .. _parseFunc: https://docs.typo3.org/m/typo3/reference-typoscript/master/en-us/Functions/Parsefunc.html
69 */
70class HtmlViewHelper extends AbstractViewHelper
71{
72    use CompileWithRenderStatic;
73
74    /**
75     * @var \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController contains a backup of the current $GLOBALS['TSFE'] if used in BE mode
76     */
77    protected static $tsfeBackup;
78
79    /**
80     * Children must not be escaped, to be able to pass {bodytext} directly to it
81     *
82     * @var bool
83     */
84    protected $escapeChildren = false;
85
86    /**
87     * Plain HTML should be returned, no output escaping allowed
88     *
89     * @var bool
90     */
91    protected $escapeOutput = false;
92
93    /**
94     * Initialize arguments.
95     *
96     * @throws \TYPO3Fluid\Fluid\Core\ViewHelper\Exception
97     */
98    public function initializeArguments()
99    {
100        $this->registerArgument('parseFuncTSPath', 'string', 'Path to TypoScript parseFunc setup', false, 'lib.parseFunc_RTE');
101    }
102
103    /**
104     * @param array $arguments
105     * @param \Closure $renderChildrenClosure
106     * @param RenderingContextInterface $renderingContext
107     *
108     * @return string the parsed string.
109     */
110    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
111    {
112        $parseFuncTSPath = $arguments['parseFuncTSPath'];
113        if (TYPO3_MODE === 'BE') {
114            self::simulateFrontendEnvironment();
115        }
116        $value = $renderChildrenClosure();
117        $contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
118        $contentObject->start([]);
119        $content = $contentObject->parseFunc($value, [], '< ' . $parseFuncTSPath);
120        if (TYPO3_MODE === 'BE') {
121            self::resetFrontendEnvironment();
122        }
123        return $content;
124    }
125
126    /**
127     * Copies the specified parseFunc configuration to $GLOBALS['TSFE']->tmpl->setup in Backend mode
128     * This somewhat hacky work around is currently needed because the parseFunc() function of \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer relies on those variables to be set
129     */
130    protected static function simulateFrontendEnvironment()
131    {
132        self::$tsfeBackup = $GLOBALS['TSFE'] ?? null;
133        $GLOBALS['TSFE'] = new \stdClass();
134        $GLOBALS['TSFE']->tmpl = new \stdClass();
135        $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
136        $configurationManager = $objectManager->get(ConfigurationManagerInterface::class);
137        $GLOBALS['TSFE']->tmpl->setup = $configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
138    }
139
140    /**
141     * Resets $GLOBALS['TSFE'] if it was previously changed by simulateFrontendEnvironment()
142     *
143     * @see simulateFrontendEnvironment()
144     */
145    protected static function resetFrontendEnvironment()
146    {
147        $GLOBALS['TSFE'] = self::$tsfeBackup;
148    }
149}
150