Revert "[CLEANUP] Rework/simplify copyright header and remove @package"
[Packages/TYPO3.CMS.git] / typo3 / sysext / fluid / Classes / View / StandaloneView.php
1 <?php
2 namespace TYPO3\CMS\Fluid\View;
3
4 /** *
5 * This script is backported from the TYPO3 Flow package "TYPO3.Fluid". *
6 * *
7 * It is free software; you can redistribute it and/or modify it under *
8 * the terms of the GNU Lesser General Public License, either version 3 *
9 * of the License, or (at your option) any later version. *
10 * *
11 * *
12 * This script is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
14 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
15 * General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with the script. *
19 * If not, see http://www.gnu.org/licenses/lgpl.html *
20 * *
21 * The TYPO3 project - inspiring people to share! *
22 * */
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24 use TYPO3\CMS\Extbase\Utility\ArrayUtility;
25 use TYPO3\CMS\Fluid\View\Exception\InvalidTemplateResourceException;
26 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
27
28 /**
29 * A standalone template view.
30 * Should be used as view if you want to use Fluid without Extbase extensions
31 *
32 * @api
33 */
34 class StandaloneView extends AbstractTemplateView {
35
36 /**
37 * Source code of the Fluid template
38 *
39 * @var string
40 */
41 protected $templateSource = NULL;
42
43 /**
44 * absolute path of the Fluid template
45 *
46 * @var string
47 */
48 protected $templatePathAndFilename = NULL;
49
50
51 /**
52 * absolute root path of the folder that contains Fluid layouts
53 *
54 * @var string
55 */
56 protected $layoutRootPath = NULL;
57
58 /**
59 * absolute root path of the folder that contains Fluid partials
60 *
61 * @var string
62 */
63 protected $partialRootPath = NULL;
64
65 /**
66 * Path(s) to the partial root
67 *
68 * @var array
69 */
70 protected $partialRootPaths = NULL;
71
72 /**
73 * Path(s) to the layout root
74 *
75 * @var array
76 */
77 protected $layoutRootPaths = NULL;
78
79 /**
80 * @var \TYPO3\CMS\Fluid\Core\Compiler\TemplateCompiler
81 */
82 protected $templateCompiler;
83
84 /**
85 * Constructor
86 *
87 * @param ContentObjectRenderer $contentObject The current cObject. If NULL a new instance will be created
88 * @throws \InvalidArgumentException
89 * @throws \UnexpectedValueException
90 */
91 public function __construct(ContentObjectRenderer $contentObject = NULL) {
92 $this->objectManager = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
93 /** @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager */
94 $configurationManager = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManagerInterface');
95 if ($contentObject === NULL) {
96 /** @var ContentObjectRenderer $contentObject */
97 $contentObject = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
98 }
99 $configurationManager->setContentObject($contentObject);
100 $this->templateParser = $this->objectManager->get('TYPO3\\CMS\\Fluid\\Core\\Parser\\TemplateParser');
101 $this->setRenderingContext($this->objectManager->get('TYPO3\\CMS\\Fluid\\Core\\Rendering\\RenderingContext'));
102 /** @var \TYPO3\CMS\Extbase\Mvc\Web\Request $request */
103 $request = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Mvc\\Web\\Request');
104 $request->setRequestURI(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'));
105 $request->setBaseURI(GeneralUtility::getIndpEnv('TYPO3_SITE_URL'));
106 /** @var \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder $uriBuilder */
107 $uriBuilder = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder');
108 $uriBuilder->setRequest($request);
109 /** @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext */
110 $controllerContext = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Mvc\\Controller\\ControllerContext');
111 $controllerContext->setRequest($request);
112 $controllerContext->setUriBuilder($uriBuilder);
113 $this->setControllerContext($controllerContext);
114 $this->templateCompiler = $this->objectManager->get('TYPO3\\CMS\\Fluid\\Core\\Compiler\\TemplateCompiler');
115 // singleton
116 $this->templateCompiler->setTemplateCache(GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('fluid_template'));
117 }
118
119 /**
120 * Sets the format of the current request (default format is "html")
121 *
122 * @param string $format
123 * @return void
124 * @api
125 */
126 public function setFormat($format) {
127 $this->getRequest()->setFormat($format);
128 }
129
130 /**
131 * Returns the format of the current request (defaults is "html")
132 *
133 * @return string $format
134 * @api
135 */
136 public function getFormat() {
137 return $this->getRequest()->getFormat();
138 }
139
140 /**
141 * Returns the current request object
142 *
143 * @return \TYPO3\CMS\Extbase\Mvc\Web\Request
144 */
145 public function getRequest() {
146 return $this->controllerContext->getRequest();
147 }
148
149 /**
150 * Sets the absolute path to a Fluid template file
151 *
152 * @param string $templatePathAndFilename Fluid template path
153 * @return void
154 * @api
155 */
156 public function setTemplatePathAndFilename($templatePathAndFilename) {
157 $this->templatePathAndFilename = $templatePathAndFilename;
158 }
159
160 /**
161 * Returns the absolute path to a Fluid template file if it was specified with setTemplatePathAndFilename() before
162 *
163 * @return string Fluid template path
164 * @api
165 */
166 public function getTemplatePathAndFilename() {
167 return $this->templatePathAndFilename;
168 }
169
170 /**
171 * Sets the Fluid template source
172 * You can use setTemplatePathAndFilename() alternatively if you only want to specify the template path
173 *
174 * @param string $templateSource Fluid template source code
175 * @return void
176 * @api
177 */
178 public function setTemplateSource($templateSource) {
179 $this->templateSource = $templateSource;
180 }
181
182 /**
183 * Set the root path to the layouts.
184 *
185 * @param string $layoutRootPath Root path to the layouts.
186 * @return void
187 * @api
188 * @see setLayoutRootPaths()
189 */
190 public function setLayoutRootPath($layoutRootPath) {
191 $this->layoutRootPath = $layoutRootPath;
192 $this->setLayoutRootPaths(array($layoutRootPath));
193 }
194
195 /**
196 * Set the root path(s) to the layouts.
197 *
198 * @param array $layoutRootPaths Root path to the layouts
199 * @return void
200 * @api
201 */
202 public function setLayoutRootPaths(array $layoutRootPaths) {
203 $this->layoutRootPaths = $layoutRootPaths;
204 }
205
206 /**
207 * Returns the first found entry in $this->layoutRootPaths.
208 * Don't use, this might not be the desired result.
209 *
210 * @throws InvalidTemplateResourceException
211 * @return string Path to layout root directory
212 */
213 public function getLayoutRootPath() {
214 $layoutRootPaths = $this->getLayoutRootPaths();
215 return array_shift($layoutRootPaths);
216 }
217
218 /**
219 * Resolves the layout root to be used inside other paths.
220 *
221 * @return string Fluid layout root path
222 * @throws InvalidTemplateResourceException
223 * @api
224 */
225 public function getLayoutRootPaths() {
226 if ($this->layoutRootPaths === NULL && $this->templatePathAndFilename === NULL) {
227 throw new InvalidTemplateResourceException('No layout root path has been specified. Use setLayoutRootPaths().', 1288091419);
228 }
229 if ($this->layoutRootPaths === NULL) {
230 $this->layoutRootPaths = array(dirname($this->templatePathAndFilename) . '/Layouts');
231 }
232 return $this->layoutRootPaths;
233 }
234
235 /**
236 * Set the root path to the partials.
237 * If set, overrides the one determined from $this->partialRootPathPattern
238 *
239 * @param string $partialRootPath Root path to the partials. If set, overrides the one determined from $this->partialRootPathPattern
240 * @return void
241 * @api
242 * @see setPartialRootPaths()
243 */
244 public function setPartialRootPath($partialRootPath) {
245 $this->partialRootPath = $partialRootPath;
246 $this->setPartialRootPaths(array($partialRootPath));
247 }
248
249 /**
250 * Returns the first found entry in $this->partialRootPaths
251 * Don't use, this might not be the desired result.
252 *
253 * @throws InvalidTemplateResourceException
254 * @return string Path to partial root directory
255 */
256 public function getPartialRootPath() {
257 $partialRootPaths = $this->getPartialRootPaths();
258 return array_shift($partialRootPaths);
259 }
260
261 /**
262 * Set the root path(s) to the partials.
263 * If set, overrides the one determined from $this->partialRootPathPattern
264 *
265 * @param array $partialRootPaths Root paths to the partials. If set, overrides the one determined from $this->partialRootPathPattern
266 * @return void
267 * @api
268 */
269 public function setPartialRootPaths(array $partialRootPaths) {
270 $this->partialRootPaths = $partialRootPaths;
271 }
272
273 /**
274 * Returns the absolute path to the folder that contains Fluid partial files
275 *
276 * @return string Fluid partial root path
277 * @throws InvalidTemplateResourceException
278 * @api
279 */
280 public function getPartialRootPaths() {
281 if ($this->partialRootPaths === NULL && $this->templatePathAndFilename === NULL) {
282 throw new InvalidTemplateResourceException('No partial root path has been specified. Use setPartialRootPaths().', 1288094511);
283 }
284 if ($this->partialRootPaths === NULL) {
285 $this->partialRootPaths = array(dirname($this->templatePathAndFilename) . '/Partials');
286 }
287 return $this->partialRootPaths;
288 }
289
290 /**
291 * Checks whether a template can be resolved for the current request
292 *
293 * @return boolean
294 * @api
295 */
296 public function hasTemplate() {
297 try {
298 $this->getTemplateSource();
299 return TRUE;
300 } catch (InvalidTemplateResourceException $e) {
301 return FALSE;
302 }
303 }
304
305 /**
306 * Returns a unique identifier for the resolved template file
307 * This identifier is based on the template path and last modification date
308 *
309 * @param string $actionName Name of the action. This argument is not used in this view!
310 * @return string template identifier
311 * @throws InvalidTemplateResourceException
312 */
313 protected function getTemplateIdentifier($actionName = NULL) {
314 if ($this->templateSource === NULL) {
315 $templatePathAndFilename = $this->getTemplatePathAndFilename();
316 $templatePathAndFilenameInfo = pathinfo($templatePathAndFilename);
317 $templateFilenameWithoutExtension = basename($templatePathAndFilename, '.' . $templatePathAndFilenameInfo['extension']);
318 $prefix = sprintf('template_file_%s', $templateFilenameWithoutExtension);
319 return $this->createIdentifierForFile($templatePathAndFilename, $prefix);
320 } else {
321 $templateSource = $this->getTemplateSource();
322 $prefix = 'template_source';
323 $templateIdentifier = sprintf('Standalone_%s_%s', $prefix, sha1($templateSource));
324 return $templateIdentifier;
325 }
326 }
327
328 /**
329 * Returns the Fluid template source code
330 *
331 * @param string $actionName Name of the action. This argument is not used in this view!
332 * @return string Fluid template source
333 * @throws InvalidTemplateResourceException
334 */
335 protected function getTemplateSource($actionName = NULL) {
336 if ($this->templateSource === NULL && $this->templatePathAndFilename === NULL) {
337 throw new InvalidTemplateResourceException('No template has been specified. Use either setTemplateSource() or setTemplatePathAndFilename().', 1288085266);
338 }
339 if ($this->templateSource === NULL) {
340 if (!is_file($this->templatePathAndFilename)) {
341 throw new InvalidTemplateResourceException('Template could not be found at "' . $this->templatePathAndFilename . '".', 1288087061);
342 }
343 $this->templateSource = file_get_contents($this->templatePathAndFilename);
344 }
345 return $this->templateSource;
346 }
347
348 /**
349 * Returns a unique identifier for the resolved layout file.
350 * This identifier is based on the template path and last modification date
351 *
352 * @param string $layoutName The name of the layout
353 * @return string layout identifier
354 * @throws InvalidTemplateResourceException
355 */
356 protected function getLayoutIdentifier($layoutName = 'Default') {
357 $layoutPathAndFilename = $this->getLayoutPathAndFilename($layoutName);
358 $prefix = 'layout_' . $layoutName;
359 return $this->createIdentifierForFile($layoutPathAndFilename, $prefix);
360 }
361
362 /**
363 * Resolves the path and file name of the layout file, based on
364 * $this->getLayoutRootPaths() and request format and returns the file contents
365 *
366 * @param string $layoutName Name of the layout to use. If none given, use "Default"
367 * @return string contents of the layout file if it was found
368 * @throws InvalidTemplateResourceException
369 */
370 protected function getLayoutSource($layoutName = 'Default') {
371 $layoutPathAndFilename = $this->getLayoutPathAndFilename($layoutName);
372 $layoutSource = file_get_contents($layoutPathAndFilename);
373 if ($layoutSource === FALSE) {
374 throw new InvalidTemplateResourceException('"' . $layoutPathAndFilename . '" is not a valid template resource URI.', 1312215888);
375 }
376 return $layoutSource;
377 }
378
379 /**
380 * Resolve the path and file name of the layout file, based on
381 * $this->getLayoutRootPaths() and request format
382 *
383 * In case a layout has already been set with setLayoutPathAndFilename(),
384 * this method returns that path, otherwise a path and filename will be
385 * resolved using the layoutPathAndFilenamePattern.
386 *
387 * @param string $layoutName Name of the layout to use. If none given, use "Default"
388 * @return string Path and filename of layout files
389 * @throws InvalidTemplateResourceException
390 */
391 protected function getLayoutPathAndFilename($layoutName = 'Default') {
392 $upperCasedLayoutName = ucfirst($layoutName);
393 $possibleLayoutPaths = array();
394 $paths = ArrayUtility::sortArrayWithIntegerKeys($this->getLayoutRootPaths());
395 $paths = array_reverse($paths, TRUE);
396 foreach ($paths as $layoutRootPath) {
397 $possibleLayoutPaths[] = GeneralUtility::fixWindowsFilePath($layoutRootPath . '/' . $upperCasedLayoutName . '.' . $this->getRequest()->getFormat());
398 $possibleLayoutPaths[] = GeneralUtility::fixWindowsFilePath($layoutRootPath . '/' . $upperCasedLayoutName);
399 if ($upperCasedLayoutName !== $layoutName) {
400 $possibleLayoutPaths[] = GeneralUtility::fixWindowsFilePath($layoutRootPath . '/' . $layoutName . '.' . $this->getRequest()->getFormat());
401 $possibleLayoutPaths[] = GeneralUtility::fixWindowsFilePath($layoutRootPath . '/' . $layoutName);
402 }
403 }
404 foreach ($possibleLayoutPaths as $layoutPathAndFilename) {
405 if ($this->testFileExistence($layoutPathAndFilename)) {
406 return $layoutPathAndFilename;
407 }
408 }
409
410 throw new InvalidTemplateResourceException('Could not load layout file. Tried following paths: "' . implode('", "', $possibleLayoutPaths) . '".', 1288092555);
411 }
412
413 /**
414 * Wrapper method for is_file function for testing reasons
415 *
416 * @param string $filePath
417 * @return bool
418 */
419 protected function testFileExistence($filePath) {
420 return is_file($filePath);
421 }
422
423 /**
424 * Returns a unique identifier for the resolved partial file.
425 * This identifier is based on the template path and last modification date
426 *
427 * @param string $partialName The name of the partial
428 * @return string partial identifier
429 * @throws InvalidTemplateResourceException
430 */
431 protected function getPartialIdentifier($partialName) {
432 $partialPathAndFilename = $this->getPartialPathAndFilename($partialName);
433 $prefix = 'partial_' . $partialName;
434 return $this->createIdentifierForFile($partialPathAndFilename, $prefix);
435 }
436
437 /**
438 * Resolves the path and file name of the partial file, based on
439 * $this->getPartialRootPath() and request format and returns the file contents
440 *
441 * @param string $partialName The name of the partial
442 * @return string contents of the layout file if it was found
443 * @throws InvalidTemplateResourceException
444 */
445 protected function getPartialSource($partialName) {
446 $partialPathAndFilename = $this->getPartialPathAndFilename($partialName);
447 $partialSource = file_get_contents($partialPathAndFilename);
448 if ($partialSource === FALSE) {
449 throw new InvalidTemplateResourceException('"' . $partialPathAndFilename . '" is not a valid template resource URI.', 1257246932);
450 }
451 return $partialSource;
452 }
453
454 /**
455 * Resolve the partial path and filename based on $this->getPartialRootPaths() and request format
456 *
457 * @param string $partialName The name of the partial
458 * @return string The full path which should be used. The path definitely exists.
459 * @throws InvalidTemplateResourceException
460 */
461 protected function getPartialPathAndFilename($partialName) {
462 $upperCasedPartialName = ucfirst($partialName);
463 $paths = ArrayUtility::sortArrayWithIntegerKeys($this->getPartialRootPaths());
464 $paths = array_reverse($paths, TRUE);
465 $possiblePartialPaths = array();
466 foreach ($paths as $partialRootPath) {
467 $possiblePartialPaths[] = GeneralUtility::fixWindowsFilePath($partialRootPath . '/' . $upperCasedPartialName . '.' . $this->getRequest()->getFormat());
468 $possiblePartialPaths[] = GeneralUtility::fixWindowsFilePath($partialRootPath . '/' . $upperCasedPartialName);
469 if ($upperCasedPartialName !== $partialName) {
470 $possiblePartialPaths[] = GeneralUtility::fixWindowsFilePath($partialRootPath . '/' . $partialName . '.' . $this->getRequest()->getFormat());
471 $possiblePartialPaths[] = GeneralUtility::fixWindowsFilePath($partialRootPath . '/' . $partialName);
472 }
473 }
474 foreach ($possiblePartialPaths as $partialPathAndFilename) {
475 if ($this->testFileExistence($partialPathAndFilename)) {
476 return $partialPathAndFilename;
477 }
478 }
479 throw new InvalidTemplateResourceException('Could not load partial file. Tried following paths: "' . implode('", "', $possiblePartialPaths) . '".', 1288092556);
480 }
481
482 /**
483 * Returns a unique identifier for the given file in the format
484 * Standalone_<prefix>_<SHA1>
485 * The SH1 hash is a checksum that is based on the file path and last modification date
486 *
487 * @param string $pathAndFilename
488 * @param string $prefix
489 * @return string
490 */
491 protected function createIdentifierForFile($pathAndFilename, $prefix) {
492 $templateModifiedTimestamp = filemtime($pathAndFilename);
493 $templateIdentifier = sprintf('Standalone_%s_%s', $prefix, sha1($pathAndFilename . '|' . $templateModifiedTimestamp));
494 $templateIdentifier = str_replace('/', '_', str_replace('.', '_', $templateIdentifier));
495 return $templateIdentifier;
496 }
497 }