Index: branches/5.2.x/core/units/modules/modules_event_handler.php =================================================================== diff -u -r14699 -r14787 --- branches/5.2.x/core/units/modules/modules_event_handler.php (.../modules_event_handler.php) (revision 14699) +++ branches/5.2.x/core/units/modules/modules_event_handler.php (.../modules_event_handler.php) (revision 14787) @@ -1,6 +1,6 @@ status = kEvent::erSUCCESS; $event->setRedirectParams(Array ('opener' => 's'), true); - $this->Application->DeleteUnitCache(true); //true to reset sections cache also + $this->Application->DeleteUnitCache(); + $this->Application->DeleteSectionCache(); + $event->SetRedirectParam('RefreshTree', 1); } } /** - * Occures after list is queried + * Occurs after list is queried * * @param kEvent $event */ Index: branches/5.2.x/core/kernel/managers/rewrite_url_processor.php =================================================================== diff -u -r14753 -r14787 --- branches/5.2.x/core/kernel/managers/rewrite_url_processor.php (.../rewrite_url_processor.php) (revision 14753) +++ branches/5.2.x/core/kernel/managers/rewrite_url_processor.php (.../rewrite_url_processor.php) (revision 14787) @@ -68,10 +68,19 @@ * Possible url endings from ModRewriteUrlEnding configuration variable * * @var Array + * @access protected */ protected $_urlEndings = Array ('.html', '/', ''); /** + * Factory storage sub-set, containing mod-rewrite listeners, used during url building and parsing + * + * @var Array + * @access protected + */ + protected $rewriteListeners = Array (); + + /** * Constructor of kRewriteUrlProcessor class * * @param $manager @@ -280,9 +289,11 @@ foreach ($this->Application->RewriteListeners as $prefix => $listener_data) { foreach ($listener_data['listener'] as $index => $rewrite_listener) { list ($listener_prefix, $listener_method) = explode(':', $rewrite_listener); - $listener =& $this->Application->recallObject($listener_prefix); - $this->Application->RewriteListeners[$prefix][$index] = Array (&$listener, $listener_method); + // don't use temp variable, since it will swap objects in Factory in PHP5 + $this->rewriteListeners[$prefix][$index] = Array (); + $this->rewriteListeners[$prefix][$index][0] =& $this->Application->recallObject($listener_prefix); + $this->rewriteListeners[$prefix][$index][1] = $listener_method; } } @@ -415,7 +426,7 @@ $this->_initRewriteListeners(); $page_number = $this->_parsePage($url_parts, $vars); - foreach ($this->Application->RewriteListeners as $prefix => $listeners) { + foreach ($this->rewriteListeners as $prefix => $listeners) { // set default page // $vars[$prefix . '_Page'] = 1; // will override page in session in case, when none is given in url @@ -838,7 +849,7 @@ list ($prefix) = explode('.', $pass_element); $catalog_item = $this->Application->findModule('Var', $prefix) && $this->Application->getUnitOption($prefix, 'CatalogItem'); - if ( array_key_exists($prefix, $this->Application->RewriteListeners) ) { + if ( array_key_exists($prefix, $this->rewriteListeners) ) { // if next prefix is same as current, but with special => exclude current prefix from url $next_prefix = array_key_exists($pass_index + 1, $pass_info) ? $pass_info[$pass_index + 1] : false; if ( $next_prefix ) { @@ -956,7 +967,7 @@ list ($prefix) = explode('.', $prefix_special); $url_parts = Array (); - $listener = $this->Application->RewriteListeners[$prefix][0]; + $listener = $this->rewriteListeners[$prefix][0]; $ret = $listener[0]->$listener[1](REWRITE_MODE_BUILD, $prefix_special, $params, $url_parts, $pass_events); Index: branches/5.2.x/core/kernel/managers/cache_manager.php =================================================================== diff -u -r14728 -r14787 --- branches/5.2.x/core/kernel/managers/cache_manager.php (.../cache_manager.php) (revision 14728) +++ branches/5.2.x/core/kernel/managers/cache_manager.php (.../cache_manager.php) (revision 14787) @@ -1,6 +1,6 @@ $value); $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'ConfigurationValues', 'VariableName = ' . $this->Conn->qstr($name)); - $this->DeleteUnitCache(); + if ( array_key_exists($name, $this->originalConfigVariables) && $value != $this->originalConfigVariables[$name] ) { + $this->DeleteUnitCache(); + } } /** @@ -336,63 +346,61 @@ } /** - * Deletes all data, that was cached during unit config parsing (including unit config locations) + * Deletes all data, that was cached during unit config parsing (excluding unit config locations) * - * @param bool $include_sections + * @param Array $config_variables * @access public */ - public function DeleteUnitCache($include_sections = false) + public function DeleteUnitCache($config_variables = null) { - if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { + if ( isset($config_variables) && !array_intersect(array_keys($this->originalConfigVariables), $config_variables) ) { + // prevent cache reset, when given config variables are not in unit cache + return; + } + + if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $this->Application->rebuildCache('master:configs_parsed', kCache::REBUILD_LATER, CacheSettings::$unitCacheRebuildTime); } else { $this->Application->rebuildDBCache('configs_parsed', kCache::REBUILD_LATER, CacheSettings::$unitCacheRebuildTime); } + } - if ($include_sections) { - if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { - $this->Application->rebuildCache('master:sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime); - } - else { - $this->Application->rebuildDBCache('sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime); - } + /** + * Deletes cached section tree, used during permission checking and admin console tree display + * + * @return void + * @access public + */ + public function DeleteSectionCache() + { + if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { + $this->Application->rebuildCache('master:sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime); } + else { + $this->Application->rebuildDBCache('sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime); + } } /** - * Preloads widely used configuration variables, so they will get to cache for sure + * Preloads 21 widely used configuration variables, so they will get to cache for sure * * @access protected */ protected function preloadConfigVars() { $config_vars = Array ( // session related - 'SessionTimeout', - 'SessionCookieName', - 'SessionCookieDomains', - 'SessionBrowserSignatureCheck', - 'SessionIPAddressCheck', - 'CookieSessions', - 'KeepSessionOnBrowserClose', - 'User_GuestGroup', - 'User_LoggedInGroup', - 'RegistrationUsernameRequired', + 'SessionTimeout', 'SessionCookieName', 'SessionCookieDomains', 'SessionBrowserSignatureCheck', + 'SessionIPAddressCheck', 'CookieSessions', 'KeepSessionOnBrowserClose', 'User_GuestGroup', + 'User_LoggedInGroup', 'RegistrationUsernameRequired', // output related - 'UseModRewrite', - 'UseContentLanguageNegotiation', - 'UseOutputCompression', - 'OutputCompressionLevel', - 'Config_Site_Time', - 'SystemTagCache', + 'UseModRewrite', 'UseContentLanguageNegotiation', 'UseOutputCompression', 'OutputCompressionLevel', + 'Config_Site_Time', 'SystemTagCache', // tracking related - 'UseChangeLog', - 'UseVisitorTracking', - 'ModRewriteUrlEnding', - 'ForceModRewriteUrlEnding', + 'UseChangeLog', 'UseVisitorTracking', 'ModRewriteUrlEnding', 'ForceModRewriteUrlEnding', 'UseCronForRegularEvent', ); @@ -412,12 +420,14 @@ /** * Sets data from cache to object * + * Used for cases, when ConfigValue is called before LoadApplicationCache method (e.g. session init, url engine init) + * * @param Array $data * @access public */ public function setFromCache(&$data) { - $this->configVariables = $data['Application.ConfigHash']; + $this->configVariables = $this->originalConfigVariables = $data['Application.ConfigHash']; $this->configIDs = $this->originalConfigIDs = $data['Application.ConfigCacheIds']; } Index: branches/5.2.x/core/kernel/utility/unit_config_reader.php =================================================================== diff -u -r14699 -r14787 --- branches/5.2.x/core/kernel/utility/unit_config_reader.php (.../unit_config_reader.php) (revision 14699) +++ branches/5.2.x/core/kernel/utility/unit_config_reader.php (.../unit_config_reader.php) (revision 14787) @@ -1,6 +1,6 @@ StoreCache = $cache; - if (!$this->Application->InitDone) { + if ( !$this->Application->InitDone ) { // scanModules is called multiple times during installation process $this->Application->InitManagers(); + + // get build-in rewrite listeners ONLY to be able to parse mod-rewrite url when unit config cache is missing + $this->retrieveCollections(); + $this->_sortRewriteListeners(); } $this->Application->cacheManager->applyDelayedUnitProcessing(); @@ -372,7 +376,7 @@ } /** - * Process all collectable unit config options here to also catch ones, defined from OnAfterConfigRead events + * Process all collectible unit config options here to also catch ones, defined from OnAfterConfigRead events * */ function retrieveCollections() Index: branches/5.2.x/core/kernel/application.php =================================================================== diff -u -r14714 -r14787 --- branches/5.2.x/core/kernel/application.php (.../application.php) (revision 14714) +++ branches/5.2.x/core/kernel/application.php (.../application.php) (revision 14787) @@ -1,6 +1,6 @@ UnitConfigReader =& $this->makeClass('kUnitConfigReader'); - $this->UnitConfigReader->scanModules(MODULES_PATH); + $this->UnitConfigReader->scanModules(MODULES_PATH); // will also set RewriteListeners when existing cache is read $this->registerModuleConstants(); @@ -325,7 +325,7 @@ // start processing request $this->HttpQuery =& $this->recallObject('HTTPQuery'); - $this->HttpQuery->AfterInit(); + $this->HttpQuery->AfterInit(); // TODO: only uses build-in rewrite listeners, when cache is build for the first time if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Processed HTTPQuery initial'); @@ -339,7 +339,7 @@ $this->UrlManager->LoadStructureTemplateMapping(); - $this->Session->ValidateExpired(); + $this->Session->ValidateExpired(); // needs mod_rewrite url already parsed to keep user at proper template after session expiration if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Processed HTTPQuery AfterInit'); @@ -359,7 +359,7 @@ $this->ValidateLogin(); // must be called before AfterConfigRead, because current user should be available there - $this->UnitConfigReader->AfterConfigRead(); + $this->UnitConfigReader->AfterConfigRead(); // will set RewriteListeners when missing cache is built first time if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Processed AfterConfigRead'); @@ -2725,12 +2725,29 @@ return $this->ModuleInfo['Core']['RootCat']; } - function DeleteUnitCache($include_sections = false) + /** + * Deletes all data, that was cached during unit config parsing (excluding unit config locations) + * + * @param Array $config_variables + * @access public + */ + public function DeleteUnitCache($config_variables = null) { - $this->cacheManager->DeleteUnitCache($include_sections); + $this->cacheManager->DeleteUnitCache($config_variables); } /** + * Deletes cached section tree, used during permission checking and admin console tree display + * + * @return void + * @access public + */ + public function DeleteSectionCache() + { + $this->cacheManager->DeleteSectionCache(); + } + + /** * Sets data from cache to object * * @param Array $data Index: branches/5.2.x/core/units/configuration/configuration_event_handler.php =================================================================== diff -u -r14637 -r14787 --- branches/5.2.x/core/units/configuration/configuration_event_handler.php (.../configuration_event_handler.php) (revision 14637) +++ branches/5.2.x/core/units/configuration/configuration_event_handler.php (.../configuration_event_handler.php) (revision 14787) @@ -1,6 +1,6 @@ getObject(); /* @var $object kDBItem */ - if ($object->GetDBField('ElementType') == 'password') { - if (trim($object->GetDBField('VariableValue')) == '') { + if ( $object->GetDBField('ElementType') == 'password' ) { + if ( trim($object->GetDBField('VariableValue')) == '' ) { $field_options = $object->GetFieldOptions('VariableValue'); unset($field_options['skip_empty']); $object->SetFieldOptions('VariableValue', $field_options); @@ -165,38 +167,25 @@ // allows to check if variable's value was changed now $variable_name = $object->GetDBField('VariableName'); - $variable_value = $object->GetDBField('VariableValue'); - $watch_variables = Array ( - 'Require_AdminSSL', 'AdminSSL_URL', 'AdvancedUserManagement', - 'Site_Name', 'AdminConsoleInterface', 'UsePopups' - ); + $changed = $this->Application->GetVar($event->getPrefixSpecial() . '_changed', Array ()); - if (in_array($variable_name, $watch_variables)) { - $changed = $this->Application->GetVar($event->getPrefixSpecial() . '_changed', Array ()); + if ( $object->GetDBField('VariableValue') != $object->GetOriginalField('VariableValue') ) { + $changed[] = $variable_name; + $this->Application->SetVar($event->getPrefixSpecial() . '_changed', $changed); + } - if ($variable_value != $object->GetOriginalField('VariableValue')) { - $changed[] = $variable_name; - $this->Application->SetVar($event->getPrefixSpecial() . '_changed', $changed); - } + if ( $variable_name == 'Require_AdminSSL' || $variable_name == 'AdminSSL_URL' ) { + // when administrative console is moved to SSL mode, then delete skin + if ( in_array($variable_name, $changed) && !$skin_deleted ) { + $skin_helper =& $this->Application->recallObject('SkinHelper'); + /* @var $skin_helper SkinHelper */ - switch ($variable_name) { - case 'Require_AdminSSL': - case 'AdminSSL_URL': - static $skin_deleted = false; + $skin_file = $skin_helper->getSkinPath(); + if ( file_exists($skin_file) ) { + unlink($skin_file); + } - if (in_array($variable_name, $changed) && !$skin_deleted) { - // when administrative console is moved to SSL mode, then delete skin - $skin_helper =& $this->Application->recallObject('SkinHelper'); - /* @var $skin_helper SkinHelper */ - - $skin_file = $skin_helper->getSkinPath(); - if (file_exists($skin_file)) { - unlink($skin_file); - } - - $skin_deleted = true; - } - break; + $skin_deleted = true; } } @@ -210,30 +199,31 @@ */ function OnUpdate(&$event) { - if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) { + if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; - return ; + return; } - $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); + $items_info = $this->Application->GetVar($event->getPrefixSpecial(true)); // 1. save user selected module root category $new_category_id = getArrayValue($items_info, 'ModuleRootCategory', 'VariableValue'); - if ($new_category_id !== false) { + if ( $new_category_id !== false ) { unset($items_info['ModuleRootCategory']); } $object =& $event->getObject( Array('skip_autoload' => true) ); /* @var $object kDBItem */ - if ($items_info) { + if ( $items_info ) { $has_error = false; + foreach ($items_info as $id => $field_values) { $object->Clear(); // clear validation errors from previous variable $object->Load($id); - $object->SetFieldsFromHash($field_values); + $object->SetFieldsFromHash($field_values); - if (!$object->Update($id)) { + if ( !$object->Update($id) ) { // don't stop when error found ! $has_error = true; } @@ -242,40 +232,43 @@ $event->status = $has_error ? kEvent::erFAIL : kEvent::erSUCCESS; } - if ($event->status == kEvent::erSUCCESS) { - if ($new_category_id !== false) { + if ( $event->status == kEvent::erSUCCESS ) { + if ( $new_category_id !== false ) { // root category was submitted $module = $this->Application->GetVar('module'); $root_category_id = $this->Application->findModule('Name', $module, 'RootCat'); - if ($root_category_id != $new_category_id) { + if ( $root_category_id != $new_category_id ) { // root category differs from one in db - $fields_hash = Array('RootCat' => $new_category_id); - $this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Modules', 'Name = '.$this->Conn->qstr($module)); + $fields_hash = Array ('RootCat' => $new_category_id); + $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Modules', 'Name = ' . $this->Conn->qstr($module)); } } // reset cache $changed = $this->Application->GetVar($event->getPrefixSpecial() . '_changed', Array ()); - $require_refresh = Array ( - 'AdvancedUserManagement', 'Site_Name', 'AdminConsoleInterface', 'UsePopups' - ); + $require_refresh = Array ('AdvancedUserManagement', 'Site_Name', 'AdminConsoleInterface', 'UsePopups'); $refresh_sections = array_intersect($require_refresh, $changed); $require_full_refresh = Array ('Site_Name', 'AdminConsoleInterface'); - if (array_intersect($require_full_refresh, $changed)) { + if ( array_intersect($require_full_refresh, $changed) ) { $event->SetRedirectParam('refresh_all', 1); - } elseif ($refresh_sections) { - // reset sections too, because of AdvancedUserManagement + } + elseif ( $refresh_sections ) { $event->SetRedirectParam('refresh_tree', 1); } - $this->Application->DeleteUnitCache($refresh_sections ? true : false); + if ( $refresh_sections ) { + // reset sections too, because of AdvancedUserManagement + $this->Application->DeleteSectionCache(); + } + + $this->Application->DeleteUnitCache($changed); } - elseif ($this->Application->GetVar('errors_' . $event->getPrefixSpecial())) { + elseif ( $this->Application->GetVar('errors_' . $event->getPrefixSpecial()) ) { // because we have list out there, and this is item - $this->Application->removeObject( $event->getPrefixSpecial() ); + $this->Application->removeObject($event->getPrefixSpecial()); } // keeps module and section in REQUEST to ensure, that last admin template will work