[TYPO3] Caching ein- oder ausschalten in Extbase?

[TYPO3] Caching ein- oder ausschalten in Extbase?

Wie kann man Extbase Ansichten eigentlich cachen oder vom Cache ausschließen? Und wann ist was überhaupt nützlich? Und wie können wir Caches automatisch leeren lassen? Das versuchen wir euch in diesem Blogpost näher zu bringen.

Caches sind etwas tolles. Diese entlasten Server und damit auch die Umwelt, sofern sie gut eingesetzt werden. Dazu kommt, dass sich auch das Ranking bei Google & Co. verbessert, wenn die Seite schnell geladen werden kann. Aber Caches sind auch manchmal ganz schön nervig. Vor allem bei der Entwicklung eines neuen Features oder wenn es eine Änderung an einem Datensatz gab, aber diese Änderung erst Tage später ersichtlicht wird.

Fangen wir am besten von vorne an. Seit der Einführung von Extbase lassen sich einzelne Views ganz einfach vom Caching ausschließen, während per Default alle Views fürs Caching vorbereitet wurden. So bald eine Ansicht cachebar ist, kann diese auch in den Suchergebnissen von typo3/cms-indexed-search gefunden oder mit Hilfe der Extension staticfilecache statisch abgelegt werden. Aber selbst ohne diese Vorteile wird die Ansicht auch so schon deutlich schneller ausgeliefert.

Gibt es jedoch eine Interaktion mit Benutzereingaben im Frontend - wenn beispielsweise ein Benutzerprofil gepflegt werden soll, oder wenn ein Filter die Ergebnisse einer Listenansicht reduzieren soll - wird ein Caching schwierig bis unmöglich. Bei einem einfachen Filter könnte man sich eventuell noch mit Links mit cHash Werten behelfen, aber bei größeren Formularen stößt man schnell an die Grenzen der Machbarkeit. Im schlimmsten Fall kann man sogar Datenschutzprobleme aufreißen, wenn beispielsweise ein Bewerbungsformular gecacht werden soll, bei einem Validierungsfehler aber dann die Werte des Vorgängers plötzlich sichtbar werden (Anmerkung vom Autor: Alles schon erlebt).
Vereinfacht kann man sich also merken, dass vor allem Detailansichten gecacht werden sollten, alle anderen Ansichten - gerade mit Interaktion der Besucher - sollte man vom Caching ausnehmen, wenn man sich unsicher ist.

Das kann dann beispielsweise so aussehen in configurePlugin() - hier wird listAction() und listAjaxAction() vom Caching ausgenommen:

\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( 'users', 'Pi1', [ \In2code\Users\Controller\UserController::class => 'list, listAjax, detail' ], [ \In2code\Users\Controller\UserController::class => 'list, listAjax' ] );

ClearCacheCmd and Cache tags

Gibt es jedoch die Möglichkeit, dass der Benutzer sein Profil im Frontend pflegen kann, soll auch gleich der Cache seiner eigenen Detailansicht verfallen. Und hier kann man wunderbar Cache Tags zum Einsatz bringen. Im nachfolgenden Beispiel werden für alle Detalansichten Tags im Cache erzeugt (Tag: tx_users_detail). Darüber hinaus auch noch individuelle Tags wie tx_users_user_123 (wobei 123 die UID des Datensatzes ist):

public function initializeDetailAction() { $cacheTags = [ 'tx_users_detail', 'tx_users_user_' . (int)$this->request->getArgument('user') ]; $tsfeController = $GLOBALS['TSFE']; if ($tsfeController !== null) { $tsfeController->addCacheTags($cacheTags); } } public function detailAction(User $user = null): void { // Detail action stuff }

Wie ihr den Cache der Detailseiten per Page TSConfig löschen könnt, sobald ein Redakteur eine Änderung im Backend (z.B. in einem Sysfolder) vornimmt, ist vielen bereits bekannt (siehe offizielle Dokumentation hierzu):

TCEMAIN.clearCacheCmd = cacheTag:tx_users_detail

Aber nun wollen wir den Cache einer einzelnen Seite löschen, sobald der Benutzer sein Profil im Frontend in einem entsprechenden Extbase-Formular geändert hat:

public function updateAction(User $user): void { $cacheManager = GeneralUtility::makeInstance(CacheManager::class); $cacheManager->flushCachesByTag('tx_users_user_' . $user->getUid()); // Update and redirect stuff }

Oder den Cache aller Detailseiten, wenn wir alle Benutzer beispielsweise nächtlich aus LDAP mit Hilfe eines Symfony command erneut importieren:

$cacheManager = GeneralUtility::makeInstance(CacheManager::class); $cacheManager->flushCachesByTag('tx_users_detail');

Übrigens: Bei der Nutzung von flushCachesByTag() werden auch statische Cachedateien gelöscht, wenn ihr die Extension staticfilecache im Einsatz habt.

Eigene Caches nutzen mit dem CacheManager

Wollt ihr Teile aus eurer ungecachten Ansicht selber cachen, könnt ihr auf den CacheManager in TYPO3 setzen. Hierzu braucht es eine Registrierung in der ext_localconf.php:

/** * Initialize cache manager configuration for EXT:users */ if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['users_filter'])) { $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['users_filter'] = []; }

