Index: trunk/core/units/categories/cache_updater.php =================================================================== diff -u -N --- trunk/core/units/categories/cache_updater.php (revision 8905) +++ trunk/core/units/categories/cache_updater.php (revision 0) @@ -1,489 +0,0 @@ -Stack = Array(); - } - - function Push($values) - { - array_push($this->Stack, $values); - } - - function Pop() - { - if ($this->Count() > 0) { - return array_pop($this->Stack); - } - else { - return false; - } - } - - function Get() - { - if ($this->Count() > 0) { - // return end($this->Stack); - return $this->Stack[count($this->Stack)-1]; - } - else { - return false; - } - } - - function Update($values) - { - $this->Stack[count($this->Stack)-1] = $values; - } - - function Count() - { - return count($this->Stack); - } - } - - class clsCachedPermissions { - var $Allow = Array(); - var $Deny = Array(); - var $CatId; - - /** - * Table name used for inserting permissions - * - * @var string - */ - var $table = ''; - - function clsCachedPermissions($CatId, $table_name) - { - $this->CatId = $CatId; - $this->table = $table_name; - } - - function SetCatId($CatId) - { - $this->CatId = $CatId; - } - - function CheckPermArray($Perm) - { - if (!isset($this->Allow[$Perm])) { - $this->Allow[$Perm] = array(); - $this->Deny[$Perm] = array(); - } - } - - function AddAllow($Perm, $GroupId) - { - $this->CheckPermArray($Perm); - if (!in_array($GroupId, $this->Allow[$Perm])) { - array_push($this->Allow[$Perm], $GroupId); - $this->RemoveDeny($Perm, $GroupId); - } - } - - function AddDeny($Perm, $GroupId) - { - $this->CheckPermArray($Perm); - if (!in_array($GroupId, $this->Deny[$Perm])) { - array_push($this->Deny[$Perm], $GroupId); - $this->RemoveAllow($Perm, $GroupId); - } - } - - function RemoveDeny($Perm, $GroupId) - { - if (in_array($GroupId, $this->Deny[$Perm])) { - array_splice($this->Deny[$Perm], array_search($GroupId, $this->Deny[$Perm]), 1); - } - } - - function RemoveAllow($Perm, $GroupId) - { - if (in_array($GroupId, $this->Allow[$Perm])) { - array_splice($this->Allow[$Perm], array_search($GroupId, $this->Allow[$Perm]), 1); - } - } - - function GetInsertSQL() - { - $values = array(); - foreach ($this->Allow as $perm => $groups) { - if (count($groups) > 0) { - $values[] = '(' .$this->CatId. ', ' .$perm. ', "' .join(',', $groups). '")'; - } - } - if (!$values) return ''; - $sql = 'INSERT INTO '.$this->table.' (CategoryId, PermId, ACL) VALUES '.join(',', $values); - return $sql; - } - } - - class kPermCacheUpdater extends kHelper { - /** - * Holds Stack - * - * @var clsRecursionStack - */ - var $Stack; - - /** - * Rebuild process iteration - * - * @var int - */ - var $iteration; - - /** - * Categories count to process - * - * @var unknown_type - */ - var $totalCats = 0; - - /** - * Processed categories count - * - * @var int - */ - var $doneCats = 0; - - /** - * Temporary table name used for storing cache building progress - * - * @var string - */ - var $progressTable = ''; - - /** - * Temporary table name used for storing not fully built permissions cache - * 1. preserves previous cache while new cache is building - * 2. when rebuild process fails allows previous cache (in live table) is used - * - * @var string - */ - var $permCacheTable = ''; - - var $primaryLanguageId = 0; - var $languageCount = 0; - var $root_prefixes = Array(); - - /** - * Update cache only for requested categories and it's parent categories - * - * @var bool - */ - var $StrictPath = false; - - function Init($prefix, $special, $event_params = null) - { - parent::Init($prefix, $special, $event_params); - - $continuing = isset($event_params['continue']) ? $event_params['continue'] : 1; - $this->StrictPath = isset($event_params['strict_path']) ? $event_params['strict_path'] : false; - if ($this->StrictPath && !is_array($this->StrictPath)) { - $this->StrictPath = explode('|', trim($this->StrictPath, '|')); - } - - // cache widely used values to speed up process: begin - $ml_helper =& $this->Application->recallObject('kMultiLanguageHelper'); - $this->languageCount = $ml_helper->getLanguageCount(); - $this->primaryLanguageId = $this->Application->GetDefaultLanguageId(); - // cache widely used values to speed up process: end - - foreach ($this->Application->ModuleInfo as $module_name => $module_info) { - $this->root_prefixes[ $module_info['RootCat'] ] = $module_info['Var']; - } - - $this->iteration = 0; - $this->progressTable = $this->Application->GetTempName('permCacheUpdate'); - $this->permCacheTable = $this->Application->GetTempName(TABLE_PREFIX.'PermCache'); - - if ($continuing == 1) { - $this->InitUpdater(); - } - elseif ($continuing == 2) { - $this->getData(); - } - } - - function InitUpdater() - { - $this->Stack =& new clsRecursionStack(); - $this->initData(); - } - - function getDonePercent() - { - if (!$this->totalCats) { - return 0; - } - return min(100, intval( floor( $this->doneCats / $this->totalCats * 100 ) )); - } - - function getData() - { - $tmp = $this->Conn->GetOne('SELECT data FROM '.$this->progressTable); - if ($tmp) $tmp = unserialize($tmp); - - $this->totalCats = isset($tmp['totalCats']) ? $tmp['totalCats'] : 0; - $this->doneCats = isset($tmp['doneCats']) ? $tmp['doneCats'] : 0; - if (isset($tmp['stack'])) { - $this->Stack = $tmp['stack']; - } - else { - $this->Stack =& new clsRecursionStack(); - } - } - - function setData() - { - $tmp = Array ( - 'totalCats' => $this->totalCats, - 'doneCats' => $this->doneCats, - 'stack' => $this->Stack, - ); - - $this->Conn->Query('DELETE FROM '.$this->progressTable); - - $fields_hash = Array('data' => serialize($tmp)); - $this->Conn->doInsert($fields_hash, $this->progressTable); - } - - function initData() - { - $this->clearData(); // drop table before starting anyway - - // 1. create table for rebuilding permissions cache - $this->Conn->Query('CREATE TABLE '.$this->permCacheTable.' LIKE '.TABLE_PREFIX.'PermCache'); - - if ($this->StrictPath) { - // when using strict path leave all other cache intact - $sql = 'INSERT INTO '.$this->permCacheTable.' - SELECT * - FROM '.TABLE_PREFIX.'PermCache'; - $this->Conn->Query($sql); - - // delete only cache related to categories in path - $sql = 'DELETE FROM '.$this->permCacheTable.' - WHERE CategoryId IN ('.implode(',', $this->StrictPath).')'; - $this->Conn->Query($sql); - } - - $this->Conn->Query('CREATE TABLE '.$this->progressTable.'(data LONGTEXT)'); - - $this->totalCats = (int)$this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'Category'); - $this->doneCats = 0; - } - - function clearData() - { - $this->Conn->Query('DROP TABLE IF EXISTS '.$this->progressTable); - $this->Conn->Query('DROP TABLE IF EXISTS '.$this->permCacheTable); - $this->Conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName = \'ForcePermCacheUpdate\''); - $this->Conn->Query('UPDATE '.TABLE_PREFIX.'ConfigurationValues SET VariableValue = VariableValue+1 WHERE VariableName = \'CategoriesRebuildSerial\''); - } - - function SaveData() - { - // copy data from temp permission cache table back to live - $this->Conn->Query('TRUNCATE '.TABLE_PREFIX.'PermCache'); - - $sql = 'INSERT INTO '.TABLE_PREFIX.'PermCache - SELECT * - FROM '.$this->permCacheTable; - $this->Conn->Query($sql); - $this->clearData(); - } - - function DoTheJob() - { - $data = $this->Stack->Get(); - if ($data === false) { //If Stack is empty - $data['current_id'] = 0; - $data['titles'] = Array(); - $data['parent_path'] = Array(); - $data['named_path'] = Array(); - $data['category_template'] = ''; - $data['item_template'] = ''; - $data['children_count'] = 0; - $data['system'] = 0; - $data['left'] = 0; - $data['right'] = 2; - $data['debug_title'] = 'ROOT'; - $this->Stack->Push($data); - } - - if (!isset($data['queried'])) { - $this->QueryTitle($data); - $this->QueryChildren($data); - $data['children_count'] = count($data['children']); - $this->QueryPermissions($data); - $data['queried'] = 1; - $data['right'] = $data['left']+1; - - if ($sql = $data['perms']->GetInsertSQL()) { - $this->Conn->Query($sql); - // $this->doneCats++; // moved to the place where it pops out of the stack by Kostja - } - $this->iteration++; - } - - // start with first child if we haven't started yet - if (!isset($data['current_child'])) $data['current_child'] = 0; - - // if we have more children on CURRENT LEVEL - if (isset($data['children'][$data['current_child']])) { - if ($this->StrictPath) { - while ( isset($data['children'][ $data['current_child'] ]) && !in_array($data['children'][ $data['current_child'] ], $this->StrictPath) ) { - $data['current_child']++; - continue; - } - if (!isset($data['children'][ $data['current_child'] ])) return false; //error - } - $next_data = Array(); - $next_data['titles'] = $data['titles']; - $next_data['parent_path'] = $data['parent_path']; - $next_data['named_path'] = $data['named_path']; - $next_data['category_template'] = $data['category_template']; - $next_data['item_template'] = $data['item_template']; - $next_data['current_id'] = $data['children'][ $data['current_child'] ]; //next iteration should process child - $next_data['perms'] = $data['perms']; //we should copy our permissions to child - inheritance - $next_data['perms']->SetCatId($next_data['current_id']); - $next_data['left'] = $data['right']; - $data['current_child']++; - $this->Stack->Update($data); //we need to update ourself for the iteration after the next (or further) return to next child - $this->Stack->Push($next_data); //next iteration should process this child - return true; - } - else { - $this->Stack->Update($data); - $prev_data = $this->Stack->Pop(); //remove ourself from stack if we have finished all the childs (or there are none) - $data['right'] = $prev_data['right']; - $this->UpdateCachedPath($data); - // we are getting here if we finished with current level, so check if it's first level - then bail out. - - $this->doneCats++; // moved by Kostja from above, seems to fix the prob - $has_more = $this->Stack->Count() > 0; - if ($has_more) { - $next_data = $this->Stack->Get(); - $next_data['right'] = $data['right']+1; - $next_data['children_count'] += $data['children_count']; - $this->Stack->Update($next_data); - } - return $has_more; - } - } - - function UpdateCachedPath(&$data) - { - $fields_hash = Array ( - 'ParentPath' => '|'.implode('|', $data['parent_path']).'|', - 'NamedParentPath' => $data['system'] ? $data['file_name'] : implode('/', $data['named_path'] ), - 'CachedCategoryTemplate' => $data['category_template'], - 'CachedDescendantCatsQty' => $data['children_count'], - 'TreeLeft' => $data['left'], - 'TreeRight' => $data['right'], - ); - - $i = 1; - while ($i <= $this->languageCount) { - $fields_hash['l'.$i.'_CachedNavbar'] = implode('&|&', $data['titles'][$i]); - $i++; - } - - $this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Category', 'CategoryId = '.$data['current_id']); - } - - function QueryTitle(&$data) - { - $category_id = $data['current_id']; - $sql = 'SELECT * - FROM '.TABLE_PREFIX.'Category - WHERE CategoryId = '.$category_id; - - $record = $this->Conn->GetRow($sql); - if ($record) { - $i = 1; - while ($i <= $this->languageCount) { - $data['titles'][$i][] = $record['l'.$i.'_Name'] ? $record['l'.$i.'_Name'] : $record['l'.$this->primaryLanguageId.'_Name']; - $i++; - } - $data['debug_title'] = $record['l1_Name']; - - $data['parent_path'][] = $category_id; - $data['named_path'][] = preg_replace('/^Content\\//', '', $record['Filename']); - $data['system'] = $record['IsSystem']; - $data['file_name'] = $record['Filename']; - - // it is one of the modules root category - $root_prefix = isset($this->root_prefixes[$category_id]) ? $this->root_prefixes[$category_id] : false; - if ($root_prefix) { - $fields_hash = Array(); - if (!$record['CategoryTemplate']) { - $record['CategoryTemplate'] = $this->Application->ConfigValue($root_prefix.'_CategoryTemplate'); - $fields_hash['CategoryTemplate'] = $record['CategoryTemplate']; - } - - $this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Category', 'CategoryId = '.$category_id); - } - - // if explicitly set, then use it; use parent template otherwise - if ($record['CategoryTemplate']) { - $data['category_template'] = $record['CategoryTemplate']; - } - } - - } - - function QueryChildren(&$data) - { - $sql = 'SELECT CategoryId - FROM '.TABLE_PREFIX.'Category - WHERE ParentId = '.$data['current_id']; - $data['children'] = $this->Conn->GetCol($sql); - } - - function QueryPermissions(&$data) - { - // don't search for section "view" permissions here :) - $sql = 'SELECT ipc.PermissionConfigId, ip.GroupId, ip.PermissionValue - FROM '.TABLE_PREFIX.'Permissions AS ip - LEFT JOIN '.TABLE_PREFIX.'PermissionConfig AS ipc ON ipc.PermissionName = ip.Permission - WHERE (CatId = '.$data['current_id'].') AND (Permission LIKE "%.VIEW") AND (ip.Type = 0)'; - - $records = $this->Conn->Query($sql); - - //create permissions array only if we don't have it yet (set by parent) - if (!isset($data['perms'])) { - $data['perms'] = new clsCachedPermissions($data['current_id'], $this->permCacheTable); - } - - foreach ($records as $record) { - if ($record['PermissionValue'] == 1) { - $data['perms']->AddAllow($record['PermissionConfigId'], $record['GroupId']); - } - else { - $data['perms']->AddDeny($record['PermissionConfigId'], $record['GroupId']); - } - } - } - - /** - * Rebuild all cache in one step - * - */ - function OneStepRun($path='') - { - $this->InitUpdater(); - $needs_more = true; - while ($needs_more) { - // until proceeeded in this step category count exceeds category per step limit - $needs_more = $this->DoTheJob(); - } - $this->SaveData(); - } - } -?> \ No newline at end of file