Skip to content

Instantly share code, notes, and snippets.

@bwaidelich
Created November 29, 2012 12:03
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bwaidelich/4168523 to your computer and use it in GitHub Desktop.
Save bwaidelich/4168523 to your computer and use it in GitHub Desktop.
Cache View Helper for TYPO3 Fluid
Your_Package_ViewHelpers_CacheViewHelper_CacheFrontend:
frontend: TYPO3\Flow\Cache\Frontend\StringFrontend
backend: TYPO3\Flow\Cache\Backend\SimpleFileBackend
<?php
namespace Your\Package\ViewHelpers;
/* *
* This script belongs to the TYPO3 Flow package "Your.Package". *
* *
* It is free software; you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License, either version 3 *
* of the License, or (at your option) any later version. *
* *
* The TYPO3 project - inspiring people to share! *
* */
use TYPO3\Flow\Annotations as Flow;
/**
* View Helper that caches all its contents based on a specified identifier
* and some (optional) variables
*
* = Examples =
*
* <code title="Simple Cache w/o variables">
* <x:cache identifier="foo">This is cached</x:cache>
* </code>
* <output>
* This is cached
* </output>
*
* <code title="Simple Cache w/o variables">
* <x:cache identifier="foo" variables="{bar: bar}">This is cached: {bar}</x:cache>
* </code>
* <output>
* This is cached: <bar>
* // depending on {bar}
* </output>
*/
class CacheViewHelper extends \TYPO3\Fluid\Core\ViewHelper\AbstractViewHelper {
/**
* @Flow\Inject
* @var \TYPO3\Flow\Persistence\PersistenceManagerInterface
*/
protected $persistenceManager;
/**
* @Flow\Inject
* @var \TYPO3\Flow\Cache\Frontend\StringFrontend
*/
protected $cacheFrontend;
/**
* @param string $identifier unique identifier for the cache
* @param array $variables variables that affect the cache identifier
* @return string
*/
public function render($identifier, array $variables = array()) {
$cacheIdentifier = $this->buildCacheIdentifier();
if (!$this->cacheFrontend->has($cacheIdentifier)) {
$content = $this->renderChildren();
$this->cacheFrontend->set($cacheIdentifier, $content);
return $content;
}
return $this->cacheFrontend->get($cacheIdentifier);
}
/**
* @return string
*/
protected function buildCacheIdentifier() {
$variables = $this->convertObjectsToHashes($this->arguments['variables']);
\TYPO3\Flow\Utility\Arrays::sortKeysRecursively($variables);
return md5(sprintf('%s|%s', $this->arguments['identifier'], http_build_query($variables)));
}
/**
* Recursively converts objects in an array to their identifiers
*
* @param array $values the array to be processed
* @return array the modified array
* @throws \TYPO3\Fluid\Core\ViewHelper\Exception if $values contain an object and its identifier could not be determined
*/
protected function convertObjectsToHashes(array $values) {
foreach ($values as &$value) {
if (is_object($value)) {
$identifier = $this->persistenceManager->getIdentifierByObject($value);
if ($identifier === NULL) {
throw new \TYPO3\Fluid\Core\ViewHelper\Exception(sprintf('The identifier of an object of type "%s" could not be determined', get_class($value)), 1354187274);
}
$value = $identifier;
} elseif (is_array($value)) {
$value = $this->convertObjectsToHashes($value);
}
}
return $values;
}
}
?>
{namespace x=Your\Package\ViewHelpers}
<h2>non cached</h2>
<p>{now -> f:format.date(format: 'd.m.Y H:i:s')}</p>
<h2>cached (w/o invalidators)</h2>
<x:cache identifier="example1">
<p>{now -> f:format.date(format: 'd.m.Y H:i:s')}</p>
</x:cache>
<h2>cached (w invalidators)</h2>
<x:cache identifier="example2" variables="{foo: foo}">
<p>{now -> f:format.date(format: 'd.m.Y H:i:s')}</p>
</x:cache>
Your\Package\ViewHelpers\CacheViewHelper:
properties:
cacheFrontend:
object:
factoryObjectName: TYPO3\Flow\Cache\CacheManager
factoryMethodName: getCache
arguments:
1:
value: Your_Package_ViewHelpers_CacheViewHelper_CacheFrontend
@bwaidelich
Copy link
Author

I didn't find a way to avoid the manual identifier which is quite annoying (the ViewHelper instance doesn't have a unique id that survives the session).
Using the hashed raw content in addition to the variables won't work performance wise..

Ultimately, cacheable Partials/Sections are the way to go as they're unique through their path. Stay tuned

@bwaidelich
Copy link
Author

FYI: see https://review.typo3.org/#/c/16856/ for a work-in-progress of the cacheable partial implementation. Feel free to add comments on http://forge.typo3.org/issues/43457

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment