Index: install/install_schema.sql =================================================================== --- install/install_schema.sql (revision 15373) +++ install/install_schema.sql (working copy) @@ -482,6 +482,7 @@ TreeLeft bigint(20) NOT NULL DEFAULT '0', TreeRight bigint(20) NOT NULL DEFAULT '0', NamedParentPath text, + NamedParentPathHash int(10) unsigned NOT NULL DEFAULT '0', MetaDescription text, HotItem int(11) NOT NULL DEFAULT '2', NewItem int(11) NOT NULL DEFAULT '2', @@ -489,6 +490,7 @@ Modified int(11) DEFAULT NULL, ModifiedById int(11) DEFAULT NULL, CachedTemplate varchar(255) NOT NULL DEFAULT '', + CachedTemplateHash int(10) unsigned NOT NULL DEFAULT '0', Template varchar(255) NOT NULL DEFAULT '#inherit#', UseExternalUrl tinyint(3) unsigned NOT NULL DEFAULT '0', ExternalUrl varchar(255) NOT NULL DEFAULT '', @@ -551,7 +553,9 @@ KEY PageExpiration (PageExpiration), KEY Protected (Protected), KEY LiveRevisionNumber (LiveRevisionNumber), - KEY PromoBlockGroupId (PromoBlockGroupId) + KEY PromoBlockGroupId (PromoBlockGroupId), + KEY NamedParentPathHash (NamedParentPathHash), + KEY CachedTemplateHash (CachedTemplateHash) ); CREATE TABLE CategoryCustomData ( Index: install/upgrades.sql =================================================================== --- install/upgrades.sql (revision 15373) +++ install/upgrades.sql (working copy) @@ -2750,3 +2750,9 @@ UPDATE LanguageLabels SET l<%PRIMARY_LANGUAGE%>_Translation = '<TITLE> Tag' WHERE PhraseKey = 'LA_FLD_PAGECONTENTTITLE'; ALTER TABLE EmailLog ADD EventType TINYINT(4) NULL AFTER EventName; DELETE FROM UserPersistentSessionData WHERE VariableName IN ('email-log[Default]columns_.', 'promo-block[Default]columns_.'); + +ALTER TABLE Categories + ADD NamedParentPathHash INT UNSIGNED NOT NULL DEFAULT '0' AFTER NamedParentPath, + ADD CachedTemplateHash INT UNSIGNED NOT NULL DEFAULT '0' AFTER CachedTemplate, + ADD INDEX (NamedParentPathHash), + ADD INDEX (CachedTemplateHash); Index: units/categories/cache_updater.php =================================================================== --- units/categories/cache_updater.php (revision 15359) +++ units/categories/cache_updater.php (working copy) @@ -420,28 +420,32 @@ function UpdateCachedPath(&$data) { - if ($data['current_id'] == 0) { + if ( $data['current_id'] == 0 ) { // don't update non-existing "Home" category - return ; + return; } + // allow old fashion system templates to work (maybe this is no longer needed, since no such urls after upgrade from 4.3.1) + $named_parent_path = strpos($data['file_name'], '/') !== false ? $data['file_name'] : implode('/', $data['named_path']); + $fields_hash = Array ( - 'ParentPath' => '|'.implode('|', $data['parent_path']).'|', - // allow old fashion system templates to work - 'NamedParentPath' => strpos($data['file_name'], '/') !== false ? $data['file_name'] : implode('/', $data['named_path'] ), - 'CachedTemplate' => $data['template'], - 'CachedDescendantCatsQty' => $data['children_count'], + 'ParentPath' => '|' . implode('|', $data['parent_path']) . '|', + 'NamedParentPath' => $named_parent_path, // url component for a category page + 'NamedParentPathHash' => kUtil::crc32(mb_strtolower(preg_replace('/^Content\//i', '', $named_parent_path))), + 'CachedTemplate' => $data['template'], // actual template to use when category is visited + 'CachedTemplateHash' => kUtil::crc32(mb_strtolower($data['template'])), + 'CachedDescendantCatsQty' => $data['children_count'], 'TreeLeft' => $data['left'], 'TreeRight' => $data['right'], ); foreach ($this->languages as $language_id) { - $fields_hash['l'.$language_id.'_CachedNavbar'] = implode('&|&', $data['titles'][$language_id]); + $fields_hash['l' . $language_id . '_CachedNavbar'] = implode('&|&', $data['titles'][$language_id]); } - $this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Categories', 'CategoryId = '.$data['current_id']); + $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Categories', 'CategoryId = ' . $data['current_id']); - if ($this->Conn->getAffectedRows() > 0) { + if ( $this->Conn->getAffectedRows() > 0 ) { $this->Application->incrementCacheSerial('c', $data['current_id']); } } Index: units/categories/categories_config.php =================================================================== --- units/categories/categories_config.php (revision 15359) +++ units/categories/categories_config.php (working copy) @@ -333,6 +333,7 @@ 'TreeLeft' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'TreeRight' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'NamedParentPath' => Array ('type' => 'string', 'default' => null), + 'NamedParentPathHash' => Array ('type' => 'string', 'not_null' => 1, 'default' => 0), 'MetaDescription' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => null), 'HotItem' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (2 => 'la_Auto', 1 => 'la_Always', 0 => 'la_Never'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 2), 'NewItem' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (2 => 'la_Auto', 1 => 'la_Always', 0 => 'la_Never'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 2), @@ -340,6 +341,7 @@ 'Modified' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'), 'ModifiedById' => Array ('type' => 'int', 'formatter' => 'kLEFTFormatter', 'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!'), 'options' => Array (USER_ROOT => 'root', USER_GUEST => 'Guest'),'left_sql'=>'SELECT %s FROM '.TABLE_PREFIX.'Users WHERE `%s` = \'%s\'', 'left_key_field' => 'PortalUserId', 'left_title_field' => 'Username', 'default' => NULL), 'CachedTemplate' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''), + 'CachedTemplateHash' => Array ('type' => 'string', 'not_null' => 1, 'default' => 0), // fields from Pages 'Template' => Array ( Index: units/categories/categories_event_handler.php =================================================================== --- units/categories/categories_event_handler.php (revision 15361) +++ units/categories/categories_event_handler.php (working copy) @@ -617,13 +617,14 @@ // bug: when template contains "-" symbols (or others, that stripDisallowed will replace) it's not found if (!array_key_exists($template, $page_by_template)) { + $template_crc = kUtil::crc32(mb_strtolower($template)); + $sql = 'SELECT ' . $this->Application->getUnitOption($event->Prefix, 'IDField') . ' FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . ' WHERE ( - (NamedParentPath = ' . $this->Conn->qstr($template) . ') OR - (NamedParentPath = ' . $this->Conn->qstr('Content/' . $template) . ') OR - (`Type` = ' . PAGE_TYPE_TEMPLATE . ' AND CachedTemplate = ' . $this->Conn->qstr($template) . ') + (NamedParentPathHash = ' . $template_crc . ') OR + (`Type` = ' . PAGE_TYPE_TEMPLATE . ' AND CachedTemplateHash = ' . $template_crc . ') ) AND (ThemeId = ' . $this->_getCurrentThemeId() . ' OR ThemeId = 0)'; $page_id = $this->Conn->GetOne($sql); @@ -719,7 +720,7 @@ if ( $event->getEventParam('temp_id') == 0 ) { if ( $object->isLoaded() ) { // update path only for real categories (not including "Home" root category) - $fields_hash = Array ('ParentPath' => $object->buildParentPath()); + $fields_hash = $object->buildParentBasedFields(); $this->Conn->doUpdate($fields_hash, $object->TableName, 'CategoryId = ' . $object->GetID()); $parent_path = $fields_hash['ParentPath']; } @@ -2213,14 +2214,9 @@ /* @var $object CategoriesItem */ // need to update path after category is created, so category is included in that path - $parent_path = $object->buildParentPath(); - - $sql = 'UPDATE ' . $object->TableName . ' - SET ParentPath = ' . $this->Conn->qstr($parent_path) . ' - WHERE CategoryId = ' . $object->GetID(); - $this->Conn->Query($sql); - - $object->SetDBField('ParentPath', $parent_path); + $fields_hash = $object->buildParentBasedFields(); + $this->Conn->doUpdate($fields_hash, $object->TableName, $object->IDField . ' = ' . $object->GetID()); + $object->SetDBFieldsFromHash($fields_hash); } /** Index: units/categories/categories_item.php =================================================================== --- units/categories/categories_item.php (revision 15359) +++ units/categories/categories_item.php (working copy) @@ -19,24 +19,58 @@ /** * Builds parent path for this category * - * @return string + * @return Array * @access public */ - public function buildParentPath() + public function buildParentBasedFields() { + static $parent_cache = Array ( + 0 => Array ('ParentPath' => '|', 'NamedParentPath' => '', 'CachedTemplate' => ''), + ); + + $ml_helper = $this->Application->recallObject('kMultiLanguageHelper'); + /* @var $ml_helper kMultiLanguageHelper */ + + $languages = $ml_helper->getLanguages(); $parent_id = $this->GetDBField('ParentId'); - if ( $parent_id == 0 ) { - $parent_path = '|'; + if ( !isset($parent_cache[$parent_id]) ) { + $select_fields = Array ('ParentPath', 'NamedParentPath', 'Template', 'CachedTemplate'); + + foreach ($languages as $language_id) { + $select_fields[] = 'l' . $language_id . '_Name'; + $select_fields[] = 'l' . $language_id . '_CachedNavbar'; + } + + $sql = 'SELECT ' . implode(', ', $select_fields) . ' + FROM ' . $this->Application->getUnitOption($this->Prefix, 'TableName') . ' + WHERE CategoryId = ' . $parent_id; + $parent_cache[$parent_id] = $this->Conn->GetRow($sql); } - else { - $sql = 'SELECT ParentPath - FROM ' . $this->Application->getUnitOption($this->Prefix, 'TableName') . ' WHERE - CategoryId = ' . $parent_id; - $parent_path = $this->Conn->GetOne($sql); + + $named_parent_path = trim($parent_cache[$parent_id]['NamedParentPath'] . '/' . $this->GetDBField('Filename'), '/'); + $cached_template = $this->GetDBField('Template') == CATEGORY_TEMPLATE_INHERIT ? $parent_cache[$parent_id]['CachedTemplate'] : $this->GetDBField('Template'); + + // maybe also build CachedNavbar field here + $ret = Array ( + 'ParentPath' => $parent_cache[$parent_id]['ParentPath'] . $this->GetID() . '|', + 'NamedParentPath' => $named_parent_path, + 'NamedParentPathHash' => kUtil::crc32(mb_strtolower(preg_replace('/^Content\//i', '', $named_parent_path))), + 'CachedTemplate' => $cached_template, + 'CachedTemplateHash' => kUtil::crc32(mb_strtolower($cached_template)), + ); + + $primary_language = $this->Application->GetDefaultLanguageId(); + + foreach ($languages as $language_id) { + $language_prefix = 'l' . $language_id . '_'; + $cached_navbar = $parent_cache[$parent_id][$language_prefix . 'CachedNavbar'] . '&|&'; + $cached_navbar .= $this->GetDBField($language_prefix . 'Name') ? $this->GetDBField($language_prefix . 'Name') : $this->GetDBField('l' . $primary_language . '_Name'); + + $ret['l' . $language_id . '_CachedNavbar'] = $cached_navbar; } - return $parent_path . $this->GetID() . '|'; + return $ret; } /** Index: units/categories/categories_tag_processor.php =================================================================== --- units/categories/categories_tag_processor.php (revision 15389) +++ units/categories/categories_tag_processor.php (working copy) @@ -1156,7 +1156,7 @@ } // different path in structure AND design template differes from requested template - $structure_path_match = strtolower( $page->GetDBField('NamedParentPath') ) == strtolower('Content/' . $template); + $structure_path_match = mb_strtolower( $page->GetDBField('NamedParentPath') ) == mb_strtolower('Content/' . $template); $design_match = $page->GetDBField('CachedTemplate') == $template; if (!$structure_path_match && !$design_match) { Index: units/helpers/themes_helper.php =================================================================== --- units/helpers/themes_helper.php (revision 15359) +++ units/helpers/themes_helper.php (working copy) @@ -603,12 +603,14 @@ $theme_id = (int)$this->getCurrentThemeId(); } + $template_crc = kUtil::crc32(mb_strtolower($template)); + $sql = 'SELECT ' . $this->Application->getUnitOption('c', 'IDField') . ' FROM ' . $this->Application->getUnitOption('c', 'TableName') . ' WHERE ( - (NamedParentPath = ' . $this->Conn->qstr('Content/' . $template) . ') OR - (`Type` = ' . PAGE_TYPE_TEMPLATE . ' AND CachedTemplate = ' . $this->Conn->qstr($template) . ') + (NamedParentPathHash = ' . $template_crc . ') OR + (`Type` = ' . PAGE_TYPE_TEMPLATE . ' AND CachedTemplateHash = ' . $template_crc . ') ) AND (ThemeId = ' . $theme_id . ($theme_id > 0 ? ' OR ThemeId = 0' : '') . ')'; Index: units/structure/structure_config.php =================================================================== --- units/structure/structure_config.php (revision 15359) +++ units/structure/structure_config.php (working copy) @@ -147,6 +147,7 @@ 'TreeLeft' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'TreeRight' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'NamedParentPath' => Array('type' => 'string', 'default' => null), + 'NamedParentPathHash' => Array ('type' => 'string', 'not_null' => 1, 'default' => 0), 'MetaDescription' => Array('type' => 'string', 'default' => null), 'HotItem' => Array('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (2 => 'la_Auto', 1 => 'la_Always', 0 => 'la_Never'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 2), 'NewItem' => Array('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (2 => 'la_Auto', 1 => 'la_Always', 0 => 'la_Never'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 2), @@ -154,6 +155,7 @@ 'Modified' => Array('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'), 'ModifiedById' => Array('type' => 'int', 'formatter' => 'kLEFTFormatter', 'options' => Array(USER_ROOT => 'root', USER_GUEST => 'Guest'),'left_sql'=>'SELECT %s FROM '.TABLE_PREFIX.'Users WHERE `%s` = \'%s\'', 'left_key_field' => 'PortalUserId', 'left_title_field' => 'Username', 'default' => NULL), 'CachedTemplate' => Array('type' => 'string', 'not_null' => 1, 'default' => ''), + 'CachedTemplateHash' => Array ('type' => 'string', 'not_null' => 1, 'default' => 0), // fields from Pages