dc26420c20c582863035aab1ea602d94d4cff423
[Packages/TYPO3.CMS.git] / typo3 / sysext / fluid / Classes / ViewHelpers / CObjectViewHelper.php
1 <?php
2 namespace TYPO3\CMS\Fluid\ViewHelpers;
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
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
19
20 /**
21 * This ViewHelper renders CObjects from the global TypoScript configuration.
22 * NOTE: You have to ensure proper escaping (htmlspecialchars/intval/etc.) on your own!
23 *
24 * = Examples =
25 *
26 * <code title="Render lib object">
27 * <f:cObject typoscriptObjectPath="lib.someLibObject" />
28 * </code>
29 * <output>
30 * rendered lib.someLibObject
31 * </output>
32 *
33 * <code title="Specify cObject data & current value">
34 * <f:cObject typoscriptObjectPath="lib.customHeader" data="{article}" currentValueKey="title" />
35 * </code>
36 * <output>
37 * rendered lib.customHeader. data and current value will be available in TypoScript
38 * </output>
39 *
40 * <code title="inline notation">
41 * {article -> f:cObject(typoscriptObjectPath: 'lib.customHeader')}
42 * </code>
43 * <output>
44 * rendered lib.customHeader. data will be available in TypoScript
45 * </output>
46 */
47 class CObjectViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper
48 {
49 /**
50 * Disable escaping of child nodes' output
51 *
52 * @var bool
53 */
54 protected $escapeChildren = false;
55
56 /**
57 * Disable escaping of this node's output
58 *
59 * @var bool
60 */
61 protected $escapeOutput = false;
62
63 /**
64 * @var array
65 */
66 protected $typoScriptSetup;
67
68 /**
69 * @var \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController contains a backup of the current $GLOBALS['TSFE'] if used in BE mode
70 */
71 protected $tsfeBackup;
72
73 /**
74 * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
75 */
76 protected $configurationManager;
77
78 /**
79 * @var ContentObjectRenderer
80 */
81 protected $contentObjectRenderer;
82
83 /**
84 * @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
85 */
86 public function injectConfigurationManager(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager)
87 {
88 $this->configurationManager = $configurationManager;
89 $this->typoScriptSetup = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
90 }
91
92 /**
93 * @param ContentObjectRenderer $contentObjectRenderer
94 */
95 public function injectContentObjectRenderer(ContentObjectRenderer $contentObjectRenderer)
96 {
97 $this->contentObjectRenderer = $contentObjectRenderer;
98 }
99
100 /**
101 * Initialize arguments.
102 *
103 * @throws \TYPO3Fluid\Fluid\Core\ViewHelper\Exception
104 */
105 public function initializeArguments()
106 {
107 parent::initializeArguments();
108 $this->registerArgument('typoscriptObjectPath', 'string', 'the TypoScript setup path of the TypoScript object to render', true);
109 $this->registerArgument('data', 'mixed', 'the data to be used for rendering the cObject. Can be an object, array or string. If this argument is not set, child nodes will be used');
110 $this->registerArgument('currentValueKey', 'string', 'currentValueKey');
111 $this->registerArgument('table', 'string', 'table', false, '');
112 }
113
114 /**
115 * Renders the TypoScript object in the given TypoScript setup path.
116 *
117 * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
118 * @return string the content of the rendered TypoScript object
119 */
120 public function render()
121 {
122 $typoscriptObjectPath = $this->arguments['typoscriptObjectPath'];
123 $data = $this->arguments['data'];
124 $currentValueKey = $this->arguments['currentValueKey'];
125 $table = $this->arguments['table'];
126 if (TYPO3_MODE === 'BE') {
127 $this->simulateFrontendEnvironment();
128 }
129 if ($data === null) {
130 $data = $this->renderChildren();
131 }
132 $currentValue = null;
133 if (is_object($data)) {
134 $data = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getGettableProperties($data);
135 } elseif (is_string($data) || is_numeric($data)) {
136 $currentValue = (string)$data;
137 $data = [$data];
138 }
139 $this->contentObjectRenderer->start($data, $table);
140 if ($currentValue !== null) {
141 $this->contentObjectRenderer->setCurrentVal($currentValue);
142 } elseif ($currentValueKey !== null && isset($data[$currentValueKey])) {
143 $this->contentObjectRenderer->setCurrentVal($data[$currentValueKey]);
144 }
145 $pathSegments = GeneralUtility::trimExplode('.', $typoscriptObjectPath);
146 $lastSegment = array_pop($pathSegments);
147 $setup = $this->typoScriptSetup;
148 foreach ($pathSegments as $segment) {
149 if (!array_key_exists(($segment . '.'), $setup)) {
150 throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('TypoScript object path "' . htmlspecialchars($typoscriptObjectPath) . '" does not exist', 1253191023);
151 }
152 $setup = $setup[$segment . '.'];
153 }
154 $content = $this->contentObjectRenderer->cObjGetSingle($setup[$lastSegment], $setup[$lastSegment . '.']);
155 if (TYPO3_MODE === 'BE') {
156 $this->resetFrontendEnvironment();
157 }
158 return $content;
159 }
160
161 /**
162 * Sets the $TSFE->cObjectDepthCounter in Backend mode
163 * This somewhat hacky work around is currently needed because the cObjGetSingle() function of \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer relies on this setting
164 */
165 protected function simulateFrontendEnvironment()
166 {
167 $this->tsfeBackup = isset($GLOBALS['TSFE']) ? $GLOBALS['TSFE'] : null;
168 $GLOBALS['TSFE'] = new \stdClass();
169 $GLOBALS['TSFE']->cObjectDepthCounter = 100;
170 }
171
172 /**
173 * Resets $GLOBALS['TSFE'] if it was previously changed by simulateFrontendEnvironment()
174 *
175 * @see simulateFrontendEnvironment()
176 */
177 protected function resetFrontendEnvironment()
178 {
179 $GLOBALS['TSFE'] = $this->tsfeBackup;
180 }
181 }