Index: Classes/ExtDirect/Server.php =================================================================== --- Classes/ExtDirect/Server.php (revision 3843) +++ Classes/ExtDirect/Server.php (working copy) @@ -45,7 +45,7 @@ $versions = $wslibObj->selectVersionsInWorkspace($this->getCurrentWorkspace(), 0, -99, $pageId, $parameter->depth); $workspacesService = t3lib_div::makeInstance('tx_Workspaces_Service_GridData'); - $data = $workspacesService->generateGridListFromVersions($versions, $parameter); + $data = $workspacesService->generateGridListFromVersions($versions, $parameter, $this->getCurrentWorkspace()); return $data; } Index: Classes/Service/GridData.php =================================================================== --- Classes/Service/GridData.php (revision 3843) +++ Classes/Service/GridData.php (working copy) @@ -31,9 +31,11 @@ * @subpackage Service */ class tx_Workspaces_Service_GridData { + protected $currentWorkspace = NULL; protected $dataArray = array(); protected $sort = ''; protected $sortDir = ''; + protected $workspacesCache = NULL; /** * Generates grid list array from given versions. @@ -41,8 +43,9 @@ * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid, t3ver_oid and t3ver_swapmode fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid" * @param object $parameter * @return array + * @throws InvalidArgumentException */ - public function generateGridListFromVersions($versions, $parameter) { + public function generateGridListFromVersions($versions, $parameter, $currentWorkspace) { // Read the given parameters from grid. If the parameter is not set use default values. $filterTxt = isset($parameter->filterTxt) ? $parameter->filterTxt : ''; @@ -50,6 +53,12 @@ $limit = isset($parameter->limit) ? intval($parameter->limit) : 10; $this->sort = isset($parameter->sort) ? $parameter->sort : 't3ver_oid'; $this->sortDir = isset($parameter->dir) ? $parameter->dir : 'ASC'; + + if (is_int($currentWorkspace)) { + $this->currentWorkspace = $currentWorkspace; + } else { + throw new InvalidArgumentException('No such workspace defined'); + } $data = array(); $data['data'] = array(); @@ -77,17 +86,20 @@ $workspacesObj = t3lib_div::makeInstance('Tx_Workspaces_Service_Workspaces'); $availableWorkspaces = $workspacesObj->getAvailableWorkspaces(); - foreach ($versions as $table => $records) { - $versionArray = array('table' => $table); + $this->initializeWorkspacesCachingFramework(); - foreach ($records as $record) { - - $origRecord = t3lib_BEFunc::getRecord($table, $record['t3ver_oid']); - $versionRecord = t3lib_BEFunc::getRecord($table, $record['uid']); - - // check the given version is from an available workspace - if (array_key_exists($versionRecord['t3ver_wsid'], $availableWorkspaces)) { - + // check for dataArray in cache + if ($this->getDataArrayFromCache($versions, $filterTxt) == FALSE) { + $stagesObj = t3lib_div::makeInstance('Tx_Workspaces_Service_Stages'); + + foreach ($versions as $table => $records) { + $versionArray = array('table' => $table); + + foreach ($records as $record) { + + $origRecord = t3lib_BEFunc::getRecord($table, $record['t3ver_oid']); + $versionRecord = t3lib_BEFunc::getRecord($table, $record['uid']); + if (isset($GLOBALS['TCA'][$table]['columns']['hidden'])) { $recordState = $this->workspaceState($versionRecord['t3ver_state'], $origRecord['hidden'], $versionRecord['hidden']); } else { @@ -131,6 +143,9 @@ } } } + $this->sortDataArray(); + + $this->setDataArrayIntoCache($versions, $filterTxt); } $this->sortDataArray(); } @@ -153,7 +168,90 @@ return $dataArrayPart; } + /** + * Initialize the workspace cache + * + * @return void + */ + protected function initializeWorkspacesCachingFramework() { + if (TYPO3_UseCachingFramework) { + try { + $GLOBALS['typo3CacheFactory']->create( + 'workspaces_cache', + 't3lib_cache_frontend_StringFrontend', + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['sys_workspace_cache']['backend'], + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['sys_workspace_cache']['options']); + } catch (t3lib_cache_exception_DuplicateIdentifier $e) { + // do nothing, a workspace cache already exists + } + + $this->workspacesCache = $GLOBALS['typo3CacheManager']->getCache('workspaces_cache'); + } + } + + + /** + * Put the generated dataArray into the workspace cache. + * + * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid, t3ver_oid and t3ver_swapmode fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid" + * @param string $filterTxt The given filter text from the grid. + */ + protected function setDataArrayIntoCache (array $versions, $filterTxt) { + if (TYPO3_UseCachingFramework) { + $hash = $this->calculateHash($versions, $filterTxt); + $content = serialize($this->dataArray); + + $this->workspacesCache->set($hash, $content, array($this->currentWorkspace)); + } + } + + + /** + * Checks if a cache entry is given for given versions and filter text and tries to load the data array from cache. + * + * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid, t3ver_oid and t3ver_swapmode fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid" + * @param string $filterTxt The given filter text from the grid. + */ + protected function getDataArrayFromCache (array $versions, $filterTxt) { + $cacheEntry = FALSE; + + if (TYPO3_UseCachingFramework) { + $hash = $this->calculateHash($versions, $filterTxt); + + $content = $this->workspacesCache->get($hash); + + if ($content != FALSE) { + $this->dataArray = unserialize($content); + $cacheEntry = TRUE; + } + } + + return $cacheEntry; + } + + /** + * Calculate the hash value of the used workspace, the user id, the versions array, the filter text, the sorting attribute, the workspace selected in grid and the sorting direction. + * + * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid, t3ver_oid and t3ver_swapmode fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid" + * @param string $filterTxt The given filter text from the grid. + */ + protected function calculateHash (array $versions, $filterTxt) { + $hashArray = array( + $GLOBALS['BE_USER']->workspace, + $GLOBALS['BE_USER']->user['uid'], + $versions, + $filterTxt, + $this->sort, + $this->sortDir, + $this->currentWorkspace); + $hash = md5(serialize($hashArray)); + + return $hash; + } + + + /** * Performs sorting on the data array accordant to the * selected column in the grid view to be used for sorting. * Index: Classes/Service/Tcemain.php =================================================================== --- Classes/Service/Tcemain.php (revision 3843) +++ Classes/Service/Tcemain.php (working copy) @@ -56,6 +56,19 @@ } /** + * hook that is called AFTER all commands of the commandmap was + * executed + * + * @param t3lib_TCEmain $tcemainObj reference to the main tcemain object + * @return void + */ + public function processCmdmap_afterFinish(t3lib_TCEmain $tcemainObj) { + if (TYPO3_UseCachingFramework) { + $this->flushWorkspaceCacheEntriesByWorkspaceId($tcemainObj->BE_USER->workspace); + } + } + + /** * In case a sys_workspace_stage record is deleted we do a hard reset * for all existing records in that stage to avoid that any of these end up * as orphan records. @@ -129,6 +142,30 @@ return $tceMain; } + /** + * Flushes the workspace cache for current workspace and for the virtual "all workspaces" too. + * + * @param integer $workspaceId The workspace to be flushed in cache + * @return void + */ + protected function flushWorkspaceCacheEntriesByWorkspaceId($workspaceId) { + if (TYPO3_UseCachingFramework) { + try { + $GLOBALS['typo3CacheFactory']->create( + 'workspaces_cache', + 't3lib_cache_frontend_StringFrontend', + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['sys_workspace_cache']['backend'], + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['sys_workspace_cache']['options']); + } catch (t3lib_cache_exception_DuplicateIdentifier $e) { + // do nothing, a workspace cache already exists + } + + $workspacesCache = $GLOBALS['typo3CacheManager']->getCache('workspaces_cache'); + + $workspacesCache->flushByTag($workspaceId); + $workspacesCache->flushByTag(tx_Workspaces_Service_Workspaces::SELECT_ALL_WORKSPACES); + } + } } Index: ext_localconf.php =================================================================== --- ext_localconf.php (revision 3843) +++ ext_localconf.php (working copy) @@ -20,4 +20,15 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['viewOnClickClass']['workspaces'] = 'EXT:workspaces/Classes/Service/Tcemain.php:tx_Workspaces_Service_Befunc'; $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe']['workspaces'] = 'EXT:workspaces/Classes/Service/Fehooks.php:tx_Workspaces_Service_Fehooks->hook_eofe'; +if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['useCachingFramework']) { + // Initialize the caching framework. The caching framework is asking it self if it is initialized already before initializing. + t3lib_cache::initializeCachingFramework(); + + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['sys_workspace_cache']['backend'] = 't3lib_cache_backend_DbBackend'; + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['sys_workspace_cache']['options'] = array( + 'cacheTable' => 'sys_workspace_cache', + 'tagsTable' => 'sys_workspace_cache_tags' + ); +} + ?> \ No newline at end of file Index: ext_tables.sql =================================================================== --- ext_tables.sql (revision 3843) +++ ext_tables.sql (working copy) @@ -48,3 +48,30 @@ PRIMARY KEY (uid), KEY parent (pid) ); + + +# +# Table structure for table 'sys_workspace_cache' +# +CREATE TABLE sys_workspace_cache ( + id int(11) unsigned NOT NULL auto_increment, + identifier varchar(32) DEFAULT '' NOT NULL, + content mediumblob NOT NULL, + crdate int(11) DEFAULT '0' NOT NULL, + lifetime int(11) DEFAULT '0' NOT NULL, + PRIMARY KEY (id), + KEY cache_id (identifier) +) ENGINE=InnoDB; + + +# +# Table structure for table 'sys_workspace_cache_tags' +# +CREATE TABLE sys_workspace_cache_tags ( + id int(11) unsigned NOT NULL auto_increment, + identifier varchar(128) DEFAULT '' NOT NULL, + tag varchar(128) DEFAULT '' NOT NULL, + PRIMARY KEY (id), + KEY cache_id (identifier), + KEY cache_tag (tag) +) ENGINE=InnoDB;