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