[BUGFIX] Standalone- and TemplateView must not require ucfirst file names
[Packages/TYPO3.CMS.git] / typo3 / sysext / fluid / Classes / View / TemplateView.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 * The TYPO3 project - inspiring people to share! *
12 * */
13
14 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
15 use TYPO3\CMS\Core\Utility\GeneralUtility;
16 use TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext;
17 use TYPO3\CMS\Extbase\Object\ObjectManager;
18 use TYPO3\CMS\Fluid\Compatibility\TemplateParserBuilder;
19 use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
20 use TYPO3\CMS\Fluid\Fluid;
21
22 /**
23 * The main template view. Should be used as view if you want Fluid Templating
24 *
25 * @api
26 */
27 class TemplateView extends AbstractTemplateView {
28
29 /**
30 * Pattern to be resolved for "@templateRoot" in the other patterns.
31 * Following placeholders are supported:
32 * - "@packageResourcesPath"
33 *
34 * @var string
35 */
36 protected $templateRootPathPattern = '@packageResourcesPath/Private/Templates';
37
38 /**
39 * Pattern to be resolved for "@partialRoot" in the other patterns.
40 * Following placeholders are supported:
41 * - "@packageResourcesPath"
42 *
43 * @var string
44 */
45 protected $partialRootPathPattern = '@packageResourcesPath/Private/Partials';
46
47 /**
48 * Pattern to be resolved for "@layoutRoot" in the other patterns.
49 * Following placeholders are supported:
50 * - "@packageResourcesPath"
51 *
52 * @var string
53 */
54 protected $layoutRootPathPattern = '@packageResourcesPath/Private/Layouts';
55
56 /**
57 * Path(s) to the template root. If NULL, then $this->templateRootPathPattern will be used.
58 *
59 * @var array
60 */
61 protected $templateRootPaths = NULL;
62
63 /**
64 * Path(s) to the partial root. If NULL, then $this->partialRootPathPattern will be used.
65 *
66 * @var array
67 */
68 protected $partialRootPaths = NULL;
69
70 /**
71 * Path(s) to the layout root. If NULL, then $this->layoutRootPathPattern will be used.
72 *
73 * @var array
74 */
75 protected $layoutRootPaths = NULL;
76
77 /**
78 * File pattern for resolving the template file
79 * Following placeholders are supported:
80 * - "@templateRoot"
81 * - "@partialRoot"
82 * - "@layoutRoot"
83 * - "@subpackage"
84 * - "@action"
85 * - "@format"
86 *
87 * @var string
88 */
89 protected $templatePathAndFilenamePattern = '@templateRoot/@subpackage/@controller/@action.@format';
90
91 /**
92 * Directory pattern for global partials. Not part of the public API, should not be changed for now.
93 * Following placeholders are supported:
94 * - "@templateRoot"
95 * - "@partialRoot"
96 * - "@layoutRoot"
97 * - "@subpackage"
98 * - "@partial"
99 * - "@format"
100 *
101 * @var string
102 */
103 private $partialPathAndFilenamePattern = '@partialRoot/@subpackage/@partial.@format';
104
105 /**
106 * File pattern for resolving the layout
107 * Following placeholders are supported:
108 * - "@templateRoot"
109 * - "@partialRoot"
110 * - "@layoutRoot"
111 * - "@subpackage"
112 * - "@layout"
113 * - "@format"
114 *
115 * @var string
116 */
117 protected $layoutPathAndFilenamePattern = '@layoutRoot/@layout.@format';
118
119 /**
120 * Path and filename of the template file. If set, overrides the templatePathAndFilenamePattern
121 *
122 * @var string
123 */
124 protected $templatePathAndFilename = NULL;
125
126 /**
127 * Path and filename of the layout file. If set, overrides the layoutPathAndFilenamePattern
128 *
129 * @var string
130 */
131 protected $layoutPathAndFilename = NULL;
132
133 /**
134 * Constructor
135 */
136 public function __construct() {
137 $this->templateParser = TemplateParserBuilder::build();
138 $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);
139 $this->setRenderingContext($this->objectManager->get(RenderingContextInterface::class));
140 }
141
142 /**
143 * Init view
144 */
145 public function initializeView() {
146 }
147 // Here, the backporter can insert a constructor method, which is needed for the TYPO3 CMS extension
148
149 /**
150 * Sets the path and name of of the template file. Effectively overrides the
151 * dynamic resolving of a template file.
152 *
153 * @param string $templatePathAndFilename Template file path
154 * @return void
155 * @api
156 */
157 public function setTemplatePathAndFilename($templatePathAndFilename) {
158 $this->templatePathAndFilename = $templatePathAndFilename;
159 }
160
161 /**
162 * Sets the path and name of the layout file. Overrides the dynamic resolving of the layout file.
163 *
164 * @param string $layoutPathAndFilename Path and filename of the layout file
165 * @return void
166 * @api
167 */
168 public function setLayoutPathAndFilename($layoutPathAndFilename) {
169 $this->layoutPathAndFilename = $layoutPathAndFilename;
170 }
171
172 /**
173 * Set the root path to the templates.
174 * If set, overrides the one determined from $this->templateRootPathPattern
175 *
176 * @param string $templateRootPath Root path to the templates. If set, overrides the one determined from $this->templateRootPathPattern
177 * @return void
178 * @api
179 * @see setTemplateRootPaths()
180 */
181 public function setTemplateRootPath($templateRootPath) {
182 $this->setTemplateRootPaths(array($templateRootPath));
183 }
184
185 /**
186 * Resolves the template root to be used inside other paths.
187 *
188 * @return array Path(s) to template root directory
189 */
190 public function getTemplateRootPaths() {
191 if ($this->templateRootPaths !== NULL) {
192 return $this->templateRootPaths;
193 }
194 /** @var $actionRequest \TYPO3\CMS\Extbase\Mvc\Request */
195 $actionRequest = $this->controllerContext->getRequest();
196 return array(str_replace('@packageResourcesPath', ExtensionManagementUtility::extPath($actionRequest->getControllerExtensionKey()) . 'Resources/', $this->templateRootPathPattern));
197 }
198
199 /**
200 * Set the root path(s) to the templates.
201 * If set, overrides the one determined from $this->templateRootPathPattern
202 *
203 * @param array $templateRootPaths Root path(s) to the templates. If set, overrides the one determined from $this->templateRootPathPattern
204 * @return void
205 * @api
206 */
207 public function setTemplateRootPaths(array $templateRootPaths) {
208 $this->templateRootPaths = $templateRootPaths;
209 }
210
211 /**
212 * Set the root path to the partials.
213 * If set, overrides the one determined from $this->partialRootPathPattern
214 *
215 * @param string $partialRootPath Root path to the partials. If set, overrides the one determined from $this->partialRootPathPattern
216 * @return void
217 * @api
218 * @see setPartialRootPaths()
219 */
220 public function setPartialRootPath($partialRootPath) {
221 $this->setPartialRootPaths(array($partialRootPath));
222 }
223
224 /**
225 * Set the root path(s) to the partials.
226 * If set, overrides the one determined from $this->partialRootPathPattern
227 *
228 * @param array $partialRootPaths Root paths to the partials. If set, overrides the one determined from $this->partialRootPathPattern
229 * @return void
230 * @api
231 */
232 public function setPartialRootPaths(array $partialRootPaths) {
233 $this->partialRootPaths = $partialRootPaths;
234 }
235
236 /**
237 * Resolves the partial root to be used inside other paths.
238 *
239 * @return array Path(s) to partial root directory
240 */
241 protected function getPartialRootPaths() {
242 if ($this->partialRootPaths !== NULL) {
243 return $this->partialRootPaths;
244 }
245 /** @var $actionRequest \TYPO3\CMS\Extbase\Mvc\Request */
246 $actionRequest = $this->controllerContext->getRequest();
247 return array(str_replace('@packageResourcesPath', ExtensionManagementUtility::extPath($actionRequest->getControllerExtensionKey()) . 'Resources/', $this->partialRootPathPattern));
248 }
249
250 /**
251 * Set the root path to the layouts.
252 * If set, overrides the one determined from $this->layoutRootPathPattern
253 *
254 * @param string $layoutRootPath Root path to the layouts. If set, overrides the one determined from $this->layoutRootPathPattern
255 * @return void
256 * @api
257 * @see setLayoutRootPaths()
258 */
259 public function setLayoutRootPath($layoutRootPath) {
260 $this->setLayoutRootPaths(array($layoutRootPath));
261 }
262
263 /**
264 * Set the root path(s) to the layouts.
265 * If set, overrides the one determined from $this->layoutRootPathPattern
266 *
267 * @param array $layoutRootPaths Root path to the layouts. If set, overrides the one determined from $this->layoutRootPathPattern
268 * @return void
269 * @api
270 */
271 public function setLayoutRootPaths(array $layoutRootPaths) {
272 $this->layoutRootPaths = $layoutRootPaths;
273 }
274
275 /**
276 * Resolves the layout root to be used inside other paths.
277 *
278 * @return string Path(s) to layout root directory
279 */
280 protected function getLayoutRootPaths() {
281 if ($this->layoutRootPaths !== NULL) {
282 return $this->layoutRootPaths;
283 }
284 /** @var $actionRequest \TYPO3\CMS\Extbase\Mvc\Request */
285 $actionRequest = $this->controllerContext->getRequest();
286 return array(str_replace('@packageResourcesPath', ExtensionManagementUtility::extPath($actionRequest->getControllerExtensionKey()) . 'Resources/', $this->layoutRootPathPattern));
287 }
288
289 /**
290 * Returns a unique identifier for the resolved template file
291 * This identifier is based on the template path and last modification date
292 *
293 * @param string $actionName Name of the action. If NULL, will be taken from request.
294 * @return string template identifier
295 */
296 protected function getTemplateIdentifier($actionName = NULL) {
297 $templatePathAndFilename = $this->getTemplatePathAndFilename($actionName);
298 if ($actionName === NULL) {
299 /** @var $actionRequest \TYPO3\CMS\Extbase\Mvc\Request */
300 $actionRequest = $this->controllerContext->getRequest();
301 $actionName = $actionRequest->getControllerActionName();
302 }
303 $prefix = 'action_' . $actionName;
304 return $this->createIdentifierForFile($templatePathAndFilename, $prefix);
305 }
306
307 /**
308 * Resolve the template path and filename for the given action. If $actionName
309 * is NULL, looks into the current request.
310 *
311 * @param string $actionName Name of the action. If NULL, will be taken from request.
312 * @return string Full path to template
313 * @throws Exception\InvalidTemplateResourceException
314 */
315 protected function getTemplateSource($actionName = NULL) {
316 $templatePathAndFilename = $this->getTemplatePathAndFilename($actionName);
317 $templateSource = file_get_contents($templatePathAndFilename);
318 if ($templateSource === FALSE) {
319 throw new Exception\InvalidTemplateResourceException('"' . $templatePathAndFilename . '" is not a valid template resource URI.', 1257246929);
320 }
321 return $templateSource;
322 }
323
324 /**
325 * Resolve the template path and filename for the given action. If $actionName
326 * is NULL, looks into the current request.
327 *
328 * @param string $actionName Name of the action. If NULL, will be taken from request.
329 * @return string Full path to template
330 * @throws Exception\InvalidTemplateResourceException
331 */
332 protected function getTemplatePathAndFilename($actionName = NULL) {
333 if ($this->templatePathAndFilename !== NULL) {
334 return $this->resolveFileNamePath($this->templatePathAndFilename);
335 }
336 if ($actionName === NULL) {
337 /** @var $actionRequest \TYPO3\CMS\Extbase\Mvc\Request */
338 $actionRequest = $this->controllerContext->getRequest();
339 $actionName = $actionRequest->getControllerActionName();
340 }
341
342 $paths = $this->expandGenericPathPattern($this->templatePathAndFilenamePattern, FALSE, FALSE);
343 $possibleFileNames = $this->buildListOfTemplateCandidates($actionName, $paths, '@action');
344 foreach ($possibleFileNames as $templatePathAndFilename) {
345 if ($this->testFileExistence($templatePathAndFilename)) {
346 return $templatePathAndFilename;
347 }
348 }
349 throw new Exception\InvalidTemplateResourceException('Template could not be loaded. I tried "' . implode('", "', $possibleFileNames) . '"', 1225709595);
350 }
351
352 /**
353 * Returns a unique identifier for the resolved layout file.
354 * This identifier is based on the template path and last modification date
355 *
356 * @param string $layoutName The name of the layout
357 * @return string layout identifier
358 */
359 protected function getLayoutIdentifier($layoutName = 'Default') {
360 $layoutPathAndFilename = $this->getLayoutPathAndFilename($layoutName);
361 $prefix = 'layout_' . $layoutName;
362 return $this->createIdentifierForFile($layoutPathAndFilename, $prefix);
363 }
364
365 /**
366 * Resolve the path and file name of the layout file, based on
367 * $this->layoutPathAndFilename and $this->layoutPathAndFilenamePattern.
368 *
369 * In case a layout has already been set with setLayoutPathAndFilename(),
370 * this method returns that path, otherwise a path and filename will be
371 * resolved using the layoutPathAndFilenamePattern.
372 *
373 * @param string $layoutName Name of the layout to use. If none given, use "Default"
374 * @return string contents of the layout template
375 * @throws Exception\InvalidTemplateResourceException
376 */
377 protected function getLayoutSource($layoutName = 'Default') {
378 $layoutPathAndFilename = $this->getLayoutPathAndFilename($layoutName);
379 $layoutSource = file_get_contents($layoutPathAndFilename);
380 if ($layoutSource === FALSE) {
381 throw new Exception\InvalidTemplateResourceException('"' . $layoutPathAndFilename . '" is not a valid template resource URI.', 1257246930);
382 }
383 return $layoutSource;
384 }
385
386 /**
387 * Resolve the path and file name of the layout file, based on
388 * $this->layoutPathAndFilename and $this->layoutPathAndFilenamePattern.
389 *
390 * In case a layout has already been set with setLayoutPathAndFilename(),
391 * this method returns that path, otherwise a path and filename will be
392 * resolved using the layoutPathAndFilenamePattern.
393 *
394 * @param string $layoutName Name of the layout to use. If none given, use "Default"
395 * @return string Path and filename of layout files
396 * @throws Exception\InvalidTemplateResourceException
397 */
398 protected function getLayoutPathAndFilename($layoutName = 'Default') {
399 if ($this->layoutPathAndFilename !== NULL) {
400 return $this->resolveFileNamePath($this->layoutPathAndFilename);
401 }
402 $paths = $this->expandGenericPathPattern($this->layoutPathAndFilenamePattern, TRUE, TRUE);
403 $possibleFileNames = $this->buildListOfTemplateCandidates($layoutName, $paths, '@layout');
404 foreach ($possibleFileNames as $layoutPathAndFilename) {
405 if ($this->testFileExistence($layoutPathAndFilename)) {
406 return $layoutPathAndFilename;
407 }
408 }
409 throw new Exception\InvalidTemplateResourceException('The layout files "' . implode('", "', $possibleFileNames) . '" could not be loaded.', 1225709596);
410 }
411
412 /**
413 * Returns a unique identifier for the resolved partial file.
414 * This identifier is based on the template path and last modification date
415 *
416 * @param string $partialName The name of the partial
417 * @return string partial identifier
418 */
419 protected function getPartialIdentifier($partialName) {
420 $partialPathAndFilename = $this->getPartialPathAndFilename($partialName);
421 $prefix = 'partial_' . $partialName;
422 return $this->createIdentifierForFile($partialPathAndFilename, $prefix);
423 }
424
425 /**
426 * Figures out which partial to use.
427 *
428 * @param string $partialName The name of the partial
429 * @return string contents of the partial template
430 * @throws Exception\InvalidTemplateResourceException
431 */
432 protected function getPartialSource($partialName) {
433 $partialPathAndFilename = $this->getPartialPathAndFilename($partialName);
434 $partialSource = file_get_contents($partialPathAndFilename);
435 if ($partialSource === FALSE) {
436 throw new Exception\InvalidTemplateResourceException('"' . $partialPathAndFilename . '" is not a valid template resource URI.', 1257246931);
437 }
438 return $partialSource;
439 }
440
441 /**
442 * Resolve the partial path and filename based on $this->partialPathAndFilenamePattern.
443 *
444 * @param string $partialName The name of the partial
445 * @return string the full path which should be used. The path definitely exists.
446 * @throws Exception\InvalidTemplateResourceException
447 */
448 protected function getPartialPathAndFilename($partialName) {
449 $paths = $this->expandGenericPathPattern($this->partialPathAndFilenamePattern, TRUE, TRUE);
450 $possibleFileNames = $this->buildListOfTemplateCandidates($partialName, $paths, '@partial');
451 foreach ($possibleFileNames as $partialPathAndFilename) {
452 if ($this->testFileExistence($partialPathAndFilename)) {
453 return $partialPathAndFilename;
454 }
455 }
456 throw new Exception\InvalidTemplateResourceException('The partial files "' . implode('", "', $possibleFileNames) . '" could not be loaded.', 1225709597);
457 }
458
459 /**
460 * Builds a list of possible candidates for a given template name
461 *
462 * @param string $templateName
463 * @param array $paths Paths to search in
464 * @param string $marker Marker to replace in the $templateName
465 * @return array Array of paths to search for the template file
466 */
467 protected function buildListOfTemplateCandidates($templateName, $paths, $marker) {
468 $upperCasedTemplateName = $this->ucFileNameInPath($templateName);
469 $possibleFileNames = array();
470 foreach ($paths as $partialPathAndFilename) {
471 $possibleFileNames[] = $this->resolveFileNamePath(str_replace($marker, $upperCasedTemplateName, $partialPathAndFilename));
472 if ($templateName !== $upperCasedTemplateName) {
473 $possibleFileNames[] = $this->resolveFileNamePath(str_replace($marker, $templateName, $partialPathAndFilename));
474 }
475 }
476 return $possibleFileNames;
477 }
478
479 /**
480 * Checks whether a template can be resolved for the current request context.
481 *
482 * @param ControllerContext $controllerContext Controller context which is available inside the view
483 * @return bool
484 * @api
485 */
486 public function canRender(ControllerContext $controllerContext) {
487 $this->setControllerContext($controllerContext);
488 try {
489 $this->getTemplateSource();
490 return TRUE;
491 } catch (Exception\InvalidTemplateResourceException $e) {
492 return FALSE;
493 }
494 }
495
496 /**
497 * Processes following placeholders inside $pattern:
498 * - "@templateRoot"
499 * - "@partialRoot"
500 * - "@layoutRoot"
501 * - "@subpackage"
502 * - "@controller"
503 * - "@format"
504 *
505 * This method is used to generate "fallback chains" for file system locations where a certain Partial can reside.
506 *
507 * If $bubbleControllerAndSubpackage is FALSE and $formatIsOptional is FALSE, then the resulting array will only have one element
508 * with all the above placeholders replaced.
509 *
510 * If you set $bubbleControllerAndSubpackage to TRUE, then you will get an array with potentially many elements:
511 * The first element of the array is like above. The second element has the @ controller part set to "" (the empty string)
512 * The third element now has the @ controller part again stripped off, and has the last subpackage part stripped off as well.
513 * This continues until both "@subpackage" and "@controller" are empty.
514 *
515 * Example for $bubbleControllerAndSubpackage is TRUE, we have the Tx_MyExtension_MySubPackage_Controller_MyController
516 * as Controller Object Name and the current format is "html"
517 *
518 * If pattern is "@templateRoot/@subpackage/@controller/@action.@format", then the resulting array is:
519 * - "Resources/Private/Templates/MySubPackage/My/@action.html"
520 * - "Resources/Private/Templates/MySubPackage/@action.html"
521 * - "Resources/Private/Templates/@action.html"
522 *
523 * If you set $formatIsOptional to TRUE, then for any of the above arrays, every element will be duplicated - once with "@format"
524 * replaced by the current request format, and once with ."@format" stripped off.
525 *
526 * @param string $pattern Pattern to be resolved
527 * @param bool $bubbleControllerAndSubpackage if TRUE, then we successively split off parts from "@controller" and "@subpackage" until both are empty.
528 * @param bool $formatIsOptional if TRUE, then half of the resulting strings will have ."@format" stripped off, and the other half will have it.
529 * @return array unix style paths
530 */
531 protected function expandGenericPathPattern($pattern, $bubbleControllerAndSubpackage, $formatIsOptional) {
532 $paths = array($pattern);
533 $this->expandPatterns($paths, '@templateRoot', $this->getTemplateRootPaths());
534 $this->expandPatterns($paths, '@partialRoot', $this->getPartialRootPaths());
535 $this->expandPatterns($paths, '@layoutRoot', $this->getLayoutRootPaths());
536
537 /** @var $actionRequest \TYPO3\CMS\Extbase\Mvc\Request */
538 $actionRequest = $this->controllerContext->getRequest();
539 $subpackageKey = $actionRequest->getControllerSubpackageKey();
540 $controllerName = $actionRequest->getControllerName();
541 if ($subpackageKey !== NULL) {
542 if (strpos($subpackageKey, Fluid::NAMESPACE_SEPARATOR) !== FALSE) {
543 $namespaceSeparator = Fluid::NAMESPACE_SEPARATOR;
544 } else {
545 $namespaceSeparator = Fluid::LEGACY_NAMESPACE_SEPARATOR;
546 }
547 $subpackageKeyParts = explode($namespaceSeparator, $subpackageKey);
548 } else {
549 $subpackageKeyParts = array();
550 }
551 if ($bubbleControllerAndSubpackage) {
552 $numberOfPathsBeforeSubpackageExpansion = count($paths);
553 $numberOfSubpackageParts = count($subpackageKeyParts);
554 $subpackageReplacements = array();
555 for ($i = 0; $i <= $numberOfSubpackageParts; $i++) {
556 $subpackageReplacements[] = implode('/', ($i < 0 ? $subpackageKeyParts : array_slice($subpackageKeyParts, $i)));
557 }
558 $this->expandPatterns($paths, '@subpackage', $subpackageReplacements);
559
560 for ($i = ($numberOfPathsBeforeSubpackageExpansion - 1) * ($numberOfSubpackageParts + 1); $i >= 0; $i -= ($numberOfSubpackageParts + 1)) {
561 array_splice($paths, $i, 0, str_replace('@controller', $controllerName, $paths[$i]));
562 }
563 $this->expandPatterns($paths, '@controller', array(''));
564 } else {
565 $i = $controllerName === NULL ? 0 : -1;
566 $this->expandPatterns($paths, '@subpackage', array(implode('/', $i < 0 ? $subpackageKeyParts :
567 array_slice($subpackageKeyParts, $i))));
568 $this->expandPatterns($paths, '@controller', array($controllerName));
569 }
570
571 if ($formatIsOptional) {
572 $this->expandPatterns($paths, '.@format', array('.' . $actionRequest->getFormat(), ''));
573 $this->expandPatterns($paths, '@format', array($actionRequest->getFormat(), ''));
574 } else {
575 $this->expandPatterns($paths, '.@format', array('.' . $actionRequest->getFormat()));
576 $this->expandPatterns($paths, '@format', array($actionRequest->getFormat()));
577 }
578 return array_values(array_unique($paths));
579 }
580
581 /**
582 * Expands the given $patterns by adding an array element for each $replacement
583 * replacing occurrences of $search.
584 *
585 * @param array $patterns
586 * @param string $search
587 * @param array $replacements
588 * @return void
589 */
590 protected function expandPatterns(array &$patterns, $search, array $replacements) {
591 $patternsWithReplacements = array();
592 foreach ($patterns as $pattern) {
593 foreach ($replacements as $replacement) {
594 $patternsWithReplacements[] = GeneralUtility::fixWindowsFilePath(str_replace($search, $replacement, $pattern));
595 }
596 }
597 $patterns = $patternsWithReplacements;
598 }
599
600 /**
601 * Returns a unique identifier for the given file in the format
602 * <PackageKey>_<SubPackageKey>_<ControllerName>_<prefix>_<SHA1>
603 * The SH1 hash is a checksum that is based on the file path and last modification date
604 *
605 * @param string $pathAndFilename
606 * @param string $prefix
607 * @return string
608 */
609 protected function createIdentifierForFile($pathAndFilename, $prefix) {
610 /** @var $actionRequest \TYPO3\CMS\Extbase\Mvc\Request */
611 $actionRequest = $this->controllerContext->getRequest();
612 $extensionName = $actionRequest->getControllerExtensionName();
613 $subPackageKey = $actionRequest->getControllerSubpackageKey();
614 if ($subPackageKey !== NULL) {
615 $extensionName .= '_' . $subPackageKey;
616 }
617 $controllerName = $actionRequest->getControllerName();
618 $templateModifiedTimestamp = filemtime($pathAndFilename);
619 $templateIdentifier = sprintf('%s_%s_%s_%s', $extensionName, $controllerName, $prefix, sha1($pathAndFilename . '|' . $templateModifiedTimestamp));
620 return $templateIdentifier;
621 }
622
623 /**
624 * Wrapper method to make the static call to GeneralUtility mockable in tests
625 *
626 * @param string $pathAndFilename
627 *
628 * @return string absolute pathAndFilename
629 */
630 protected function resolveFileNamePath($pathAndFilename) {
631 return GeneralUtility::getFileAbsFileName(GeneralUtility::fixWindowsFilePath($pathAndFilename), TRUE);
632 }
633
634 }