Index: branches/5.2.x/core/units/helpers/category_helper.php =================================================================== --- branches/5.2.x/core/units/helpers/category_helper.php (revision 16558) +++ branches/5.2.x/core/units/helpers/category_helper.php (revision 16559) @@ -1,361 +1,361 @@ Application->findModule('Name', $params['module']); } // Get module by category path. if ( $category_path ) { foreach ( array_reverse($category_path) as $module_category_id ) { $module_info = $this->Application->findModule('RootCat', $module_category_id); if ( $module_info && $module_info['Var'] != 'adm' ) { return $module_info; } } } - return array(); + return false; } /** * Converts multi-dimensional category structure in one-dimensional option array (category_id=>category_name) * * @param Array $data * @param int $parent_category_id * @param int $language_id * @param int $theme_id * @param int $level * @return Array * @access protected */ protected function _printChildren(&$data, $parent_category_id, $language_id, $theme_id, $level = 0) { if ( $data['ThemeId'] != $theme_id && $data['ThemeId'] != 0 ) { // don't show system templates from different themes return Array (); } $category_language = $data['l' . $language_id . '_Name'] ? $language_id : $this->_primaryLanguageId; $ret = Array ($parent_category_id => str_repeat('—', $level) . ' ' . $data['l' . $category_language . '_Name']); if ( $data['children'] ) { $level++; foreach ($data['children'] as $category_id => $category_data) { // numeric keys $ret = kUtil::array_merge_recursive($ret, $this->_printChildren($data['children'][$category_id], $category_id, $language_id, $theme_id, $level)); } } return $ret; } /** * Returns information about children under parent path (recursive) * * @param int $parent_category_id * @param Array $languages * @return Array * @access protected */ protected function _getChildren($parent_category_id, $languages) { static $items_by_parent = null, $parent_mapping = null; if ( !isset($items_by_parent) ) { $fields = $items_by_parent = Array (); foreach ($languages as $language_id) { $fields[] = 'l' . $language_id . '_Name'; } $sql = 'SELECT CategoryId AS id, ' . implode(', ', $fields) . ', ParentId, Template, ThemeId FROM ' . TABLE_PREFIX . 'Categories ORDER BY Priority DESC'; $items = $this->Conn->Query($sql, 'id'); foreach ($items as $item_id => $item_data) { $item_parent_id = $item_data['ParentId']; unset($item_data['ParentId']); if ( !array_key_exists($item_parent_id, $items_by_parent) ) { $items_by_parent[$item_parent_id] = Array (); } $item_data['children'] = false; $parent_mapping[$item_id] = $item_parent_id; $items_by_parent[$item_parent_id][$item_id] = $item_data; } $base_category = $this->Application->getBaseCategory(); // "Content" category if ( isset($items_by_parent[$base_category]) ) { $index_category = $this->findIndexCategoryId($items_by_parent[$base_category]); // rename "Content" into "Home" keeping it's ID $items_by_parent[$parent_mapping[$base_category]][$base_category]['l1_Name'] = $this->Application->Phrase('la_rootcategory_name'); if ( $index_category !== false ) { // remove category of "index.tpl" template unset($items_by_parent[$base_category][$index_category]); unset($parent_mapping[$index_category]); } } } $data = $items_by_parent[$parent_mapping[$parent_category_id]][$parent_category_id]; $categories = array_key_exists($parent_category_id, $items_by_parent) ? $items_by_parent[$parent_category_id] : Array (); foreach ($categories as $category_id => $category_data) { if ( $category_id == $parent_category_id ) { // don't process myself - prevents recursion continue; } $data['children'][$category_id] = $this->_getChildren($category_id, $languages); } return $data; } /** * Finds "Home" category among given top level categories * * @param Array $top_categories * @return bool|int * @access protected */ protected function findIndexCategoryId($top_categories) { foreach ($top_categories as $category_id => $category_info) { if ($category_info['Template'] == 'index') { return $category_id; } } return false; } /** * Generates OR retrieves from cache structure tree * * @return Array * @access protected */ protected function &_getStructureTree() { // get cached version of structure tree if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $data = $this->Application->getCache('master:StructureTree', false, CacheSettings::$structureTreeRebuildTime); } else { $data = $this->Application->getDBCache('StructureTree', CacheSettings::$structureTreeRebuildTime); } if ( $data ) { $data = unserialize($data); return $data; } // generate structure tree from scratch /** @var kMultiLanguageHelper $ml_helper */ $ml_helper = $this->Application->recallObject('kMultiLanguageHelper'); $languages = $ml_helper->getLanguages(); $root_category = $this->Application->getBaseCategory(); $data = $this->_getChildren($root_category, $languages); if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $this->Application->setCache('master:StructureTree', serialize($data)); } else { $this->Application->setDBCache('StructureTree', serialize($data)); } return $data; } /** * Returns template mapping (between physical and virtual pages) * * @return Array * @access public */ public function getTemplateMapping() { if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $data = $this->Application->getCache('master:template_mapping', false, CacheSettings::$templateMappingRebuildTime); } else { $data = $this->Application->getDBCache('template_mapping', CacheSettings::$templateMappingRebuildTime); } if ( $data ) { return unserialize($data); } $sql = 'SELECT IF(c.`Type` = ' . PAGE_TYPE_TEMPLATE . ', CONCAT(c.Template, ":", c.ThemeId), CONCAT("id:", c.CategoryId)) AS SrcTemplate, LOWER( IF( c.SymLinkCategoryId IS NOT NULL, (SELECT cc.NamedParentPath FROM ' . TABLE_PREFIX . 'Categories AS cc WHERE cc.CategoryId = c.SymLinkCategoryId), c.NamedParentPath ) ) AS DstTemplate, c.UseExternalUrl, c.ExternalUrl FROM ' . TABLE_PREFIX . 'Categories AS c WHERE c.Status = ' . STATUS_ACTIVE; $pages = $this->Conn->Query($sql, 'SrcTemplate'); $mapping = Array (); $base_url = $this->Application->BaseURL(); foreach ($pages as $src_template => $page) { // process external url, before placing in cache if ( $page['UseExternalUrl'] ) { $external_url = $page['ExternalUrl']; if ( !preg_match('/^(.*?):\/\/(.*)$/', $external_url) ) { // url without protocol will be relative url to our site $external_url = $base_url . $external_url; } $dst_template = 'external:' . $external_url; } else { $dst_template = preg_replace('/^Content\//i', '', $page['DstTemplate']); } $mapping[$src_template] = $dst_template; } if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $data = $this->Application->setCache('master:template_mapping', serialize($mapping)); } else { $this->Application->setDBCache('template_mapping', serialize($mapping)); } return $mapping; } /** * Returns category structure as field option list * * @return Array * @access public */ public function getStructureTreeAsOptions() { if ( (defined('IS_INSTALL') && IS_INSTALL) || !$this->Application->isAdmin ) { // no need to create category structure during install // OR on Front-End, because it's not used there return Array (); } if ( isset($this->_structureTree) ) { return $this->_structureTree; } /** @var kThemesHelper $themes_helper */ $themes_helper = $this->Application->recallObject('ThemesHelper'); $data = $this->_getStructureTree(); $theme_id = (int)$themes_helper->getCurrentThemeId(); $this->_primaryLanguageId = $this->Application->GetDefaultLanguageId(); $this->_structureTree = $this->_printChildren($data, $data['id'], $this->Application->GetVar('m_lang'), $theme_id); return $this->_structureTree; } /** * Replace links like "@@ID@@" to actual template names in given text * * @param string $text * @return string * @access public */ public function replacePageIds($text) { if ( !preg_match_all('/@@(\\d+)@@/', $text, $regs) ) { return $text; } $page_ids = $regs[1]; $sql = 'SELECT NamedParentPath, CategoryId FROM ' . TABLE_PREFIX . 'Categories WHERE CategoryId IN (' . implode(',', $page_ids) . ')'; $templates = $this->Conn->GetCol($sql, 'CategoryId'); $base_category = $this->Application->getBaseCategory(); if ( isset($templates[$base_category]) ) { // "Content" category will act as "Home Page" $templates[$base_category] .= '/Index'; } foreach ($page_ids as $page_id) { if ( !isset($templates[$page_id]) ) { // internal page was deleted, but link to it was found in given content block data continue; } $url_params = Array ('m_cat_id' => $page_id == $base_category ? 0 : $page_id, 'pass' => 'm'); $page_url = $this->Application->HREF(strtolower($templates[$page_id]), '', $url_params); /*if ($this->Application->isAdmin) { $page_url = preg_replace('/&(admin|editing_mode)=[\d]/', '', $page_url); }*/ $text = str_replace('@@' . $page_id . '@@', $page_url, $text); } return $text; } } Index: branches/5.2.x/core/units/helpers/navigation_bar.php =================================================================== --- branches/5.2.x/core/units/helpers/navigation_bar.php (revision 16558) +++ branches/5.2.x/core/units/helpers/navigation_bar.php (revision 16559) @@ -1,379 +1,379 @@ _params = $params; $this->_params['is_first'] = 1; $home_element = $this->_getHomeElement(); if ( !getArrayValue($this->_params, 'titles') && !getArrayValue($this->_params, 'templates') ) { // no static templates given, show only category path return $home_element . $this->getCategoryPath(); } $ret = ''; $block_params = $this->_getBaseParams(); $current_template = $this->_getCurrentTemplate(); $navigation_parts = $this->getNavigationParts(); foreach ($navigation_parts as $template => $title) { $block_params['template'] = $template; if ( $title == '__categorypath__' ) { $ret .= $this->getCategoryPath(); } else { $is_current = $template == $current_template; $block_params['current'] = $is_current; if ( substr($title, 0, 2) == '__' ) { $block_params['title'] = $title; $block_params['name'] = $this->SelectParam($this->_params, 'custom_render_as,render_as'); } else { $block_params['title'] = $this->Application->Phrase($title); $block_params['name'] = $this->_params[$is_current ? 'current_render_as' : 'render_as']; } $ret .= $this->Application->ParseBlock($block_params); } } return $home_element . $ret; } /** * Returns base params for rendering each navigation bar element * * @return Array * @access protected */ protected function _getBaseParams() { $block_params = Array ( 'no_editing' => 1, 'category' => 0, 'separator' => $this->_params['separator'], 'current' => 0, ); return $block_params; } /** * Returns the name of current physical template * * @return string * @access protected */ protected function _getCurrentTemplate() { return $this->Application->getPhysicalTemplate($this->Application->GetVar('t')); } /** * Returns element for "Home" category * * @return string * @access protected */ protected function _getHomeElement() { if ( isset($this->_params['shift']) && $this->_params['shift'] ) { $home_element = ''; $this->_params['shift']--; } else { $home_element = $this->_getHomeCategoryPath(); unset($this->_params['is_first']); } return $home_element; } /** * Renders path to top catalog category * * @return string * @access protected */ protected function _getHomeCategoryPath() { $block_params = $this->_getBaseParams(); $block_params['cat_id'] = $this->Application->getBaseCategory(); $block_params['current'] = $this->_getCurrentCategoryId() == $block_params['cat_id'] ? 1 : 0; $block_params['is_first'] = $this->_params['is_first']; $block_params['template'] = ''; // to prevent warning when category element is rendered using general "render_as" block $category_name = $this->Application->Phrase(($this->Application->isAdmin ? 'la_' : 'lu_') . 'rootcategory_name'); $block_params['cat_name'] = $block_params['title'] = $category_name; $block_params['name'] = $this->SelectParam($this->_params, 'root_cat_render_as,category_render_as,render_as'); if ( $block_params['current'] ) { $block_params['name'] = $this->SelectParam($this->_params, 'current_render_as,render_as'); } return $this->Application->ParseBlock($block_params); } /** * Returns currently selected category * * @return mixed */ protected function _getCurrentCategoryId() { return isset($this->_params['cat_id']) ? $this->_params['cat_id'] : $this->Application->GetVar('m_cat_id'); } /** * Get navigation parts * * @return Array * @access protected */ protected function getNavigationParts() { $titles = explode(',', $this->_params['titles']); $templates = explode(',', $this->_params['templates']); if ( getArrayValue($this->_params, 'show_category') && !in_array('__categorypath__', $titles) ) { // insert before __item__ or first element, when __item__ isn't specified $item_index = (int)array_search('__item__', $titles); array_splice($titles, $item_index, 0, '__categorypath__'); array_splice($templates, $item_index, 0, '__categorypath__'); } return array_combine($templates, $titles); } /** * Renders path to given category using given blocks. * * @return string * @access protected */ protected function getCategoryPath() { $category_path = $this->getCategoryParentPath(); if ( !$category_path ) { // in "Home" category return ''; } $main_category_id = $this->_getCurrentCategoryId(); /** @var CategoryHelper $category_helper */ $category_helper = $this->Application->recallObject('CategoryHelper'); $module_info = $category_helper->getCategoryModule($this->_params, array_keys($category_path)); - $module_item_id = $this->Application->GetVar($module_info['Var'] . '_id'); + $module_item_id = $module_info ? $this->Application->GetVar($module_info['Var'] . '_id') : false; $ret = ''; $block_params = $this->_getBaseParams(); $block_params['category'] = 1; $block_params['template'] = ''; // to prevent warning when category element is rendered using general "render_as" block if ( isset($this->_params['is_first']) ) { $block_params['is_first'] = $this->_params['is_first']; } $block_params['separator'] = $this->_params['separator']; $no_current = isset($this->_params['no_current']) && $this->_params['no_current']; $backup_category_id = $this->Application->GetVar('c_id'); foreach ($this->shiftCategoryPath($category_path) as $category_id => $category_name) { $block_params['cat_id'] = $category_id; $block_params['cat_name'] = $block_params['title'] = $category_name; if ( $no_current ) { $block_params['current'] = 0; } else { $block_params['current'] = ($main_category_id == $category_id) && !$module_item_id ? 1 : 0; } $block_params['name'] = $this->SelectParam($this->_params, 'category_render_as,render_as'); if ( $block_params['current'] ) { $block_params['name'] = $this->SelectParam($this->_params, 'current_render_as,render_as'); } $this->Application->SetVar('c_id', $category_id); $ret .= $this->Application->ParseBlock($block_params); if ( array_key_exists('is_first', $block_params) ) { unset($block_params['is_first']); } } $this->Application->SetVar('c_id', $backup_category_id); return $ret; } /** * Shift category path. * * @param array $category_path Category path. * * @return array */ protected function shiftCategoryPath(array $category_path) { if ( isset($this->_params['shift']) && $this->_params['shift'] ) { return array_slice($category_path, $this->_params['shift'], null, true); } return $category_path; } /** * Returns given category's parent path as array of id=>name elements * * @return Array * @access protected */ protected function getCategoryParentPath() { $main_category_id = $this->_getCurrentCategoryId(); if ( $main_category_id == 0 ) { // don't query path for "Home" category return Array (); } $category_title = isset($this->_params['category_title']) ? $this->_params['category_title'] : 'Name'; $cache_key = 'parent_paths_named[%CIDSerial:' . $main_category_id . '%]:' . $category_title; $cached_path = $this->Application->getCache($cache_key); if ( $cached_path === false ) { $parent_path = explode('|', substr($this->getParentPath($main_category_id), 1, -1)); /** @var kMultiLanguage $ml_formatter */ $ml_formatter = $this->Application->recallObject('kMultiLanguage'); $navbar_field = $ml_formatter->LangFieldName($category_title); $id_field = $this->Application->getUnitOption('c', 'IDField'); $table_name = $this->Application->getUnitOption('c', 'TableName'); $this->Conn->nextQueryCachable = true; $sql = 'SELECT ' . $navbar_field . ', ' . $id_field . ' FROM ' . $table_name . ' WHERE ' . $id_field . ' IN (' . implode(',', $parent_path) . ')'; $category_names = $this->Conn->GetCol($sql, $id_field); $cached_path = Array (); $skip_category = $this->Application->getBaseCategory(); if ( $category_names ) { foreach ($parent_path as $category_id) { if ( $category_id == $skip_category ) { continue; } $cached_path[$category_id] = $category_names[$category_id]; } } $this->Application->setCache($cache_key, $cached_path); } return $cached_path; } /** * Returns parent path from a given category * * @param int $category_id * @return string * @access public */ public function getParentPath($category_id) { $cache_key = 'parent_paths[%CIDSerial:' . $category_id . '%]'; $parent_path = $this->Application->getCache($cache_key); if ( $parent_path !== false ) { return $parent_path; } $this->Conn->nextQueryCachable = true; $sql = 'SELECT ParentPath FROM ' . $this->Application->getUnitOption('c', 'TableName') . ' WHERE ' . $this->Application->getUnitOption('c', 'IDField') . ' = ' . $category_id; $parent_path = $this->Conn->GetOne($sql); $this->Application->setCache($cache_key, $parent_path); return $parent_path; } /** * Not tag. Method for parameter selection from list in this TagProcessor * * @param Array $params * @param Array $possible_names * * @return string * @access protected */ protected function SelectParam($params, $possible_names) { if ( !is_array($params) ) { return ''; } if ( !is_array($possible_names) ) { $possible_names = explode(',', $possible_names); } foreach ($possible_names as $name) { if ( isset($params[$name]) ) { return $params[$name]; } } return ''; } }