03.05.2012

Using of TYPO3 caching framework in CLI

When using TYPO3-CLI or some TYPO3-independent processing, the frontend cache needs sometimes to be cleared.

Without using the caching framework, caches can be deleted directly in the database tables cache_pages, cache_pagesection and if needed, cache_hash.

When using the caching framework, such as memcache or redis, we can not clear the cache directly in the database, we need to take another way to achieve this. The solution is simple - we need to initialize the TYPO3 caching framework and its frontend-caches. For TYPO3-CLI we don't need this step, because localconf.php is loaded and framework is initialised automatically, but for processing out of TYPO3 environment we must load the configuration first (usually by inclusion of localconf.php). Then we don't need to take care about the configuration or the type of cache, everythig is done by the caching framework.

But how is it done?

You can find the answer in the t3lib_cache library, which uses the cache manager and the cache factory to initialize the framework and the default frontend caches (page, pagesection and content hash). By using this class we have an initialized framework and we can use all the features the caching framework supplies.

In the following example is in CLI mode the caching framework in localconf.php disabled, but the configuration for framework is loaded and special parameter "useCachingFramework_CLI" is set.
Example of clearing FE-cache for some pages in TYPO3-CLI):

if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['useCachingFramework_CLI'])  
{
    try
    {
        if (!t3lib_cache::isCachingFrameworkInitialized())
        {
            t3lib_cache::initializeCachingFramework();
        }
        // we can initialize caches repeatedly as well, duplicities are ignored ...
        t3lib_cache::initPageCache();
        t3lib_cache::initPageSectionCache();
        $pageCache = $GLOBALS['typo3CacheManager']->getCache('cache_pages');
        $pageSectionCache = $GLOBALS['typo3CacheManager']->getCache('cache_pagesection');
        foreach ($pageIds as $pageId)
        {
            $pageCache->flushByTag('pageId_' . $pageId);
            $pageSectionCache->flushByTag('pageId_' . $pageId);
        }
    }
    catch (Exception $ex)
    {
        // whatever
    }
}
else {
    $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages', 'page_id IN (' . implode(',', $pageIds) . ')');
    $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection', 'page_id IN (' . implode(',', $pageIds) . ')');
}

More about the TYPO3 caching framework you can find here.

Have a lot of fun ...

Martin

23.11.2011

Sortieren eines UTF-8 kodierten Arrays nach seinen Werten

Die PHP Funktion asort kann auch mit UTF-8 Werten genutzt werden. Voraussetzung ist allerdings, dass in einem Array mit Textwerten, das richtige locale gesetzt ist. Zudem muss die Konstante SORT_LOCALE_STRING bei asort benutzt werden. Nun tritt dennoch ein Problem auf: Wenn die Textwerte UTF-8 kodiert sind, werden die Ergebnisse trotzdem single-byte sortiert, also z.B. ‘Ä’ aber auch ‘Ö’ kommen gleich nach dem ‘A’ weil diese Zeichen in UTF-8 mit zwei Zeichen kodiert sind wobei ‘Ã’ das erste davon ist.

Um dies zu lösen sind zwei Wege möglich:

1. Weg: Locale mit Charset setzten

setlocale(LC_COLLATE, 'de_DE.UTF8', 'de.UTF8', 'DEU.UTF8', 'German_Germany.UTF8', 'German.UTF8'
    'de_DE.UTF-8', 'de.UTF-8', 'DEU.UTF-8', 'German_Germany.UTF-8', 'German.UTF-8');

Diese Methode ist systemabhängig und birgt ein gewisses Risiko, da in manchen Systemen die Locale nicht richtig gesetzt sind. Windows (als Server) unterstützt z.B. UTF-8 als Zeichenkodierung meist nicht (Windows benutzt WinCP, z.B. 1252).

2. Weg: Klasse ”Collate” benutzten

$coll = collator_create('de_DE');

Diese Lösung ist erst ab PHP 5.3.0 möglich und erfordert, dass die PHP-Extension php_intl installiert ist. Dies kann dann wie folgt abgefragt resp. benutzt werden:

$oldLocale = setlocale(LC_COLLATE, '0');
if (preg_match('/\\.utf-?8\\b/i', $oldLocale)) {
    // Alles richtig gesetzt
    asort($arrayToSort, SORT_LOCALE_STRING);
}
elseif (version_compare(PHP_VERSION, '5.3.0') < 1 && function_exists('collator_create')) {
    // Wir benutzten die Collator Klasse
    $coll = collator_create($oldLocale);
    collator_asort($coll, $arrayToSort, Collator::SORT_STRING);
}
else {
    // Wir versuchen locale mit Zeichenkodierung setzten
    $lang = preg_replace('/(?:\\.|\\@).*$/', '', $oldLocale);
    foreach (array('.UTF-8', '.utf-8', '.UTF8', '.utf8', '') as $enc)
        $locale[] = $lang . $enc;
    $newLocale = setlocale(LC_COLLATE, $locale);
    if (preg_match('/\\.utf-?8\\b/i', $newLocale)) {
        asort($arrayToSort, SORT_LOCALE_STRING);
        setlocale(LC_COLLATE, $oldLocale);
    }
    else {
        // An diesem System funktioniert es nicht :(
        // Es bleibt nichts Anderes übrig als User-function zu schreiben 
        // und 'usort'/'uasort' zu benutzen
    }
}