Index: menu_helper.php =================================================================== --- menu_helper.php (revision 15384) +++ menu_helper.php (working copy) @@ -20,15 +20,17 @@ * Cached version of site menu * * @var Array + * @access protected */ - var $Menu = null; + protected $Menu = NULL; /** * Parent path mapping used in CachedMenu tag * * @var Array + * @access protected */ - var $parentPaths = Array (); + protected $parentPaths = Array (); /** * Builds site menu @@ -49,11 +51,11 @@ $levels = explode('|', trim($parent_path, '|')); - if ($levels[0] === '') { + if ( $levels[0] === '' ) { $levels = Array (); } - if (array_key_exists('level', $params) && $params['level'] > count($levels)) { + if ( array_key_exists('level', $params) && $params['level'] > count($levels) ) { // current level is deeper, then requested level return ''; } @@ -74,7 +76,7 @@ $this->Application->SetVar('cur_parent_path', $parent_path); $real_cat_id = $this->Application->GetVar('m_cat_id'); - if (!is_array($cur_menu) || !$cur_menu) { + if ( !is_array($cur_menu) || !$cur_menu ) { // no menus on this level return ''; } @@ -85,10 +87,7 @@ $block_params['total_items'] = count($cur_menu); foreach ($cur_menu as $page) { - $block_params = array_merge( - $block_params, - $this->_prepareMenuItem($page, $real_cat_id, $root_path) - ); + $block_params = array_merge($block_params, $this->_prepareMenuItem($page, $real_cat_id, $root_path)); $block_params['is_last'] = $cur_item == $block_params['total_items']; $block_params['is_first'] = $cur_item == 1; @@ -106,18 +105,18 @@ * Builds cached menu version * * @return Array + * @access protected */ - function _prepareMenu() + protected function _prepareMenu() { - static $root_cat = null; - static $root_path = null; + static $root_cat = NULL, $root_path = NULL; - if (!$root_cat) { + if ( !$root_cat ) { $root_cat = $this->Application->getBaseCategory(); $cache_key = 'parent_paths[%CIDSerial:' . $root_cat . '%]'; $root_path = $this->Application->getCache($cache_key); - if ($root_path === false) { + if ( $root_path === false ) { $this->Conn->nextQueryCachable = true; $sql = 'SELECT ParentPath FROM ' . TABLE_PREFIX . 'Categories @@ -135,15 +134,15 @@ $menu = $this->Application->getDBCache('cms_menu', CacheSettings::$cmsMenuRebuildTime); } - if ($menu) { + if ( $menu ) { $menu = unserialize($menu); $this->parentPaths = $menu['parentPaths']; } else { - $menu = $this->_altBuildMenuStructure(Array ('CategoryId' => $root_cat, 'ParentPath' => $root_path)); + $menu = $this->_buildMenuStructure($root_cat); $menu['parentPaths'] = $this->parentPaths; - if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { + if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $this->Application->setCache('master:cms_menu', serialize($menu)); } else { @@ -167,13 +166,14 @@ function _getCategoryId($params) { $cat = isset($params['category_id']) && $params['category_id'] != '' ? $params['category_id'] : $this->Application->GetVar('m_cat_id'); - if ("$cat" == 'parent') { + + if ( "$cat" == 'parent' ) { $this_category = $this->Application->recallObject('c'); /* @var $this_category kDBItem */ $cat = $this_category->GetDBField('ParentId'); } - elseif ($cat == 0) { + elseif ( $cat == 0 ) { $cat = $this->Application->getBaseCategory(); } @@ -187,14 +187,13 @@ * @param int $real_cat_id * @param string $root_path * @return Array + * @access protected */ - function _prepareMenuItem($page, $real_cat_id, $root_path) + protected function _prepareMenuItem($page, $real_cat_id, $root_path) { - static $language_id = null; - static $primary_language_id = null; - static $template = null; + static $language_id = NULL, $primary_language_id = NULL, $template = NULL; - if (!isset($language_id)) { + if ( !isset($language_id) ) { $language_id = $this->Application->GetVar('m_lang'); $primary_language_id = $this->Application->GetDefaultLanguageId(); $template = $this->Application->GetVar('t'); @@ -203,11 +202,11 @@ $active = $category_active = false; $title = $page['l' . $language_id . '_ItemName'] ? $page['l' . $language_id . '_ItemName'] : $page['l' . $primary_language_id . '_ItemName']; - if ($page['ItemType'] == 'cat') { - if (array_key_exists($real_cat_id, $this->parentPaths)) { + if ( $page['ItemType'] == 'cat' ) { + if ( array_key_exists($real_cat_id, $this->parentPaths) ) { $active = strpos($this->parentPaths[$real_cat_id], $page['ParentPath']) !== false; } - elseif ($page['ItemPath'] == $template) { + elseif ( $page['ItemPath'] == $template ) { // physical template in menu $active = true; } @@ -215,12 +214,12 @@ $category_active = $page['CategoryId'] == $real_cat_id; } - /*if ($page['ItemType'] == 'cat_index') { + /*if ( $page['ItemType'] == 'cat_index' ) { $check_path = str_replace($root_path, '', $page['ParentPath']); $active = strpos($parent_path, $check_path) !== false; } - if ($page['ItemType'] == 'page') { + if ( $page['ItemType'] == 'page' ) { $active = $page['ItemPath'] == preg_replace('/^Content\//i', '', $this->Application->GetVar('t')); }*/ @@ -253,14 +252,15 @@ * * @param Array $menu * @return Array + * @access protected */ - function _removeNonMenuItems($menu) + protected function _removeNonMenuItems($menu) { $theme_id = $this->Application->GetVar('m_theme'); foreach ($menu as $menu_index => $menu_item) { // $menu_index is in "cN" format, where N is category id - if (!$menu_item['IsMenu'] || $menu_item['Status'] != STATUS_ACTIVE || ($menu_item['ThemeId'] != $theme_id && $menu_item['ThemeId'] != 0)) { + if ( !$menu_item['IsMenu'] || $menu_item['Status'] != STATUS_ACTIVE || ($menu_item['ThemeId'] != $theme_id && $menu_item['ThemeId'] != 0) ) { // don't show sections, that are not from menu OR system templates from other themes unset($menu[$menu_index]); } @@ -270,52 +270,61 @@ } /** - * Builds cache for children of given category (no matter, what menu status is) + * Builds cache of all menu items and their parent categories * - * @param Array $parent + * @param int $top_category_id * @return Array + * @access protected */ - function _altBuildMenuStructure($parent) + protected function _buildMenuStructure($top_category_id) { - static $lang_part = null; + // 1. get parent paths of leaf categories, that are in menu (across all themes) + $sql = 'SELECT ParentPath, CategoryId + FROM ' . $this->Application->getUnitOption('c', 'TableName') . ' + WHERE IsMenu = 1 AND Status = ' . STATUS_ACTIVE; + $this->parentPaths = $this->Conn->GetCol($sql ,'CategoryId'); - if (!isset($lang_part)) { - $ml_helper = $this->Application->recallObject('kMultiLanguageHelper'); - /* @var $ml_helper kMultiLanguageHelper */ + // 2. figure out parent paths of all categories in path to leaf categories + foreach ($this->parentPaths as $leaf_parent_path) { + $parent_categories = explode('|', substr($leaf_parent_path, 1, -1)); - $lang_part = ''; - $languages = $ml_helper->getLanguages(); - - foreach ($languages as $language_id) { - $lang_part .= 'c.l' . $language_id . '_MenuTitle AS l' . $language_id . '_ItemName,' . "\n"; + foreach ($parent_categories as $index => $parent_category_id) { + if ( !isset($this->parentPaths[$parent_category_id]) ) { + $parent_path = array_slice($parent_categories, 0, $index + 1); + $this->parentPaths[$parent_category_id] = '|' . implode('|', $parent_path) . '|'; + } } } + return $this->_altBuildMenuStructure($top_category_id, implode(',', array_keys($this->parentPaths))); + } + + /** + * Builds cache for children of given category (no matter, what menu status is) + * + * @param int $parent_category_id + * @param string $category_limit + * @return Array + * @access protected + */ + protected function _altBuildMenuStructure($parent_category_id, $category_limit = NULL) + { // Sub-categories from current category - $items = $this->getSubCategories( $parent['CategoryId'] ); + $items = $this->_getSubCategories($parent_category_id, $category_limit); // sort menu items uasort($items, Array (&$this, '_menuSort')); - // store menu items - $the_items = Array(); - foreach ($items as $index => $an_item) { - $the_items[ $an_item['ItemId'] ] = $an_item; - - $this->parentPaths[ $an_item['CategoryId'] ] = $an_item['ParentPath']; - } - - // process submenus of each menu - $items = $the_items; + // process sub-menus of each menu foreach ($items as $key => $menu_item) { - if ($menu_item['CategoryId'] == $parent['CategoryId']) { + if ( $menu_item['CategoryId'] == $parent_category_id ) { // don't process myself - prevents recursion continue; } - $sub_items = $this->_altBuildMenuStructure($menu_item); + $sub_items = $this->_altBuildMenuStructure($menu_item['CategoryId'], $category_limit); - if ($sub_items) { + if ( $sub_items ) { $items[$key]['sub_items'] = $sub_items; } } @@ -323,22 +332,33 @@ return $items; } - function getSubCategories($parent_id) + /** + * Returns given category sub-categories + * + * @param int $parent_id + * @param string $category_limit + * @return Array + * @access protected + */ + protected function _getSubCategories($parent_id, $category_limit = NULL) { - static $items_by_parent = null; + static $items_by_parent = NULL, $lang_part = NULL; - if (!isset($items_by_parent)) { + if ( !isset($lang_part) ) { $ml_helper = $this->Application->recallObject('kMultiLanguageHelper'); /* @var $ml_helper kMultiLanguageHelper */ $lang_part = ''; - $items_by_parent = Array (); $languages = $ml_helper->getLanguages(); foreach ($languages as $language_id) { $lang_part .= 'c.l' . $language_id . '_MenuTitle AS l' . $language_id . '_ItemName,' . "\n"; } + } + if ( !isset($items_by_parent) ) { + $items_by_parent = Array (); + // Sub-categories from current category $sql = 'SELECT c.CategoryId AS CategoryId, @@ -353,6 +373,11 @@ c.IsMenu, c.Type, c.ThemeId, c.UseExternalUrl, c.ExternalUrl, c.UseMenuIconUrl, c.MenuIconUrl, c.Status FROM ' . TABLE_PREFIX . 'Categories AS c'; + + if ( isset($category_limit) && $category_limit ) { + $sql .= ' WHERE c.CategoryId IN (' . $category_limit . ')'; + } + $items = $this->Conn->Query($sql, 'ItemId'); foreach ($items as $item_id => $item_data) { @@ -370,7 +395,7 @@ } /** - * Method for sorting pages by priority in decending order + * Method for sorting pages by priority in descending order * * @param Array $a * @param Array $b @@ -378,10 +403,10 @@ */ function _menuSort($a, $b) { - if ($a['ItemPriority'] == $b['ItemPriority']) { + if ( $a['ItemPriority'] == $b['ItemPriority'] ) { return 0; } - return ($a['ItemPriority'] < $b['ItemPriority']) ? 1 : -1; //descending + return ($a['ItemPriority'] < $b['ItemPriority']) ? 1 : -1; // descending } }