Wenn ihr das FrontendInterface in eurer Klasse "injecten" wollt, so könnt ihr das in einer Configuration/Services.yaml definieren:

services: cache.users_filter: class: TYPO3\CMS\Core\Cache\Frontend\FrontendInterface factory: ['@TYPO3\CMS\Core\Cache\CacheManager', 'getCache'] arguments: ['users_filter']

Wenn man nun eine "teure" Datenbankabfrage über das Repository machen würde, kann man an Stelle dieser auch einen CacheService nutzen:

<?php declare(strict_types=1); namespace In2code\Users\Domain\Service; use In2code\Users\Utility\FrontendUtility; use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; /** * Class GetFilterObjectsService */ class GetFilterObjectsService { /** * @var FrontendInterface|null */ private ?FrontendInterface $cache = null; /** * @var array */ protected array $objects = []; /** * Cache lifetime in seconds * * @var int */ protected int $lifetime = 86400; /** * GetFilterObjectsService constructor. * @param FrontendInterface $cache */ public function __construct(FrontendInterface $cache) { $this->cache = $cache; } /** * @return array */ public function get(): array { $objectsFromCache = $this->getObjectsFromCache(); if ($objectsFromCache === []) { // Call your Repository stuff here to git your objects $objects = $this->objectRepository->findBySomething(); $this->cacheObjects($objects); return $objects; } returN $objectsFromCache; } /** * @param array $objects * @return void */ protected function cacheObjects(array $objects): void { $this->cache->set( md5(FrontendUtility::getCurrentPageIdentifier() . 'users_filter_object'), $objects, ['users_filter_object'], $this->lifetime ); } /** * @return array */ protected function getObjectsFromCache(): array { return (array)$this->cache->get( md5(FrontendUtility::getCurrentPageIdentifier() . 'users_filter_object') ); } }

Und: Die offizielle Dokumentation hierzu findet ihr wieder auf der docs.typo3.org website.

Abschließend kann ich auch nur die Erweiterung staticfilecache empfehlen. Diese kann euer TYPO3 um den Faktor 230 verschnellern. Glaubt ihr nicht? Probiert es einfach mal aus. Als Sahnehäubchen oben drauf zeigt euch die Extension in einem eigenen Backend Modul auch gleich an, welche Seiten nicht gecacht werden können. So kommt ihr groben Fehlern schneller auf die Spur.

TYPO3: Unbenutzte Dateien im fileadmin finden

Ihr wollt unbenutzte oder verwaiste Dateien im fileadmin oder einer anderen Storage löschen? Leider gibt es hier nichts direkt vom Core. Aber ein kleiner Command in eurem Sitepackage hilft schnell...

Zum Beitrag

TYPO3: Redakteure mit individuellen user_upload Folder

Vielleicht kennt ihr die Kundenanforderung? Redakteure sollen Videos über den Button "Add media by URL" hinzufügen können. Aber die Dateien sollen sich dann nicht in fileadmin/user_upload/ sondern in...

Zum Beitrag

TYPO3: Seiten im Mixed Mode finden

Mixed Mode bezeichnet man in TYPO3 übersetzte Seiten, auf denen sich Seiteninhalte befinden, die nur zum Teil eine Relation auf entsprechende Seiteninhalte in der Hauptsprache haben. Dies wird im...

Zum Beitrag

Extbase Extensions: An Erweiterbarkeit denken mit data, site und language

Heute mal eine kleine Bitte an die TYPO3-Extension-Autoren da draußen: Achtet auf Erweiterbarkeit eurer Extensions. Dies fördert dann auch die Verbreitung der entsprechenden Plugins.

Zum Beitrag

SQL: Zeige alle Tabellen absteigend nach Größe sortiert

Ich brauche in letzter Zeit häufiger den SQL-Befehl, um herauszufinden, welche Tabellen in der TYPO3-Datenbank am größten sind. Ich habe das Snippet einmal veröffentlicht.

Zum Beitrag

TYPO3 12 mit CKEditor 5: Stile als Einfachauswahl

Wenn man im RTE in TYPO3 einen Link setzt, kann es sein, dass man zwischen verschiedenen Link-Klassen auswählen muss, um beispielsweise Buttons im Frontend zu erzeugen. Neu ist in TYPO3 12 dass man...

Zum Beitrag