Caching Framework: automatisch Cache leeren bei Datensatzänderung

Das Caching Framework lässt sich gut verwenden, um aufwändig generierte/abgefragte Daten zur Wiederverwendung schneller parat zu haben. Die prinzipielle Funktionsweise haben wir in „Caching Framework nutzen“ erklärt und findet sich auch in der Doku sowie in zahlreichen anderen Blogs.
Was aber oftmals fehlt: wie aktualisiert man den Cache bzw. invalidert ihn bei Veränderung der Daten?

Häufig hängt der Inhalt des Caches von Datensätzen ab. D.h. der Cache-Inhalt veraltet, wenn sich ein Datensatz verändert. Und damit ist auch der Ansatzpunkt für die Invalidierung klar: der processDatamap_afterDatabaseOperations-Hook im DataHandler. Er wird immer nach Datenbankoperationen („new“ bzw. „update“) aufgerufen und bekommt auch den Taballennamen mit übergeben. Somit ist es recht einfach, die eigenen Datensätze zu erkennen und auf die Veränderung zu reagieren:

EXT:my_extension/Classes/Hooks/DataHandler.php:

<?php
namespace MyVendorName\MyExtension\Hooks;

use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class DataHandler
{
    public function processDatamap_afterDatabaseOperations($status, $tableName, $recordId, array $databaseData, \TYPO3\CMS\Core\DataHandling\DataHandler $dataHandler)
    {
        if ($tableName === 'tx_myextension_domain_model_example') {
            $cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('myCache');
            $cache->flushByTag('tag_123');
        }
    }
}

Dann noch am Hook registrieren, und fertig:

EXT:my_extension/ext_localconf.php

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['myextension_clearcfcache'] = 'MyVendorName\\MyExtension\\Hooks\\DataHandler';

Links

Template-Pfade via Flexform setzen

Früher war alles so einfach… Für Plugins konnte einfach in einem Flexform-Feld eine Template-Datei angegeben werden, und schwupps war die via TypoScript gesetzte Datei für dieses eine Content-Element überschrieben. Das wohl bekannteste Beispiel hierfür ist die Extension News (tt_news).

Die Zeiten haben sich geändert. Mit Extbase/Fluid ist Vieles flexibler und einfacher geworden: wir können Dank Partials HTML-Schnipsel wiederverwenden, können Dank der Overrides Kaskaden für Template-Pfade in TypoScript festlegen – aber wie kann gelöst werden, dass ein einzelnes Content-Element ein anderes Template bekommen soll?

Weiterlesen

Query debuggen mit Extbase

Eine Abfrage ans Repository bleibt leer? Aber warum? Welcher Parameter in der Abfrage führte zum leeren Ergebnis?

Leider erhält man nicht so rasch die SQL-Query, die hier abgefeuert wurde. Aber mit einem kleinen Eingriff wird man doch schlauer: folgenden Schnipsel vor dem $query->execute(); einfügen:

/** @var Typo3DbQueryParser $queryParser */
$queryParser = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Storage\\Typo3DbQueryParser');
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->parseQuery($query));

Update 2017-12-06

In TYPO3 8.x ist durch die Integration von Doctrine der Aufruf etwas anders

$queryParser = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class);
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->convertQueryToDoctrineQueryBuilder($query)->getSQL());

 

Quellen:

Entwicklungshilfe seit TYPO3 6.0

TYPO3 hat zwei kleine Gemeinheiten in sich, die einem manchmal das Leben erschweren:

  • zum einen den Cache (bzw. inzwischen die Caches),
  • zum anderen seine Verschwiegenheit über genauere Fehlerursachen (in produktiven Umgebungen).

Ersteres lässt sich v.a. während der Extbase-basierten Entwicklung (neben altbekannten TypoScript-Einstellungen) über eine Änderung am CachingFramework lösen. Denn nach Änderungen im Model bzw. in den Annotationen im Controller oder Repository entstehen  Fehlermeldungen oftmals durch veraltete Einträge im Reflection Cache von Extbase, welcher Modelproperties und Annotationen speichert.

Die Verschwiegenheit bei Fehlern lässt sich mit einer Reihe von Schaltern beheben, sodass TYPO3 sehr auskunftfreudig wird.

Weiterlesen

TYPO3 6.x – Mails mit Anhängen

Das prinzipielle Vorgehen zum Versand von Mails über die „neue“ Mail-API von TYPO3 hatte Jigal dereinst schön im Artikel „New mail API for the core“ erklärt.

Etwas tricky wird es in TYPO3 6.x durch die Einführung der Namespaces. Denn TYPO3 erweitert nur einige Klasse des Swiftmailers, nicht aber alle. Somit bewegen sich viele Aufrufe innerhalb der TYPO3-Namespaces (z.B. TYPO3\CMS\Core\Mail), während andere Klassen- und Methodenaufrufe kläglich scheitern, weil die Swiftmailer-Klassen nicht gefunden werden (z.B. Swift_Attachment::fromPath($path)).

Lösung

Die Lösung des Problems ist eigentlich ganz trivial: aus der eigenen (namespace-behafteten) Extension einfach wieder in den globalen Namespace wechseln, indem vor alle Swiftmailer-eigenen Klassen ein Backslash gesetzt wird.

$mail = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Mail\\MailMessage');
$mail->setFrom(array($senderEmail => $senderName));
$mail->setTo(array($receiverEmail => $receiverName));
$mail->setSubject($subject);
$mail->setBody($body, 'text/html');

$attachment = \Swift_Attachment::fromPath($imgPath, 'image/jpeg');
$mail->attach($attachment);

$mail->send();

Quellen

  1. buzz.typo3.org: New mail API for the core (als PDF-Backup)
  2. [FLOW3-general] Swift Mailer Attachment (als PDF-Backup)

Caching Framework nutzen

Für umfangreichere Datenkonstrukte, die häufig verwendet werden oder aber aufwändig zu erzeugen sind, ist ein Cache nützlich. Ein typischer Fall sind Dateilisten, die sich auf Verzeichnissen generieren (z.B. für eine einfache Bildergalerie). Die Inhalte der Verzeichnisse ändern sich meist nur extrem selten – wozu also immer wieder aufs Neue via Dateisystem auslesen, welche Dateien existieren? Hier ist es doch naheliegender, die Liste zu cachen und nur selten oder gar nur via gezielter Anforderung zu aktalisieren.
Einen von vielen Fällen, wo das Caching Framework in einer eigenen Extension zum Einsatz kommen kann…

Weiterlesen