Wie der Titel schon vermuten lässt, handelt es sich im folgenden Workaround schon um etwas sehr Spezielles. In einer unserer Extensions haben wir Datensätze, in denen eine GoogleMaps-Karte dargestellt wird. Mit jedem Klick auf die Karte wird ein Marker erstellt und mit Hilfe eines AJAX-Requests direkt in der Datenbank gespeichert.
Den AJAX-Request rufe ich mit Hilfe von jQuery auf und es wird die offizielle typo3/ajax.php von TYPO3 geladen. In meinem Objekt hole ich mir nun den gerade bearbeiteten Datensatz über das Repository:
$start = microtime(TRUE); $poiCollection = $this->poiCollectionRepository->findByUid($uid); echo microtime(TRUE) - $start; |
Wenn ich die URL zu dem AJAX-Request nun direkt aufrufe erscheint ein Wert von 0.30214715004 Sekunden. Ich weiß nicht wie Ihr das seht, aber um einen einzigen Datensatz zu holen, der direkt über die UID abgefragt wird, sollte nicht über eine Viertelsekunde benötigen. Schon gar nicht in AJAX-Requests.
Ich habe mich mit xdebug durch den Quellcode gehangelt und bin bei folgender Methode im Objekt Typo3QuerySettings fündig geworden:
/** @var $configurationManager \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface */ $configurationManager = $objectManager->get('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManagerInterface'); if (TYPO3_MODE === 'BE' && $configurationManager->isFeatureEnabled('ignoreAllEnableFieldsInBe')) { $this->setIgnoreEnableFields(TRUE); } |
Hier wird die Methode isFeatureEnabled() aufgerufen, um heraus zu finden, ob das Feature „ignoreAllEnableFieldsInBe“ über TypoScript aktiviert wurde oder nicht. Richtig gelesen: „TypoScript“! Um TypoScript im Backend zur Verfügung zu stellen, müssen schon ein paar Hebel bewegt werden. Zumindest ist das der Grund, warum die Abfrage so lange dauert. Die Frage ist jetzt: Wie kann ich es verhindern oder zumindest umgehen, dass dieser riesige Overhead an TypoScript geladen wird?
Ich habe mir dazu die getConfiguration() angeschaut:
public function getConfiguration($extensionName = NULL, $pluginName = NULL) { // 1st level cache $configurationCacheKey = strtolower(($extensionName ?: $this->extensionName) . '_' . ($pluginName ?: $this->pluginName)); if (isset($this->configurationCache[$configurationCacheKey])) { return $this->configurationCache[$configurationCacheKey]; } $frameworkConfiguration = $this->getExtbaseConfiguration(); ... |
Hey cool. Da gibt es einen ConfigurationsCache, aber leider ist dieser als „protected“ deklariert. Ein eigenes Configurations-Objekt wollte ich mir jetzt nicht bauen und habe ein paar Nachforschungen im Extbase-Quellcode durchgeführt und die Methode setProperty im ObjektAccess gefunden. Dort sieht man wie ihr als protected deklarierte Eigenschaften trotzdem direkt befüllen könnt ($forceDirectAccess) und genau das habe ich mir zu Nutze gemacht.
Zurück in meinem Ajax-Objekt injecte ich mir jetzt den BackendConfigurationCache:
/** * @var \TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager * @inject */ protected $backendConfigurationManager; |
Und mit Hilfe der initializeObject()-Methode, die beim Instanziieren eines Objekte immer zuvor aufgerufen wird, verwende ich das Beispiel aus dem ObjectAccess und setze die benötigte Konfiguration manuell:
/** * In Typo3QuerySettings is a feature check which loads whole TS which needs about 250ms * With this workaround I modify the 1st level cache of configuration manager * * @return void */ public function initializeObject() { // set minimal configuration $configuration = array(); $configuration['_']['features']['ignoreAllEnableFieldsInBe'] = 0; // transport our minimal configuration into backendConfigurationManagers 1st-level Cache if (property_exists(get_class($this->backendConfigurationManager), 'configurationCache')) { $propertyReflection = new \TYPO3\CMS\Extbase\Reflection\PropertyReflection(get_class($this->backendConfigurationManager), 'configurationCache'); $propertyReflection->setAccessible(TRUE); $propertyReflection->setValue($this->backendConfigurationManager, $configuration); } } |
Ich gebe zu: Dieser Weg ist echt schräg und bestimmt nicht StateOfTheArt, aber als Messergebnis erhalte ich nun einen Wert von gerade mal: 0.0470860004425 Sekunden. Über das 6-fache an Performance.