Application->GetVar('m_cat_id'); if (array_key_exists('shift', $params) && $params['shift']) { $home_element = ''; $params['shift']--; } else { $home_element = $this->getHomeCategoryPath($params, $main_category_id); unset($params['is_first']); } if (!getArrayValue($params, 'titles') && !getArrayValue($params, 'templates')) { // no static templates given, show only category path return $home_element . $this->getCategoryPath($main_category_id, $params); } $navigation_parts = $this->getNavigationParts($params['titles'], $params['templates']); $ret = ''; $block_params = Array (); //$params; // sort of TagProcessor:prepareTagParams $block_params['no_editing'] = 1; $block_params['category'] = 0; $block_params['separator'] = $params['separator']; $show_category = getArrayValue($params, 'show_category'); $current_template = $this->Application->GetVar('t'); $physical_template = $this->Application->getPhysicalTemplate($current_template); if ($physical_template !== false) { // replace menu template name with it's actual template name on disk list ($current_template) = explode(':', $physical_template, 2); } foreach ($navigation_parts as $template => $title) { $block_params['template'] = $template; if ($title == '__item__') { if ($show_category) { $ret .= $this->getCategoryPath($main_category_id, $params); $show_category = false; } $category_path = $this->getCategoryParentPath($main_category_id); $module_info = $this->getCategoryModule($params, array_keys($category_path)); if (!$module_info) { continue; } $module_prefix = $module_info['Var']; $object =& $this->Application->recallObject($module_prefix); /* @var $object kCatDBItem */ $title_field = $this->Application->getUnitOption($module_prefix, 'TitleField'); $block_params['title'] = $object->GetField($title_field); $block_params['prefix'] = $module_prefix; $block_params['current'] = 0; $block_params['name'] = $this->SelectParam($params, 'module_item_render_as,render_as'); } else { $block_params['current'] = ($template == $current_template); $block_params['title'] = $this->Application->Phrase($title); $block_params['name'] = $template == $current_template ? $params['current_render_as'] : $params['render_as']; } $ret .= $this->Application->ParseBlock($block_params); } if ($show_category) { $params['no_current'] = true; return $home_element . ($show_category ? $this->getCategoryPath($main_category_id, $params) : '') . $ret; } return $home_element . $ret; } /** * Get navigation parts * * @param Array $titles * @param Array $templates * @return Array */ function getNavigationParts($titles, $templates) { $titles = explode(',', $titles); $templates = explode(',', $templates); $ret = Array (); foreach ($templates as $template_pos => $template) { $ret[$template] = $titles[$template_pos]; } return $ret; } /** * Renders path to given category using given blocks. * * @param int $main_category_id * @param Array $params * @return string */ function getCategoryPath($main_category_id, $params) { $category_path = $this->getCategoryParentPath($main_category_id); if (!$category_path) { // in "Home" category return ''; } if (array_key_exists('shift', $params) && $params['shift']) { array_splice($category_path, 0, $params['shift']); } $module_info = $this->getCategoryModule($params, array_keys($category_path)); $module_category_id = $module_info['RootCat']; $module_item_id = $this->Application->GetVar($module_info['Var'].'_id'); $ret = ''; $block_params['category'] = 1; $block_params['no_editing'] = 1; if (array_key_exists('is_first', $params)) { $block_params['is_first'] = $params['is_first']; } $block_params['separator'] = $params['separator']; $no_current = isset($params['no_current']) && $params['no_current']; $backup_category_id = $this->Application->GetVar('c_id'); foreach ($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['is_module_root'] = $category_id == $module_category_id ? 1 : 0; $block_params['name'] = $this->SelectParam($params, 'render_as,block'); // which block to parse as current ? if ($block_params['is_module_root']) { $block_params['name'] = $this->SelectParam($params, 'module_root_render_as,render_as'); $block_params['module_index'] = $module_info['TemplatePath'].'index'; } if ($block_params['current']) { $block_params['name'] = $this->SelectParam($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; } /** * Returns module information based on given module name or current category (relative to module root categories) * * @param Array $params * @param Array $category_ids category parent path (already as array) * @return Array */ function getCategoryModule($params, $category_ids) { if (isset($params['module'])) { // get module by name specified $module_info = $this->Application->findModule('Name', $params['module']); } elseif ($category_ids) { // get module by category path $module_root_categories = $this->getModuleRootCategories(); $common_categories = array_intersect($category_ids, $module_root_categories); $module_category_id = array_shift($common_categories); // get 1st common category $module_info = $this->Application->findModule('RootCat', $module_category_id); } return $module_info; } /** * Renders path to top catalog category * * @param Array $params * @param int $current_category * @return string */ function getHomeCategoryPath($params, $current_category) { $block_params['cat_id'] = $this->Application->getBaseCategory(); $block_params['no_editing'] = 1; $block_params['current'] = $current_category == $block_params['cat_id'] ? 1 : 0; $block_params['separator'] = $params['separator']; $block_params['is_first'] = $params['is_first']; $block_params['cat_name'] = $this->Application->Phrase(($this->Application->isAdmin ? 'la_' : 'lu_') . 'rootcategory_name'); $block_params['name'] = $this->SelectParam($params, 'root_cat_render_as,render_as'); return $this->Application->ParseBlock($block_params); } /** * Returns root categories from all modules * * @return Array */ function getModuleRootCategories() { static $root_categories = null; if (!isset($root_categories)) { $root_categories = Array (); foreach ($this->Application->ModuleInfo as $module_name => $module_info) { array_push($root_categories, $module_info['RootCat']); } $root_categories = array_unique($root_categories); } return $root_categories; } /** * Returns given category's parent path as array of id=>name elements * * @param int $main_category_id * @return Array */ function getCategoryParentPath($main_category_id) { if ($main_category_id == 0) { // don't query path for "Home" category return Array (); } $cache_key = 'parent_paths_named[%CIDSerial:' . $main_category_id . '%]'; $cached_path = $this->Application->getCache($cache_key); if ($cached_path === false) { $ml_formatter =& $this->Application->recallObject('kMultiLanguage'); $navbar_field = $ml_formatter->LangFieldName('CachedNavBar'); $id_field = $this->Application->getUnitOption('c', 'IDField'); $table_name = $this->Application->getUnitOption('c', 'TableName'); $this->Conn->nextQueryCachable = true; $sql = 'SELECT '.$navbar_field.', ParentPath FROM '.$table_name.' WHERE '.$id_field.' = '.$main_category_id; $category_data = $this->Conn->GetRow($sql); $cached_path = Array (); $skip_category = $this->Application->getBaseCategory(); if ($category_data) { $category_names = explode('&|&', $category_data[$navbar_field]); $category_ids = explode('|', substr($category_data['ParentPath'], 1, -1)); foreach ($category_ids as $category_index => $category_id) { if ($category_id == $skip_category) { continue; } $cached_path[$category_id] = $category_names[$category_index]; } } $this->Application->setCache($cache_key, $cached_path); } return $cached_path; } /** * Not tag, method for parameter * selection from list in this TagProcessor * * @param Array $params * @param string $possible_names * @return string * @access public */ 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 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_type $language_id * @param int $theme_id * @param int $level * @return Array */ 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 */ 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, ThemeId FROM ' . $this->Application->getUnitOption('c', 'TableName') . ' 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; } } $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; } /** * Generates OR retrieves from cache structure tree * * @return Array */ function &_getStructureTree() { // get cached version of structure tree if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { $data = $this->Application->getCache('master:StructureTree', false); } else { $data = $this->Application->getDBCache('StructureTree'); } if ($data) { $data = unserialize($data); return $data; } // generate structure tree from scratch $ml_helper =& $this->Application->recallObject('kMultiLanguageHelper'); /* @var $ml_helper 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; } function getTemplateMapping() { if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { $data = $this->Application->getCache('master:template_mapping', false); } else { $data = $this->Application->getDBCache('template_mapping'); } 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 . 'Category AS cc WHERE cc.CategoryId = c.SymLinkCategoryId), c.NamedParentPath ) ) AS DstTemplate, c.UseExternalUrl, c.ExternalUrl FROM ' . TABLE_PREFIX . 'Category 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 */ 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; } $themes_helper =& $this->Application->recallObject('ThemesHelper'); /* @var $themes_helper kThemesHelper */ $data = $this->_getStructureTree(); $theme_id = (int)$themes_helper->getCurrentThemeId(); $root_category = $this->Application->getBaseCategory(); $this->_primaryLanguageId = $this->Application->GetDefaultLanguageId(); $this->_structureTree = $this->_printChildren($data, $root_category, $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 */ function replacePageIds($text) { if (!preg_match_all('/@@(\\d+)@@/', $text, $regs)) { return $text; } $page_ids = $regs[1]; $sql = 'SELECT NamedParentPath, CategoryId FROM ' . TABLE_PREFIX . 'Category WHERE CategoryId IN (' . implode(',', $page_ids) . ')'; $templates = $this->Conn->GetCol($sql, 'CategoryId'); foreach ($page_ids as $page_id) { if (!array_key_exists($page_id, $templates)) { // internal page was deleted, but link to it was found in given content block data continue; } $url_params = Array ('m_cat_id' => $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; } }