Added feature #15306: [Caching framework] Add scheduler task to execute garbage colle...
authorChristian Kuhn <lolli@schwarzbu.ch>
Sat, 30 Oct 2010 12:52:07 +0000 (12:52 +0000)
committerChristian Kuhn <lolli@schwarzbu.ch>
Sat, 30 Oct 2010 12:52:07 +0000 (12:52 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@9231 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
typo3/sysext/scheduler/ext_autoload.php
typo3/sysext/scheduler/ext_localconf.php
typo3/sysext/scheduler/locallang.xml
typo3/sysext/scheduler/mod1/locallang.xml
typo3/sysext/scheduler/mod1/locallang_csh_scheduler.xml
typo3/sysext/scheduler/tasks/class.tx_scheduler_cachingframeworkgarbagecollection.php [new file with mode: 0644]
typo3/sysext/scheduler/tasks/class.tx_scheduler_cachingframeworkgarbagecollection_additionalfieldprovider.php [new file with mode: 0644]
typo3/sysext/scheduler/tests/tx_scheduler_cachingframeworkgarbagecollectionTest.php [new file with mode: 0644]

index 88eb71f..0f749d2 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2010-10-30  Christian Kuhn  <lolli@schwarzbu.ch>
+
+       * Added feature #15306: [Caching framework] Add scheduler task to execute garbage collection
+
 2010-10-29  Sebastian Kurfuerst  <sebastian@typo3.org>
 
        * Updated Fluid version to 1.3.0alpha3
index 8b3ba19..a378d25 100644 (file)
@@ -18,5 +18,7 @@ return array(
        'tx_scheduler_additionalfieldprovider' => $extensionPath . 'interfaces/interface.tx_scheduler_additionalfieldprovider.php',
        'tx_scheduler_module' => $extensionPath . 'mod1/index.php',
        'tx_scheduler_croncmdtest' => $extensionPath . 'tests/tx_scheduler_croncmdTest.php',
+       'tx_scheduler_cachingframeworkgarbagecollection' => $extensionPath . 'tasks/class.tx_scheduler_cachingframeworkgarbagecollection.php',
+       'tx_scheduler_cachingframeworkgarbagecollection_additionalfieldprovider' => $extensionPath . 'tasks/class.tx_scheduler_cachingframeworkgarbagecollection_additionalfieldprovider.php',
 );
 ?>
\ No newline at end of file
index d90797e..fd3200e 100644 (file)
@@ -29,4 +29,13 @@ if (!empty($extConf['showSampleTasks'])) {
                'additionalFields' => 'tx_scheduler_SleepTask_AdditionalFieldProvider'
        );
 }
-?>
\ No newline at end of file
+
+       // Add caching framework garbage collection task
+$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks']['tx_scheduler_CachingFrameworkGarbageCollection'] = array(
+               'extension'        => $_EXTKEY,
+               'title'            => 'LLL:EXT:' . $_EXTKEY . '/locallang.xml:cachingFrameworkGarbageCollection.name',
+               'description'      => 'LLL:EXT:' . $_EXTKEY . '/locallang.xml:cachingFrameworkGarbageCollection.description',
+               'additionalFields' => 'tx_scheduler_CachingFrameworkGarbageCollection_AdditionalFieldProvider',
+       );
+
+?>
index ae5a0ea..5279180 100644 (file)
@@ -10,6 +10,8 @@
                        <label index="testTask.description">The Scheduler test task just sends a mail to a given email address. It is designed to be used for testing purposes.</label>
                        <label index="sleepTask.name">Scheduler sleep task</label>
                        <label index="sleepTask.description">This task does nothing but put PHP to sleep for a number of seconds. It is designed to test multiple executions.</label>
+                       <label index="cachingFrameworkGarbageCollection.name">Caching framework garbage collection</label>
+                       <label index="cachingFrameworkGarbageCollection.description">This task calls the garbage collection of configured caching framework caches which use one of the selected backends. This will free some space in cache backends which do not have an internal garbage collection. In case of the default database backend it is advisable to run this task once a day when the database is mostly idle.</label>
                </languageKey>
        </data>
 </T3locallang>
