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