Index: admin/system_presets/simple/categories_c.php =================================================================== --- admin/system_presets/simple/categories_c.php (revision 12866) +++ admin/system_presets/simple/categories_c.php (working copy) @@ -40,12 +40,12 @@ // fields to hide $hidden_fields = Array ( - 'CategoryId', /*'Type',*/ 'SymLinkCategoryId', /*'ParentId', 'Name', 'Filename', 'AutomaticFilename',*/ + 'CategoryId', /*'Type', 'SymLinkCategoryId', 'ParentId', 'Name', 'Filename', 'AutomaticFilename',*/ /*'Description',*/ 'CreatedOn', 'EditorsPick', 'Status', /*'Priority', 'MetaKeywords', 'CachedDescendantCatsQty', 'CachedNavbar',*/ 'CreatedById', /*'ResourceId', 'ParentPath', 'TreeLeft', 'TreeRight', 'NamedParentPath', 'MetaDescription', 'HotItem',*/ 'NewItem', /*'PopItem', 'Modified', 'ModifiedById', 'CachedTemplate',*/ 'Template', /*'UseExternalUrl', 'ExternalUrl',*/ 'UseMenuIconUrl', 'MenuIconUrl', 'Title', 'MenuTitle', - /*'MetaTitle', 'IndexTools', 'IsIndex', 'IsMenu', 'IsSystem',*/ 'FormId', 'FormSubmittedTemplate', + /*'MetaTitle', 'IndexTools', 'IsMenu', 'IsSystem',*/ 'FormId', 'FormSubmittedTemplate', /*'FriendlyURL', 'ThemeId'*/ ); @@ -56,7 +56,7 @@ ); $debug_only_fields = Array ( - 'Filename', 'AutomaticFilename', 'IsIndex', + 'Filename', 'AutomaticFilename', 'SymLinkCategoryId' ); // fields to make required Index: core/admin_templates/categories/categories_edit.tpl =================================================================== --- core/admin_templates/categories/categories_edit.tpl (revision 12866) +++ core/admin_templates/categories/categories_edit.tpl (working copy) @@ -72,7 +72,7 @@ - + @@ -91,7 +91,6 @@ - Index: core/admin_templates/config/config_general.tpl =================================================================== --- core/admin_templates/config/config_general.tpl (revision 12866) +++ core/admin_templates/config/config_general.tpl (working copy) @@ -100,7 +100,7 @@ - + Index: core/admin_templates/incs/form_blocks.tpl =================================================================== --- core/admin_templates/incs/form_blocks.tpl (revision 12866) +++ core/admin_templates/incs/form_blocks.tpl (working copy) @@ -576,9 +576,9 @@ - Index: core/admin_templates/tools/system_tools.tpl =================================================================== --- core/admin_templates/tools/system_tools.tpl (revision 12866) +++ core/admin_templates/tools/system_tools.tpl (working copy) @@ -31,7 +31,7 @@
+ style="display: none;"> - + @@ -593,14 +593,36 @@ - + style="display: none;">
- + Index: core/install/english.lang =================================================================== --- core/install/english.lang (revision 12871) +++ core/install/english.lang (working copy) @@ -35,7 +35,6 @@ VXA= Q2FuY2Vs U2VjdGlvbg== - U2VjdGlvbiBJbmRleA== TnVtYmVyIG9mIGRheXMgZm9yIGEgY2F0LiB0byBiZSBORVc= RGVmYXVsdCBNRVRBIGRlc2NyaXB0aW9u RGVmYXVsdCBNRVRBIEtleXdvcmRz @@ -250,7 +249,6 @@ WWFob28gQXBwbGljYXRpb25JZA== QXJlIHlvdSBzdXJlIHlvdSB3YW50IHRvIGRlbGV0ZSBzZWxlY3RlZCBFeHBvcnQgUHJlc2V0Pw== VGhlIHNlY3Rpb24gdHJlZSBtdXN0IGJlIHVwZGF0ZWQgdG8gcmVmbGVjdCB0aGUgbGF0ZXN0IGNoYW5nZXM= - Q29udGFpbmVy QXJ1YmE= QWZnaGFuaXN0YW4= QW5nb2xh @@ -691,7 +689,6 @@ SW5zdGFsbCBNb2R1bGVz SW5zdGFsbCBQaHJhc2UgVHlwZXM= VXNlIGN1cnJlbnQgc2VjdGlvbiBhcyByb290IGZvciB0aGUgZXhwb3J0 - SXMgSW5kZXggU2VjdGlvbg== UHJpbWFyeQ== UmVxdWlyZWQ= SXMgU3lzdGVt Index: core/install/install_schema.sql =================================================================== --- core/install/install_schema.sql (revision 12866) +++ core/install/install_schema.sql (working copy) @@ -436,7 +436,6 @@ l5_MenuTitle varchar(255) NOT NULL DEFAULT '', MetaTitle text, IndexTools text, - IsIndex tinyint(1) NOT NULL DEFAULT '0', IsMenu tinyint(4) NOT NULL DEFAULT '1', IsSystem tinyint(4) NOT NULL DEFAULT '0', FormId int(11) DEFAULT NULL, @@ -466,7 +465,6 @@ KEY `Status` (`Status`), KEY CreatedOn (CreatedOn), KEY EditorsPick (EditorsPick), - KEY IsIndex (IsIndex), KEY ThemeId (ThemeId) ); Index: core/install/upgrades.php =================================================================== --- core/install/upgrades.php (revision 12866) +++ core/install/upgrades.php (working copy) @@ -1197,13 +1197,16 @@ } /** - * Update to 5.0.2-B2 + * Update to 5.0.2-B2; Transforms IsIndex field values to SymLinkCategoryId field * * @param string $mode when called mode {before, after) */ function Upgrade_5_0_2_B2($mode) { + // 0 - Regular, 1 - Category Index, 2 - Container + if ($mode == 'before') { + // fix "Content" category $fields_hash = Array ( 'CreatedById' => -1, // root 'CreatedOn' => time(), @@ -1211,8 +1214,31 @@ ); $category_id = $this->Application->findModule('Name', 'Core', 'RootCat'); + $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Category', 'CategoryId = ' . $category_id); - $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Category', 'CategoryId = ' . $category_id); + // get all categories, marked as category index + $sql = 'SELECT ParentPath, CategoryId + FROM ' . TABLE_PREFIX . 'Category + WHERE IsIndex = 1'; + $category_indexes = $this->Conn->GetCol($sql, 'CategoryId'); + + foreach ($category_indexes as $category_id => $parent_path) { + $parent_path = explode('|', substr($parent_path, 1, -1)); + + // set symlink to $category_id for each category, marked as container in given category path + $sql = 'SELECT CategoryId + FROM ' . TABLE_PREFIX . 'Category + WHERE CategoryId IN (' . implode(',', $parent_path) . ') AND (IsIndex = 2)'; + $category_containers = $this->Conn->GetCol($sql); + + if ($category_containers) { + $sql = 'UPDATE ' . TABLE_PREFIX . 'Category + SET SymLinkCategoryId = ' . $category_id . ' + WHERE CategoryId IN (' . implode(',', $category_containers) . ')'; + $this->Conn->Query($sql); + } + + } } if ($mode == 'after') { Index: core/install/upgrades.sql =================================================================== --- core/install/upgrades.sql (revision 12867) +++ core/install/upgrades.sql (working copy) @@ -1609,4 +1609,7 @@ UPDATE Phrase SET PhraseType = 1 WHERE Phrase IN ('la_ToolTip_MoveUp', 'la_ToolTip_MoveDown', 'la_invalid_state', 'la_Pending', 'la_text_sess_expired', 'la_ToolTip_Export'); DELETE FROM Phrase WHERE Phrase IN ('la_ToolTip_Move_Up', 'la_ToolTip_Move_Down'); -UPDATE Phrase SET Phrase = 'lu_btn_SendPassword' WHERE Phrase = 'LU_BTN_SENDPASSWORD'; \ No newline at end of file +UPDATE Phrase SET Phrase = 'lu_btn_SendPassword' WHERE Phrase = 'LU_BTN_SENDPASSWORD'; + +ALTER TABLE Category DROP IsIndex; +DELETE FROM Phrase WHERE Phrase IN ('la_CategoryIndex', 'la_Container', 'la_fld_IsIndex'); \ No newline at end of file Index: core/kernel/application.php =================================================================== --- core/kernel/application.php (revision 12871) +++ core/kernel/application.php (working copy) @@ -178,6 +178,13 @@ */ var $TemplatesCache = null; + /** + * Physical template name mapping to their template names based on structure + * + * @var Array + */ + var $structureTemplateMapping = Array (); + var $CompilationCache = array(); //used when compiling templates var $CachedProcessors = array(); //used when running compiled templates @@ -371,6 +378,7 @@ $this->StoreVar('UserGroups', $user_groups, true); // true for optional } + $this->LoadStructureTemplateMapping(); $this->HttpQuery->AfterInit(); $this->Session->ValidateExpired(); @@ -1334,18 +1342,48 @@ * @param string $t Template path * @var string $prefix index.php prefix - could be blank, 'admin' */ - function HREF($t, $prefix='', $params=null, $index_file=null) + function HREF($t, $prefix = '', $params = null, $index_file = null) { + static $theme_id = null; + + if (!isset($theme_id)) { + $theme_id = $this->GetVar('m_theme'); + } + if (!$t) { - $t = $this->GetVar('t'); // moved from kMainTagProcessor->T() + // when template not specified, use current + $t = $this->GetVar('t'); } $t = preg_replace('/^Content\//i', '', $t); if (substr($t, -4) == '.tpl') { + // cut template extension (deprecated link format) $t = substr($t, 0, strlen($t) - 4); } + if (substr($t, 0, 3) == 'id:') { + // link to structure page using it's id + $params['m_cat_id'] = substr($t, 3); + $t = $this->structureTemplateMapping[$t]; + } + + if (array_key_exists('use_section', $params)) { + $use_section = $params['use_section']; + unset($params['use_section']); + } + + if (isset($use_section) && $use_section && array_key_exists($t . ':' . $theme_id, $this->structureTemplateMapping)) { + // structure template corresponding to given physical template + $t = $this->structureTemplateMapping[$t . ':' . $theme_id]; + unset($params['use_section']); + } + + if (preg_match('/external:(.*)/', $t, $rets)) { + // external url + return $rets[1]; + } + if ($this->isAdmin && $prefix == '') $prefix = ADMIN_DIRECTORY; if ($this->isAdmin && $prefix == '_FRONT_END_') $prefix = ''; @@ -1876,29 +1914,31 @@ function Redirect($t='', $params=null, $prefix='', $index_file=null) { $js_redirect = getArrayValue($params, 'js_redirect'); - if (preg_match("/external:(.*)/", $t, $rets)) { - $location = $rets[1]; + + if ($t == '' || $t === true) { + $t = $this->GetVar('t'); } - else { - if ($t == '' || $t === true) $t = $this->GetVar('t'); - // pass prefixes and special from previous url - if( isset($params['js_redirect']) ) unset($params['js_redirect']); + // pass prefixes and special from previous url + if (array_key_exists('js_redirect', $params)) { + unset($params['js_redirect']); + } - if (!isset($params['pass'])) $params['pass'] = 'all'; - if ($this->GetVar('ajax') == 'yes' && $t == $this->GetVar('t')) { - // redirects to the same template as current - $params['ajax'] = 'yes'; - } - $params['__URLENCODE__'] = 1; - $location = $this->HREF($t, $prefix, $params, $index_file); - //echo " location : $location
"; + if (!array_key_exists('pass', $params)) { + $params['pass'] = 'all'; } + if ($this->GetVar('ajax') == 'yes' && $t == $this->GetVar('t')) { + // redirects to the same template as current + $params['ajax'] = 'yes'; + } + + $params['__URLENCODE__'] = 1; + $location = $this->HREF($t, $prefix, $params, $index_file); + $a_location = $location; $location = "Location: $location"; - if ($this->isDebugMode() && constOn('DBG_REDIRECT')) { $this->Debugger->appendTrace(); echo "Debug output above!!! Proceed to redirect: $a_location
"; @@ -2036,6 +2076,20 @@ $this->ConfigCacheIds = $config_ids; } + function LoadStructureTemplateMapping() + { + // get template mapping + $sql = 'SELECT Data + FROM ' . TABLE_PREFIX . 'Cache + WHERE VarName = "template_mapping"'; + $template_mapping = $this->Conn->GetOne($sql); + + if (!$this->isAdmin && $template_mapping) { + // template mappings only for Front-End + $this->structureTemplateMapping = unserialize($template_mapping); + } + } + function UpdateCache() { $update = false; Index: core/kernel/db/db_event_handler.php =================================================================== --- core/kernel/db/db_event_handler.php (revision 12866) +++ core/kernel/db/db_event_handler.php (working copy) @@ -531,9 +531,19 @@ if ($this->Application->isDebugMode()) { $this->Application->Debugger->appendTrace(); } + trigger_error('ItemLoad Permission Failed for prefix ['.$event->getPrefixSpecial().'] in '.($status_checked ? 'checkItemStatus' : 'CheckPermission').'', E_USER_WARNING); - $next_template = $this->Application->isAdmin ? 'no_permission' : $this->Application->ConfigValue('NoPermissionTemplate'); - $this->Application->Redirect($next_template, Array('next_template' => $this->Application->GetVar('t'))); + $redirect_template = $this->Application->isAdmin ? 'no_permission' : $this->Application->ConfigValue('NoPermissionTemplate'); + + $redirect_params = $this->Application->HttpQuery->getRedirectParams(true); + $next_template = $this->Application->HREF('', '', $redirect_params); + + $redirect_params = Array ( + 'm_cat_id' => 0, + 'next_template' => urlencode('external:' . $next_template), + ); + + $this->Application->Redirect($redirect_template, $redirect_params); } } Index: core/kernel/db/db_tag_processor.php =================================================================== --- core/kernel/db/db_tag_processor.php (revision 12871) +++ core/kernel/db/db_tag_processor.php (working copy) @@ -671,11 +671,6 @@ */ function prepareTagParams($tag_params = Array()) { - /*if (isset($tag_params['list_name'])) { - $list =& $this->GetList($tag_params); - $this->Init($list->Prefix, $list->Special); - }*/ - $ret = $tag_params; $ret['Prefix'] = $this->Prefix; $ret['Special'] = $this->Special; Index: core/kernel/kbase.php =================================================================== --- core/kernel/kbase.php (revision 12866) +++ core/kernel/kbase.php (working copy) @@ -132,6 +132,27 @@ } + /** + * Append prefix and special to tag + * params (get them from tagname) like + * they were really passed as params + * + * @param string $prefix_special + * @param Array $tag_params + * @return Array + * @access protected + */ + function prepareTagParams($prefix_special, $tag_params = Array()) + { + $parts = explode('.', $prefix_special); + + $ret = $tag_params; + $ret['Prefix'] = $parts[0]; + $ret['Special'] = count($parts) > 1 ? $parts[1] : ''; + $ret['PrefixSpecial'] = $prefix_special; + + return $ret; + } } class kDBBase extends kBase { Index: core/kernel/processors/main_processor.php =================================================================== --- core/kernel/processors/main_processor.php (revision 12866) +++ core/kernel/processors/main_processor.php (working copy) @@ -768,14 +768,18 @@ if ((!$this->Application->LoggedIn() || !$group_access) && $condition) { $redirect_params = $this->Application->HttpQuery->getRedirectParams(true); - $redirect_params['next_template'] = $t; if (array_key_exists('pass_category', $params)) { $redirect_params['pass_category'] = $params['pass_category']; } + $redirect_params = Array ( + 'm_cat_id' => 0, + 'next_template' => urlencode('external:' . $this->Application->HREF($t, '', $redirect_params)), + ); + if ( $this->Application->LoggedIn() && !$group_access) { - $this->Application->Redirect( $params['no_group_perm_template'], $redirect_params); + $this->Application->Redirect($params['no_group_perm_template'], $redirect_params); } $this->Application->Redirect($params['login_template'], $redirect_params); Index: core/kernel/utility/http_query.php =================================================================== --- core/kernel/utility/http_query.php (revision 12866) +++ core/kernel/utility/http_query.php (working copy) @@ -594,14 +594,8 @@ } if ($access_error) { + // place 1 of 2 (also in UsersEventHandler::OnSessionExpire) $vars = $this->_removePassThroughVariables($vars); - - if ($this->Application->isAdmin) { - // place 1 of 2 (also in UsersEventHandler::OnSessionExpire) - $vars['m_cat_id'] = 0; // category means nothing on admin login screen - $vars['m_wid'] = ''; // remove wid, otherwise parent window may add wid to its name breaking all the frameset (for targets) - $vars['pass'] = 'm'; // don't pass any other (except "m") prefixes to admin login template - } } // transform arrays Index: core/units/admin/admin_events_handler.php =================================================================== --- core/units/admin/admin_events_handler.php (revision 12866) +++ core/units/admin/admin_events_handler.php (working copy) @@ -43,9 +43,9 @@ $perm_value = null; $system_events = Array ( - 'OnResetModRwCache', 'OnResetCMSMenuCache', 'OnResetSections', - 'OnResetConfigsCache', 'OnDeleteCompiledTemplates', 'OnCompileTemplates', - 'OnGenerateTableStructure', 'OnRebuildThemes', 'OnCheckPrefixConfig', + 'OnResetModRwCache', 'OnResetSections', 'OnResetConfigsCache', + 'OnDeleteCompiledTemplates', 'OnCompileTemplates', 'OnGenerateTableStructure', + 'OnRebuildThemes', 'OnCheckPrefixConfig', ); if (in_array($event->Name, $system_events)) { @@ -98,15 +98,6 @@ $this->Conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName LIKE "mod_rw%"'); } - function OnResetCMSMenuCache(&$event) - { - if ($this->Application->GetVar('ajax') == 'yes') { - $event->status = erSTOP; - } - - $this->Conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName IN ("cms_menu", "StructureTree")'); - } - function OnResetSections(&$event) { if ($this->Application->GetVar('ajax') == 'yes') { @@ -460,8 +451,10 @@ } $prefix_elems = split('\.|_', $prefix_special, 2); $perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection'); + if(!$this->Application->CheckPermission($perm_sections['main'].'.view')) { - $this->Application->Redirect('no_permission'); + $event->status = erPERM_FAIL; + return ; } $export_helper->PrefixSpecial = $prefix_special; @@ -485,7 +478,8 @@ $perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection'); if(!$this->Application->CheckPermission($perm_sections['main'].'.view')) { - $this->Application->Redirect('no_permission'); + $event->status = erPERM_FAIL; + return ; } $export_helper->GetCSV(); @@ -503,7 +497,8 @@ $perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection'); if(!$this->Application->CheckPermission($perm_sections['main'].'.add') && !$this->Application->CheckPermission($perm_sections['main'].'.edit')) { - $this->Application->Redirect('no_permission'); + $event->status = erPERM_FAIL; + return ; } $object =& $event->getObject( Array('skip_autoload' => true) ); @@ -547,7 +542,8 @@ $prefix_elems = split('\.|_', $prefix_special, 2); $perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection'); if(!$this->Application->CheckPermission($perm_sections['main'].'.add') && !$this->Application->CheckPermission($perm_sections['main'].'.edit')) { - $this->Application->Redirect('no_permission'); + $event->status = erPERM_FAIL; + return ; } $import_helper->ImportStep(); Index: core/units/categories/categories_config.php =================================================================== --- core/units/categories/categories_config.php (revision 12866) +++ core/units/categories/categories_config.php (working copy) @@ -350,11 +350,6 @@ 'MenuTitle' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'not_null' => 1, 'default' => ''), 'MetaTitle' => Array ('type' => 'string', 'default' => null), 'IndexTools' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => null), - 'IsIndex' => - Array ( - 'type' => 'int', 'not_null' => 1, 'default' => 0, - 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_Regular', 1 => 'la_CategoryIndex', 2 => 'la_Container'), 'use_phrases' => 1, - ), 'IsMenu' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Show', 0 => 'la_Hide'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 1), 'IsSystem' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_System', 0 => 'la_text_User'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0), 'FormId' => Array ( Index: core/units/categories/categories_event_handler.php =================================================================== --- core/units/categories/categories_event_handler.php (revision 12866) +++ core/units/categories/categories_event_handler.php (working copy) @@ -62,6 +62,17 @@ */ function CheckPermission(&$event) { + if ($event->Name == 'OnResetCMSMenuCache') { + // events from "Tools -> System Tools" section are controlled via that section "edit" permission + + $perm_helper =& $this->Application->recallObject('PermissionsHelper'); + /* @var $perm_helper kPermissionsHelper */ + + $perm_value = $this->Application->CheckPermission('in-portal:service.edit'); + + return $perm_helper->finalizePermissionCheck($event, $perm_value); + } + if (!$this->Application->isAdmin) { if ($event->Name == 'OnSetSortingDirect') { // allow sorting on front event without view permission @@ -471,6 +482,7 @@ $type_clauses['menu']['include'] = '%1$s.IsMenu = 1'; $type_clauses['menu']['except'] = '%1$s.IsMenu = 0'; + $type_clauses['menu']['having_filter'] = false; if (in_array('search', $types) || in_array('search', $except_types)) { $event_mapping = Array ( @@ -602,7 +614,7 @@ $updater->OneStepRun(); } - $event->CallSubEvent('OnResetMenuCache'); + $this->_resetMenuCache(); $this->Application->RemoveVar('PermCache_UpdateRequired'); @@ -799,7 +811,7 @@ } $this->Application->StoreVar('RefreshStructureTree', 1); - $event->CallSubEvent('OnResetMenuCache'); + $this->_resetMenuCache(); if ($is_editing) { // 2. send email event to category owner, when it's status is changed (from admin) @@ -1017,7 +1029,7 @@ $priority_helper->recalculatePriorities($event, 'ParentId = ' . $parent_id); $this->Application->StoreVar('RefreshStructureTree', 1); - $event->CallSubEvent('OnResetMenuCache'); + $this->_resetMenuCache(); } /** @@ -1139,7 +1151,6 @@ $priority_helper =& $this->Application->recallObject('PriorityHelper'); /* @var $priority_helper kPriorityHelper */ - if ($clipboard_data['cut']) { $priority_helper->recalculatePriorities($event, 'ParentId = '.$source_category_id); } @@ -1160,7 +1171,7 @@ $event->redirect = 'categories/cache_updater'; } - $event->CallSubEvent('OnResetMenuCache'); + $this->_resetMenuCache(); $this->Application->StoreVar('RefreshStructureTree', 1); } } @@ -1780,11 +1791,68 @@ * * @param kEvent $event */ - function OnResetMenuCache(&$event) + function OnResetCMSMenuCache(&$event) { - $this->Conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName IN ("cms_menu", "StructureTree")'); + if ($this->Application->GetVar('ajax') == 'yes') { + $event->status = erSTOP; + } + + $this->_resetMenuCache(); } + function _resetMenuCache() + { + // reset cms menu cache + $sql = 'DELETE FROM ' . TABLE_PREFIX . 'Cache + WHERE VarName IN ("cms_menu", "StructureTree")'; + $this->Conn->Query($sql); + + // build structure template mapping + $sql = 'SELECT + IF(c.IsSystem, 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; + } + + $fields_hash = Array ( + 'VarName' => 'template_mapping', + 'Data' => serialize($mapping), + 'Cached' => adodb_mktime(), + ); + + $this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'Cache', 'REPLACE'); + } + /** * Updates structure config * @@ -1974,7 +2042,7 @@ $updater->OneStepRun(); } - $event->CallSubEvent('OnResetMenuCache'); + $this->_resetMenuCache(); if ($error_count) { // allow user to review error after structure page creation @@ -2023,7 +2091,7 @@ $this->clearSelectedIDs($event); $this->Application->StoreVar('RefreshStructureTree', 1); - $event->CallSubEvent('OnResetMenuCache'); + $this->_resetMenuCache(); } /** @@ -2038,7 +2106,7 @@ $parent_id = $this->Application->GetVar('m_cat_id'); $priority_helper->recalculatePriorities($event, 'ParentId = ' . $parent_id); - $event->CallSubEvent('OnResetMenuCache'); + $this->_resetMenuCache(); } /** Index: core/units/categories/categories_tag_processor.php =================================================================== --- core/units/categories/categories_tag_processor.php (revision 12872) +++ core/units/categories/categories_tag_processor.php (working copy) @@ -14,20 +14,6 @@ class CategoriesTagProcessor extends kDBTagProcessor { - /** - * Cached version of site menu - * - * @var Array - */ - var $Menu = null; - - /** - * Parent path mapping used in CachedMenu tag - * - * @var Array - */ - var $ParentPaths = Array (); - function SubCatCount($params) { $object =& $this->getObject($params); @@ -227,34 +213,32 @@ return $ml_formatter->LangFieldName('Name'); } + /** + * Returns symlinked category for given category + * + * @param $category_id + */ function getCategorySymLink($category_id) { static $cache = null; + if (!$category_id) { + // don't bother to get symlink for "Home" category + return $category_id; + } + if (!isset($cache)) { $id_field = $this->Application->getUnitOption($this->Prefix, 'IDField'); $table_name = $this->Application->getUnitOption($this->Prefix, 'TableName'); - $sql = 'SELECT SymLinkCategoryId, '.$id_field.' - FROM '.$table_name.' - WHERE SymLinkCategoryId IS NOT NULL'; + // get symlinked categories, that are not yet deleted + $sql = 'SELECT c1.SymLinkCategoryId, c1.' . $id_field . ' + FROM ' . $table_name . ' c1 + JOIN ' . $table_name . ' c2 ON c1.SymLinkCategoryId = c2.' . $id_field; $cache = $this->Conn->GetCol($sql, $id_field); } - if (isset($cache[$category_id])) { - - //check if sym. link category is valid - $id_field = $this->Application->getUnitOption($this->Prefix, 'IDField'); - $table_name = $this->Application->getUnitOption($this->Prefix, 'TableName'); - - $sql = 'SELECT '.$id_field.' - FROM '.$table_name.' - WHERE '.$id_field.' = '.$cache[$category_id]; - - $category_id = $this->Conn->GetOne($sql)? $cache[$category_id] : $category_id; - } - - return $category_id; + return array_key_exists($category_id, $cache) ? $cache[$category_id] : $category_id; } function CategoryLink($params) @@ -262,7 +246,7 @@ $category_id = getArrayValue($params, 'cat_id'); if ($category_id === false) { - $category_id = $this->Application->GetVar($this->getPrefixSpecial().'_id'); + $category_id = $this->Application->GetVar($this->getPrefixSpecial() . '_id'); } if ("$category_id" == 'Root') { @@ -272,7 +256,7 @@ $category_id = $this->Application->GetVar('m_cat_id'); } - $category_id = $this->getCategorySymLink($category_id); + $category_id = $this->getCategorySymLink( (int)$category_id ); unset($params['cat_id'], $params['module']); @@ -1546,119 +1530,6 @@ } /** - * Builds cached menu version - * - * @return Array - */ - function _prepareMenu() - { - static $root_cat = null; - static $root_path = null; - - if (!$root_cat) { - $root_cat = $this->Application->ModuleInfo['Core']['RootCat']; - $root_path = $this->Conn->GetOne('SELECT ParentPath FROM '.TABLE_PREFIX.'Category WHERE CategoryId = '.$root_cat); - } - - if (!$this->Menu) { - $menu = $this->Conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "cms_menu"'); - if ($menu && $menu['Cached'] > 0) { - $menu = unserialize($menu['Data']); - $this->ParentPaths = $menu['ParentPaths']; - } - else { - $menu = $this->_altBuildMenuStructure(array('CategoryId' => $root_cat, 'ParentPath' => $root_path)); - $menu['ParentPaths'] = $this->ParentPaths; - $this->Conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("cms_menu", '.$this->Conn->qstr(serialize($menu)).', '.adodb_mktime().')'); - } - unset($menu['ParentPaths']); - $this->Menu = $menu; - } - - return Array ($this->Menu, $root_path); - } - - /** - * Returns category id based tag parameters - * - * @param Array $params - * @return int - */ - function _getCategoryId($params) - { - $cat = isset($params['category_id']) && $params['category_id'] != '' ? $params['category_id'] : $this->Application->GetVar('m_cat_id'); - if ("$cat" == 'parent') { - $this_category =& $this->Application->recallObject('c'); - /* @var $this_category kDBItem */ - - $cat = $this_category->GetDBField('ParentId'); - } - else if ($cat == 0) { - $cat = $this->Application->ModuleInfo['Core']['RootCat']; - } - - return $cat; - } - - /** - * Prepares cms menu item block parameters - * - * @param Array $page - * @param int $real_cat_id - * @param string $root_path - * @return Array - */ - function _prepareMenuItem($page, $real_cat_id, $root_path) - { - static $language_id = null; - static $primary_language_id = null; - - if (!isset($language_id)) { - $language_id = $this->Application->GetVar('m_lang'); - $primary_language_id = $this->Application->GetDefaultLanguageId(); - } - - $title = $page['l'.$language_id.'_ItemName'] ? $page['l'.$language_id.'_ItemName'] : $page['l'.$primary_language_id.'_ItemName']; - $active = false; - $category_active = false; - - if ($page['ItemType'] == 'cat') { - if ( isset($this->ParentPaths[$real_cat_id])) { - $active = strpos($this->ParentPaths[$real_cat_id], $page['ParentPath']) !== false; - } - $category_active = $page['CategoryId'] == $real_cat_id; - } - - if ($page['ItemType'] == 'cat_index') { - $check_path = str_replace($root_path, '', $page['ParentPath']); - $active = strpos($parent_path, $check_path) !== false; - } - - if ($page['ItemType'] == 'page') { - $active = $page['ItemPath'] == preg_replace('/^Content\//i', '', $this->Application->GetVar('t')); - } - - $block_params = Array ( - 'title'=> $title, - 'template'=> preg_replace('/^Content\//i', '', $page['ItemPath']), - 'active'=>$active, - 'category_active' => $category_active, // new - 'parent_path'=>$page['ParentPath'], - 'parent_id'=>$page['ParentId'], - 'cat_id'=>$page['CategoryId'], - 'is_index'=>$page['IsIndex'], - 'item_type'=>$page['ItemType'], - 'page_id'=>$page['ItemId'], - 'has_sub_menu' => isset($page['sub_items']) && count($page['sub_items']) > 0, - 'external_url' => $page['UseExternalUrl'] ? $page['ExternalUrl'] : false, - 'menu_icon' => $page['UseMenuIconUrl'] ? $page['MenuIconUrl'] : false, - - ); - - return $block_params; - } - - /** * Builds site menu * * @param Array $params @@ -1666,77 +1537,13 @@ */ function CachedMenu($params) { - list ($menu, $root_path) = $this->_prepareMenu(); - $cat = $this->_getCategoryId($params); + $menu_helper =& $this->Application->recallObject('MenuHelper'); + /* @var $menu_helper MenuHelper */ - $parent_path = isset($this->ParentPaths[$cat]) ? $this->ParentPaths[$cat] : ''; - $parent_path = str_replace($root_path, '', $parent_path); //menu starts from module path - $levels = explode('|',trim($parent_path,'|')); - if ($levels[0] === '') $levels = array(); - if (isset($params['level']) && $params['level'] > count($levels)) return ; - - $level = max(isset($params['level']) ? $params['level']-1 : count($levels)-1, 0); - $parent = isset($levels[$level]) ? $levels[$level] : 0; - - $cur_menu =& $menu; - $menu_path = array_slice($levels, 0, $level+1); - foreach ($menu_path as $elem) { - $cur_menu =& $cur_menu['c'.$elem]['sub_items']; - } - - $ret = ''; - $block_params = $this->prepareTagParams($params); - $block_params['name'] = $params['render_as']; - - $this->Application->SetVar('cur_parent_path', $parent_path); - $real_cat_id = $this->Application->GetVar('m_cat_id'); - if (is_array($cur_menu) && $cur_menu) { - $cur_item = 1; - $cur_menu = $this->_removeNonMenuItems($cur_menu); - $block_params['total_items'] = count($cur_menu); - - foreach ($cur_menu as $page) { - $block_params = array_merge_recursive2( - $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; - - // bug #1: this breaks active section highlighting when 2 menu levels are printed on same page (both visible) - // bug #2: people doesn't pass cat_id parameter to m_Link tags in their blocks, so this line helps them; when removed their links will lead to nowhere - $this->Application->SetVar('m_cat_id', $page['CategoryId']); - - $ret .= $this->Application->ParseBlock($block_params, 1); - $cur_item++; - } - - $this->Application->SetVar('m_cat_id', $real_cat_id); - } - - return $ret; + return $menu_helper->menuTag($this->getPrefixSpecial(), $params); } /** - * Returns only items, that are visible in menu - * - * @param Array $menu - * @return Array - */ - function _removeNonMenuItems($menu) - { - foreach ($menu as $menu_index => $menu_item) { - // $menu_index is in "cN" format, where N is category id - if (!$menu_item['IsMenu']) { - unset($menu[$menu_index]); - } - } - - return $menu; - } - - /** * Trick to allow some kind of output formatting when using CachedMenu tag * * @param Array $params @@ -1834,97 +1641,6 @@ } /** - * Builds cache for children of given category (no matter, what menu status is) - * - * @param Array $parent - * @return Array - */ - function _altBuildMenuStructure($parent) - { - static $languages_count = null; - - if (!isset($languages_count)) { - $sql = 'SELECT COUNT(*) - FROM ' . TABLE_PREFIX . 'Language'; - $languages_count = ceil($this->Conn->GetOne($sql) / 5) * 5; - } - - $items = Array (); - - $lang_part = ''; - for ($i = 1; $i <= $languages_count; $i++) { -// $lang_part .= 'c.l' . $i . '_Name AS l' . $i . '_ItemName,' . "\n"; - $lang_part .= 'c.l' . $i . '_MenuTitle AS l' . $i . '_ItemName,' . "\n"; - } - - // Sub-categories from current category - $query = 'SELECT - c.CategoryId AS CategoryId, - CONCAT(\'c\', c.CategoryId) AS ItemId, - c.Priority AS ItemPriority, - ' . $lang_part . ' - LOWER( IF(IsIndex = 2, ( - SELECT cc.NamedParentPath FROM ' . TABLE_PREFIX . 'Category AS cc - WHERE - cc.ParentId = c.CategoryId - AND - cc.Status IN (1,4) - AND - cc.IsIndex = 1 - ), - c.NamedParentPath) ) AS ItemPath, - 0 AS IsIndex, - c.ParentPath AS ParentPath, - c.ParentId As ParentId, - \'cat\' AS ItemType, - c.IsMenu, c.UseExternalUrl, c.ExternalUrl, c.UseMenuIconUrl, c.MenuIconUrl - FROM ' . TABLE_PREFIX . 'Category AS c - WHERE - c.Status IN (1,4) AND - #c.IsMenu = 1 AND - c.ParentId = ' . $parent['CategoryId']; - $items = array_merge($items, $this->Conn->Query($query, 'ItemId')); - - uasort($items, Array (&$this, '_menuSort')); - - $the_items = array(); - foreach ($items as $an_item) { - $the_items[ $an_item['ItemId'] ] = $an_item; - $this->ParentPaths[ $an_item['CategoryId'] ] = $an_item['ParentPath']; - } - - $items = $the_items; - foreach ($items as $key => $menu_item) { - if ($menu_item['CategoryId'] == $parent['CategoryId']) { - continue; - } - - $sub_items = $this->_altBuildMenuStructure($menu_item); - if ($sub_items) { - $items[$key]['sub_items'] = $sub_items; - } - } - - return $items; - } - - /** - * Method for sorting pages by priority in decending order - * - * @param Array $a - * @param Array $b - * @return int - */ - function _menuSort($a, $b) - { - if ($a['ItemPriority'] == $b['ItemPriority']) { - return 0; - } - - return ($a['ItemPriority'] < $b['ItemPriority']) ? 1 : -1; //descending - } - - /** * Prepares cms page description for search result page * * @param Array $params Index: core/units/helpers/category_helper.php =================================================================== --- core/units/helpers/category_helper.php (revision 12866) +++ core/units/helpers/category_helper.php (working copy) @@ -62,9 +62,16 @@ $block_params['no_editing'] = 1; $block_params['category'] = 0; $block_params['separator'] = $params['separator']; - $current_template = $this->Application->GetVar('t'); $show_category = getArrayValue($params, 'show_category'); + $current_template = $this->Application->GetVar('t'); + $physical_template = array_search($current_template, $this->Application->structureTemplateMapping); + + 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; Index: core/units/helpers/helpers_config.php =================================================================== --- core/units/helpers/helpers_config.php (revision 12866) +++ core/units/helpers/helpers_config.php (working copy) @@ -50,6 +50,7 @@ Array ('pseudo' => 'LanguageImportHelper', 'class' => 'LanguageImportHelper', 'file' => 'language_import_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'), Array ('pseudo' => 'SkinHelper', 'class' => 'SkinHelper', 'file' => 'skin_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'), Array ('class' => 'SiteConfigHelper', 'pseudo' => 'SiteConfigHelper', 'file' => 'site_config_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'), + Array ('class' => 'MenuHelper', 'pseudo' => 'MenuHelper', 'file' => 'menu_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'), Array ('class' => 'InpCustomFieldsHelper', 'pseudo' => 'InpCustomFieldsHelper', 'file' => 'custom_fields_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'), Array ('class' => 'kCountryStatesHelper', 'pseudo' => 'CountryStatesHelper', 'file' => 'country_states_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'), Index: core/units/helpers/menu_helper.php =================================================================== --- core/units/helpers/menu_helper.php (revision 0) +++ core/units/helpers/menu_helper.php (revision 0) @@ -0,0 +1,312 @@ +_prepareMenu(); + $cat = $this->_getCategoryId($params); + + $parent_path = array_key_exists($cat, $this->parentPaths) ? $this->parentPaths[$cat] : ''; + $parent_path = str_replace($root_path, '', $parent_path); // menu starts from module path + + $levels = explode('|', trim($parent_path, '|')); + + if ($levels[0] === '') { + $levels = Array (); + } + + if (array_key_exists('level', $params) && $params['level'] > count($levels)) { + // current level is deeper, then requested level + return ; + } + + $level = max(array_key_exists('level', $params) ? $params['level'] - 1 : count($levels) - 1, 0); + $parent = array_key_exists($level, $levels) ? $levels[$level] : 0; + + $cur_menu =& $menu; + $menu_path = array_slice($levels, 0, $level + 1); + + foreach ($menu_path as $elem) { + $cur_menu =& $cur_menu['c' . $elem]['sub_items']; + } + + $block_params = $this->prepareTagParams($prefix_special, $params); + $block_params['name'] = $params['render_as']; + + $this->Application->SetVar('cur_parent_path', $parent_path); + $real_cat_id = $this->Application->GetVar('m_cat_id'); + + if (!is_array($cur_menu) || !$cur_menu) { + // no menus on this level + return ''; + } + + $ret = ''; + $cur_item = 1; + $cur_menu = $this->_removeNonMenuItems($cur_menu); + $block_params['total_items'] = count($cur_menu); + + foreach ($cur_menu as $page) { + $block_params = array_merge_recursive2( + $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; + + // bug #1: this breaks active section highlighting when 2 menu levels are printed on same page (both visible) + // bug #2: people doesn't pass cat_id parameter to m_Link tags in their blocks, so this line helps them; when removed their links will lead to nowhere + $this->Application->SetVar('m_cat_id', $page['CategoryId']); + + $ret .= $this->Application->ParseBlock($block_params); + $cur_item++; + } + + $this->Application->SetVar('m_cat_id', $real_cat_id); + + return $ret; + } + + /** + * Builds cached menu version + * + * @return Array + */ + function _prepareMenu() + { + static $root_cat = null; + static $root_path = null; + + if (!$root_cat) { + $root_cat = $this->Application->ModuleInfo['Core']['RootCat']; + + $sql = 'SELECT ParentPath + FROM ' . TABLE_PREFIX . 'Category + WHERE CategoryId = ' . $root_cat; + $root_path = $this->Conn->GetOne($sql); + } + + if (!$this->Menu) { + $menu = $this->Conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "cms_menu"'); + if ($menu && $menu['Cached'] > 0) { + $menu = unserialize($menu['Data']); + $this->parentPaths = $menu['parentPaths']; + } + else { + $menu = $this->_altBuildMenuStructure(Array ('CategoryId' => $root_cat, 'ParentPath' => $root_path)); + $menu['parentPaths'] = $this->parentPaths; + + $this->Conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("cms_menu", '.$this->Conn->qstr(serialize($menu)).', '.adodb_mktime().')'); + } + + unset($menu['parentPaths']); + $this->Menu = $menu; + } + + return Array ($this->Menu, $root_path); + } + + /** + * Returns category id based tag parameters + * + * @param Array $params + * @return int + */ + function _getCategoryId($params) + { + $cat = isset($params['category_id']) && $params['category_id'] != '' ? $params['category_id'] : $this->Application->GetVar('m_cat_id'); + if ("$cat" == 'parent') { + $this_category =& $this->Application->recallObject('c'); + /* @var $this_category kDBItem */ + + $cat = $this_category->GetDBField('ParentId'); + } + elseif ($cat == 0) { + $cat = $this->Application->ModuleInfo['Core']['RootCat']; + } + + return $cat; + } + + /** + * Prepares cms menu item block parameters + * + * @param Array $page + * @param int $real_cat_id + * @param string $root_path + * @return Array + */ + function _prepareMenuItem($page, $real_cat_id, $root_path) + { + static $language_id = null; + static $primary_language_id = null; + + if (!isset($language_id)) { + $language_id = $this->Application->GetVar('m_lang'); + $primary_language_id = $this->Application->GetDefaultLanguageId(); + } + + $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)) { + $active = strpos($this->parentPaths[$real_cat_id], $page['ParentPath']) !== false; + } + + $category_active = $page['CategoryId'] == $real_cat_id; + } + + /*if ($page['ItemType'] == 'cat_index') { + $check_path = str_replace($root_path, '', $page['ParentPath']); + $active = strpos($parent_path, $check_path) !== false; + } + + if ($page['ItemType'] == 'page') { + $active = $page['ItemPath'] == preg_replace('/^Content\//i', '', $this->Application->GetVar('t')); + }*/ + + $block_params = Array ( + 'title' => $title, + 'template' => $page['ItemPath'], + 'active' => $active, + 'category_active' => $category_active, // new + 'parent_path' => $page['ParentPath'], + 'parent_id' => $page['ParentId'], + 'cat_id' => $page['CategoryId'], + 'item_type' => $page['ItemType'], + 'page_id' => $page['ItemId'], + 'use_section' => (int)$page['IsSystem'], + 'has_sub_menu' => isset($page['sub_items']) && count($page['sub_items']) > 0, + 'external_url' => $page['UseExternalUrl'] ? $page['ExternalUrl'] : false, // for backward compatibility + 'menu_icon' => $page['UseMenuIconUrl'] ? $page['MenuIconUrl'] : false, + ); + + return $block_params; + } + + /** + * Returns only items, that are visible in menu + * + * @param Array $menu + * @return Array + */ + function _removeNonMenuItems($menu) + { + foreach ($menu as $menu_index => $menu_item) { + // $menu_index is in "cN" format, where N is category id + if (!$menu_item['IsMenu']) { + unset($menu[$menu_index]); + } + } + + return $menu; + } + + /** + * Builds cache for children of given category (no matter, what menu status is) + * + * @param Array $parent + * @return Array + */ + function _altBuildMenuStructure($parent) + { + static $lang_part = null; + + if (!isset($lang_part)) { + $sql = 'SELECT COUNT(*) + FROM ' . TABLE_PREFIX . 'Language'; + $languages_count = ceil($this->Conn->GetOne($sql) / 5) * 5; + + $lang_part = ''; + + for ($i = 1; $i <= $languages_count; $i++) { + $lang_part .= 'c.l' . $i . '_MenuTitle AS l' . $i . '_ItemName,' . "\n"; + } + } + + $items = Array (); + + // Sub-categories from current category + $sql = 'SELECT + c.CategoryId AS CategoryId, + CONCAT(\'c\', c.CategoryId) AS ItemId, + c.Priority AS ItemPriority, + ' . $lang_part . ' + + IF(c.IsSystem, c.Template, CONCAT("id:", c.CategoryId)) AS ItemPath, + c.ParentPath AS ParentPath, + c.ParentId As ParentId, + \'cat\' AS ItemType, + c.IsMenu, c.IsSystem, c.UseExternalUrl, c.ExternalUrl, c.UseMenuIconUrl, c.MenuIconUrl + FROM ' . TABLE_PREFIX . 'Category AS c + WHERE (c.Status = ' . STATUS_ACTIVE . ') AND (c.ParentId = ' . $parent['CategoryId'] . ')'; + $items = array_merge($items, $this->Conn->Query($sql, 'ItemId')); + + // 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; + foreach ($items as $key => $menu_item) { + if ($menu_item['CategoryId'] == $parent['CategoryId']) { + // don't process myself - prevents recursion + continue; + } + + $sub_items = $this->_altBuildMenuStructure($menu_item); + + if ($sub_items) { + $items[$key]['sub_items'] = $sub_items; + } + } + + return $items; + } + + /** + * Method for sorting pages by priority in decending order + * + * @param Array $a + * @param Array $b + * @return int + */ + function _menuSort($a, $b) + { + if ($a['ItemPriority'] == $b['ItemPriority']) { + return 0; + } + + return ($a['ItemPriority'] < $b['ItemPriority']) ? 1 : -1; //descending + } + } Index: core/units/helpers/mod_rewrite_helper.php =================================================================== --- core/units/helpers/mod_rewrite_helper.php (revision 12866) +++ core/units/helpers/mod_rewrite_helper.php (working copy) @@ -246,6 +246,13 @@ do { $template_path = implode('/', $url_parts); + $physical_template = array_search($template_path, $this->Application->structureTemplateMapping); + + if ($physical_template !== false) { + // replace menu template name with it's actual template name on disk + list ($template_path) = explode(':', $physical_template, 2); + } + $t_parts['path'] = dirname($template_path) == '.' ? '' : '/' . dirname($template_path); $t_parts['file'] = basename($template_path); @@ -591,7 +598,7 @@ $vars['m_cat_page'] = $rets[2]; } - $sql = 'SELECT CategoryId, IsIndex, NamedParentPath + $sql = 'SELECT CategoryId, SymLinkCategoryId, NamedParentPath FROM ' . TABLE_PREFIX . 'Category WHERE Status IN (1,4) AND (LOWER(NamedParentPath) = ' . $this->Conn->qstr($category_path) . ') AND (ThemeId = ' . $vars['m_theme'] . ' OR ThemeId = 0)'; $category_info = $this->Conn->GetRow($sql); @@ -604,15 +611,17 @@ } while ($category_info !== false && $url_part); if ($last_category_info) { - // IsIndex = 2 is a Container-only page, meaning it should go to index-page child - if ($last_category_info['IsIndex'] == 2) { + // this category is symlink to other category, so use it's url instead + // (used in case if url prior to symlink adding was indexed by spider or was bookmarked) + if ($last_category_info['SymLinkCategoryId']) { $sql = 'SELECT CategoryId, NamedParentPath FROM ' . TABLE_PREFIX . 'Category - WHERE (ParentId = ' . $last_category_info['CategoryId'] . ') AND (IsIndex = 1) AND (ThemeId = ' . $vars['m_theme'] . ' OR ThemeId = 0)'; + WHERE (CategoryId = ' . $last_category_info['SymLinkCategoryId'] . ')'; $category_info = $this->Conn->GetRow($sql); if ($category_info) { - // when index sub-page is found use it, otherwise use container page + // web symlinked category was found use it + // TODO: maybe 302 redirect should be made to symlinked category url (all other url parts should stay) $last_category_info = $category_info; } } Index: core/units/helpers/permissions_helper.php =================================================================== --- core/units/helpers/permissions_helper.php (revision 12866) +++ core/units/helpers/permissions_helper.php (working copy) @@ -264,12 +264,18 @@ function finalizePermissionCheck(&$event, $perm_status) { if (!$perm_status) { + $t = $this->Application->GetVar('t'); + $redirect_params = $this->Application->HttpQuery->getRedirectParams(true); + $next_template = $this->Application->HREF($t, '', $redirect_params); + + $event->SetRedirectParam('m_cat_id', 0); // category means nothing on admin login screen + $event->SetRedirectParam('next_template', urlencode('external:' . $next_template)); + if ($this->Application->isDebugMode()) { // for debugging purposes $event->SetRedirectParam('section', $event->getSection()); $event->SetRedirectParam('main_prefix', $event->getEventParam('top_prefix')); $event->SetRedirectParam('event_name', $event->Name); - $event->SetRedirectParam('next_template', $this->Application->GetVar('t')); } $event->status = erPERM_FAIL; @@ -455,15 +461,25 @@ $redirect_params['pass_category'] = $params['pass_cateogry']; } + $redirect_params = Array ( + 'm_cat_id' => 0, // category means nothing on admin login screen + 'next_template' => urlencode('external:' . $this->Application->HREF($t, '', $redirect_params)), + ); + + if ($this->Application->isAdmin) { + $redirect_params['m_wid'] = ''; // remove wid, otherwise parent window may add wid to its name breaking all the frameset (for targets) + $redirect_params['pass'] = 'm'; // don't pass any other (except "m") prefixes to admin login template + } + if (!$this->Application->LoggedIn()) { $redirect_template = array_key_exists('login_template', $params) ? $params['login_template'] : ''; + if (!$redirect_template && $this->Application->isAdmin) { $redirect_template = 'login'; } - $redirect_params['next_template'] = $t; } else { - if (isset($params['no_permissions_template'])) { + if (array_key_exists('no_permissions_template', $params)) { $redirect_template = $params['no_permissions_template']; } else { @@ -473,7 +489,6 @@ if ($this->Application->isDebugMode()) { $redirect_params['from_template'] = 1; $redirect_params['perms'] = $params[ isset($params['permissions']) ? 'permissions' : 'perm_event' ]; - $redirect_params['next_template'] = $t; } } @@ -481,7 +496,7 @@ $redirect_params['index_file'] = $params['index_file']; } - return Array($redirect_template, $redirect_params); + return Array ($redirect_template, $redirect_params); } /** Index: core/units/structure/structure_config.php =================================================================== --- core/units/structure/structure_config.php (revision 12866) +++ core/units/structure/structure_config.php (working copy) @@ -158,11 +158,6 @@ 'MenuTitle' => Array('type' => 'string', 'formatter' => 'kMultiLanguage', 'not_null' => 1, 'default' => ''), 'MetaTitle' => Array('type' => 'string', 'default' => null), 'IndexTools' => Array('type' => 'string','default' => null), - 'IsIndex' => - Array( - 'type' => 'int','not_null' => 1, 'default' => 0, - 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_Regular', 1 => 'la_CategoryIndex', 2=>'la_Container'), 'use_phrases' => 1, - ), 'IsMenu' => Array('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Show', 0 => 'la_Hide'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 1), 'IsSystem' => Array('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_System', 0 => 'la_Regular'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0), 'FormId' => Array('type' => 'int', 'formatter' => 'kOptionsFormatter', Index: themes/advanced/platform/elements/footer.elm.tpl =================================================================== --- themes/advanced/platform/elements/footer.elm.tpl (revision 12866) +++ themes/advanced/platform/elements/footer.elm.tpl (working copy) @@ -9,7 +9,7 @@
\ No newline at end of file Index: themes/advanced/platform/elements/menu.elm.tpl =================================================================== --- themes/advanced/platform/elements/menu.elm.tpl (revision 12866) +++ themes/advanced/platform/elements/menu.elm.tpl (working copy) @@ -42,11 +42,7 @@