\ No newline at end of file
index 286874c..6bcd667 100644 (file)
@@ -16,6 +16,7 @@
                        <label index="hdg.lastRun">Last run</label>
                        <label index="hdg.schedulerUser">TYPO3 Scheduler backend user</label>
                        <label index="label.automatically">automatically</label>
+                       <label index="label.cachingFrameworkGarbageCollection.selectBackends">Backend types</label>
                        <label index="label.checkAll">Check/uncheck all</label>
                        <label index="label.class">Class</label>
                        <label index="label.cron">Cron</label>
index 8fc9195..0163aec 100644 (file)
@@ -62,6 +62,8 @@
                        <label index="task_email.description">Enter a recipient for the mails sent by the test task</label>
                        <label index="task_sleepTime.alttitle">Sleep time</label>
                        <label index="task_sleepTime.description">Enter a number of seconds during which the task will just sleep.</label>
+                       <label index="task_cachingFrameworkGarbageCollection_selectedBackends.alttitle">Select backends</label>
+                       <label index="task_cachingFrameworkGarbageCollection_selectedBackends.description">If a cache uses one of the selected backends, the garbage collection will be called for this cache.</label>
                </languageKey>
        </data>
 </T3locallang>
diff --git a/typo3/sysext/scheduler/tasks/class.tx_scheduler_cachingframeworkgarbagecollection.php b/typo3/sysext/scheduler/tasks/class.tx_scheduler_cachingframeworkgarbagecollection.php
new file mode 100644 (file)
index 0000000..482d06f
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2009-2010 Christian Kuhn <lolli@schwarzbu.ch>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Garbage collection of caching framework cache backends.
+ *
+ * This task finds all configured caching framework caches and
+ * calls the garbage collection of a cache if the cache backend
+ * is configured to be cleaned.
+ *
+ * @author Christian Kuhn <lolli@schwarzbu.ch>
+ * @package TYPO3
+ * @subpackage scheduler
+ */
+class tx_scheduler_CachingFrameworkGarbageCollection extends tx_scheduler_Task {
+       /**
+        * Backend types that should be cleaned up,
+        * set by additional field provider.
+        *
+        * @var array Selected backends to do garbage collection for
+        */
+       public $selectedBackends = array();
+
+       /**
+        * Execute garbage collection, called by scheduler.
+        *
+        * @return void
+        */
+       public function execute() {
+                       // Don't do anything if caching framework is not used at all
+               if (t3lib_cache::isCachingFrameworkInitialized()) {
+                               // Global subarray with all configured caches
+                       $cacheConfigurations = $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'];
+
+                       if (is_array($cacheConfigurations)) {
+                                       // Iterate through configured caches and call garbage collection if
+                                       // backend is within selected backends in additonal field of task
+                               foreach ($cacheConfigurations as $cacheName => $cacheConfiguration) {
+                                               // The cache backend used for this cache
+                                       $usedCacheBackend = $cacheConfiguration['backend'];
+
+                                       if (in_array($usedCacheBackend, $this->selectedBackends)) {
+                                               $this->callGarbageCollectionOfCache($cacheName, $cacheConfiguration);
+                                       }
+                               }
+                       }
+               }
+
+               return(TRUE);
+       }
+
+       /**
+        * Get an instance of cache and call garbage collection
+        *
+        * @param string Cache name
+        * @param array Cache configuration
+        */
+       protected function callGarbageCollectionOfCache($cacheName, array $cacheConfiguration) {
+                       // Get existing cache instance or create a new one
+               try {
+                       $cache = $GLOBALS['typo3CacheManager']->getCache($cacheName);
+               } catch (t3lib_cache_exception_NoSuchCache $exception) {
+                       $GLOBALS['typo3CacheFactory']->create(
+                               $cacheName,
+                               $cacheConfiguration['frontend'],
+                               $cacheConfiguration['backend'],
+                               $cacheConfiguration['options']
+                       );
+                       $cache = $GLOBALS['typo3CacheManager']->getCache($cacheName);
+               }
+
+                       // Call garbage collection of this cache
+               $cache->collectGarbage();
+       }
+} // End of class
+
+if (defined('TYPO3_MODE') && $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/scheduler/tasks/class.tx_scheduler_cachingframeworkgarbagecollection.php']) {
+       include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/scheduler/tasks/class.tx_scheduler_cachingframeworkgarbagecollection.php']);
+}
+
+?>
diff --git a/typo3/sysext/scheduler/tasks/class.tx_scheduler_cachingframeworkgarbagecollection_additionalfieldprovider.php b/typo3/sysext/scheduler/tasks/class.tx_scheduler_cachingframeworkgarbagecollection_additionalfieldprovider.php
new file mode 100644 (file)
index 0000000..b537e5e
--- /dev/null
@@ -0,0 +1,148 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2009-2010 Christian Kuhn <lolli@schwarzbu.ch>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Additional BE fields for caching framework garbage collection task.
+ * Creates a multi selectbox with all available cache backends to select from.
+ *
+ * @author Christian Kuhn <lolli@schwarzbu.ch>
+ * @package TYPO3
+ * @subpackage scheduler
+ */
+class tx_scheduler_CachingFrameworkGarbageCollection_AdditionalFieldProvider implements tx_scheduler_AdditionalFieldProvider {
+       /**
+        * Add a multi select box with all available cache backends.
+        *
+        * @param array Reference to the array containing the info used in the add/edit form
+        * @param object When editing, reference to the current task object. Null when adding.
+        * @param tx_scheduler_Module Reference to the calling object (Scheduler's BE module)
+        * @return array Array containg all the information pertaining to the additional fields
+        */
+       public function getAdditionalFields(array &$taskInfo, $task, tx_scheduler_Module $parentObject) {
+                       // Initialize selected fields
+               if (empty($taskInfo['scheduler_cachingFrameworkGarbageCollection_selectedBackends'])) {
+                       $taskInfo['scheduler_cachingFrameworkGarbageCollection_selectedBackends'] = array();
+                       if ($parentObject->CMD == 'add') {
+                                       // In case of new task, set to dbBackend if it's available
+                               if (in_array('t3lib_cache_backend_DbBackend', $this->getRegisteredBackends())) {
+                                       $taskInfo['scheduler_cachingFrameworkGarbageCollection_selectedBackends'][] = 't3lib_cache_backend_DbBackend';
+                               }
+                       } elseif ($parentObject->CMD == 'edit') {
+                                       // In case of editing the task, set to currently selected value
+                               $taskInfo['scheduler_cachingFrameworkGarbageCollection_selectedBackends'] = $task->selectedBackends;
+                       }
+               }
+
+               $fieldName = 'tx_scheduler[scheduler_cachingFrameworkGarbageCollection_selectedBackends][]';
+               $fieldId = 'task_cachingFrameworkGarbageCollection_selectedBackends';
+               $fieldOptions = $this->getCacheBackendOptions($taskInfo['scheduler_cachingFrameworkGarbageCollection_selectedBackends']);
+               $fieldHtml =
+                       '<select name="' . $fieldName . '" id="' . $fieldId . '" class="wide" size="10" multiple="multiple">' .
+                               $fieldOptions .
+                       '</select>';
+
+               $additionalFields[$fieldID] = array(
+                       'code' => $fieldHtml,
+                       'label' => 'LLL:EXT:scheduler/mod1/locallang.xml:label.cachingFrameworkGarbageCollection.selectBackends',
+                       'cshKey' => '_MOD_tools_txschedulerM1',
+                       'cshLabel' => $fieldId,
+               );
+
+               return $additionalFields;
+       }
+
+       /**
+        * Checks that all selected backends exist in available backend list
+        *
+        * @param array Reference to the array containing the data submitted by the user
+        * @param tx_scheduler_Module Reference to the calling object (Scheduler's BE module)
+        * @return boolean True if validation was ok (or selected class is not relevant), false otherwise
+        */
+       public function validateAdditionalFields(array &$submittedData, tx_scheduler_Module $parentObject) {
+               $validData = TRUE;
+
+               $availableBackends = $this->getRegisteredBackends();
+               $invalidBackends = array_diff($submittedData['scheduler_cachingFrameworkGarbageCollection_selectedBackends'], $availableBackends);
+               if (!empty($invalidBackends)) {
+                       $validData = FALSE;
+               }
+
+               return $validData;
+       }
+
+       /**
+        * Save selected backends in task object
+        *
+        * @param array Contains data submitted by the user
+        * @param tx_scheduler_Task Reference to the current task object
+        * @return void
+        */
+       public function saveAdditionalFields(array $submittedData, tx_scheduler_Task $task) {
+               $task->selectedBackends = $submittedData['scheduler_cachingFrameworkGarbageCollection_selectedBackends'];
+       }
+
+       /**
+        * Build select options of available backends and set currently selected backends
+        *
+        * @param array Selected backends
+        * @return string HTML of selectbox options
+        */
+       protected function getCacheBackendOptions(array $selectedBackends) {
+               $options = array();
+
+               $availableBackends = $this->getRegisteredBackends();
+               foreach ($availableBackends as $backendName) {
+                       if (in_array($backendName, $selectedBackends)) {
+                               $selected = ' selected="selected"';
+                       } else {
+                               $selected = '';
+                       }
+                       $options[] =
+                               '<option value="' . $backendName .  '"' . $selected . '>' .
+                                       $backendName .
+                               '</option>';
+               }
+
+               return implode($options);
+       }
+
+       /**
+        * Get all registered caching framework backends
+        *
+        * @return array Registered backends
+        */
+       protected function getRegisteredBackends() {
+               $backends = array();
+               if (is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheBackends'])) {
+                       $backends = $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheBackends'];
+               }
+               return array_keys($backends);
+       }
+} // End of class
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/scheduler/tasks/class.tx_scheduler_cachingframeworkgarbagecollection_additionalfieldprovider.php']) {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/scheduler/tasks/class.tx_scheduler_cachingframeworkgarbagecollection_additionalfieldprovider.php']);
+}
+
+?>
diff --git a/typo3/sysext/scheduler/tests/tx_scheduler_cachingframeworkgarbagecollectionTest.php b/typo3/sysext/scheduler/tests/tx_scheduler_cachingframeworkgarbagecollectionTest.php
new file mode 100644 (file)
index 0000000..f17abf3
--- /dev/null
@@ -0,0 +1,82 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2010 Christian Kuhn <lolli@schwarzbu.ch>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Testcase for class "tx_scheduler_CachingFrameworkGarbageCollection"
+ *
+ * @package TYPO3
+ * @subpackage tx_scheduler
+ *
+ * @author Christian Kuhn <lolli@schwarzbu.ch>
+ */
+class tx_scheduler_CachingFrameworkGarbageCollectionTest extends tx_phpunit_testcase {
+       protected $backupGlobals = TRUE;
+
+       /**
+        * @test
+        */
+       public function executeCallsCollectGarbageOfConfiguredBackend() {
+               $cache = $this->getMock('t3lib_cache_frontend_StringFrontend', array(), array(), '', FALSE);
+               $cache->expects($this->any())->method('getIdentifier')->will($this->returnValue('cache'));
+
+               $cache->expects($this->atLeastOnce())->method('collectGarbage');
+
+               $GLOBALS['typo3CacheManager'] = new t3lib_cache_Manager();
+               $GLOBALS['typo3CacheManager']->registerCache($cache);
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'] = array(
+                       'cache' => array(
+                               'frontend' => 't3lib_cache_frontend_StringFrontend',
+                               'backend' => 't3lib_cache_backend_AbstractBackend',
+                       ),
+               );
+
+               $task = new tx_scheduler_CachingFrameworkGarbageCollection();
+               $task->selectedBackends = array('t3lib_cache_backend_AbstractBackend');
+               $task->execute();
+       }
+
+       /**
+        * @test
+        */
+       public function executeDoesNotCallCollectGarbageOfConfiguredBackend() {
+               $cache = $this->getMock('t3lib_cache_frontend_StringFrontend', array(), array(), '', FALSE);
+               $cache->expects($this->any())->method('getIdentifier')->will($this->returnValue('cache'));
+
+               $cache->expects($this->never())->method('collectGarbage');
+
+               $GLOBALS['typo3CacheManager'] = new t3lib_cache_Manager();
+               $GLOBALS['typo3CacheManager']->registerCache($cache);
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'] = array(
+                       'cache' => array(
+                               'frontend' => 't3lib_cache_frontend_StringFrontend',
+                               'backend' => 't3lib_cache_backend_AbstractBackend',
+                       ),
+               );
+
+               $task = new tx_scheduler_CachingFrameworkGarbageCollection();
+               $task->selectedBackends = array('t3lib_cache_backend_NullBackend');
+               $task->execute();
+       }
+}
+?>