Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1173158
menu_helper.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Sep 30, 3:31 PM
Size
13 KB
Mime Type
text/x-php
Expires
Thu, Oct 2, 3:31 PM (1 d, 20 h)
Engine
blob
Format
Raw Data
Handle
760391
Attached To
rINP In-Portal
menu_helper.php
View Options
<?php
/**
* @version $Id: menu_helper.php 16519 2017-01-20 20:21:46Z alex $
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined
(
'FULL_PATH'
)
or
die
(
'restricted access!'
);
class
MenuHelper
extends
kHelper
{
/**
* Cached version of site menu
*
* @var Array
* @access protected
*/
protected
$Menu
=
NULL
;
/**
* Parent path mapping used in CachedMenu tag
*
* @var Array
* @access protected
*/
protected
$parentPaths
=
Array
();
/**
* Extra parameters, that should be available in each menu item (key - param name, value - category field).
*
* @var array
*/
protected
$itemParams
=
array
(
// 'filename' => array('Filename'),
// 'created_on' => array('CreatedOn', '-- d/m/Y --'),
);
/**
* Category dummy for formatting purposes.
*
* @var CategoriesItem
*/
protected
$categoryDummy
;
/**
* Set's references to kApplication and DBConnection interface class instances
*
* @access public
*/
public
function
__construct
()
{
parent
::
__construct
();
if
(
$this
->
menuItemsRequireFormatting
()
)
{
$this
->
categoryDummy
=
$this
->
Application
->
recallObject
(
'c.menu-item'
,
null
,
array
(
'skip_autoload'
=>
true
)
);
}
}
/**
* Builds site menu
*
* @param string $prefix_special
* @param Array $params
*
* @return string
* @access public
*/
public
function
menuTag
(
$prefix_special
,
$params
)
{
list
(
$menu
,
$root_path
)
=
$this
->
_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
(
$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
;
$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
* @access protected
*/
protected
function
_prepareMenu
()
{
static
$root_cat
=
NULL
,
$root_path
=
NULL
;
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
)
{
$this
->
Conn
->
nextQueryCachable
=
true
;
$sql
=
'SELECT ParentPath
FROM '
.
TABLE_PREFIX
.
'Categories
WHERE CategoryId = '
.
$root_cat
;
$root_path
=
$this
->
Conn
->
GetOne
(
$sql
);
$this
->
Application
->
setCache
(
$cache_key
,
$root_path
);
}
}
if
(
!
$this
->
Menu
)
{
if
(
$this
->
Application
->
isCachingType
(
CACHING_TYPE_MEMORY
)
)
{
$menu
=
$this
->
Application
->
getCache
(
'master:cms_menu'
,
false
,
CacheSettings
::
$cmsMenuRebuildTime
);
}
else
{
$menu
=
$this
->
Application
->
getDBCache
(
'cms_menu'
,
CacheSettings
::
$cmsMenuRebuildTime
);
}
if
(
$menu
)
{
$menu
=
unserialize
(
$menu
);
$this
->
parentPaths
=
$menu
[
'parentPaths'
];
}
else
{
$menu
=
$this
->
_buildMenuStructure
(
$root_cat
);
$menu
[
'parentPaths'
]
=
$this
->
parentPaths
;
if
(
$this
->
Application
->
isCachingType
(
CACHING_TYPE_MEMORY
)
)
{
$this
->
Application
->
setCache
(
'master:cms_menu'
,
serialize
(
$menu
));
}
else
{
$this
->
Application
->
setDBCache
(
'cms_menu'
,
serialize
(
$menu
));
}
}
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'
)
{
/** @var kDBItem $this_category */
$this_category
=
$this
->
Application
->
recallObject
(
'c'
);
$cat
=
$this_category
->
GetDBField
(
'ParentId'
);
}
elseif
(
$cat
==
0
)
{
$cat
=
$this
->
Application
->
getBaseCategory
();
}
return
$cat
;
}
/**
* Prepares cms menu item block parameters
*
* @param Array $page
* @param int $real_cat_id
* @param string $root_path
* @return Array
* @access protected
*/
protected
function
_prepareMenuItem
(
$page
,
$real_cat_id
,
$root_path
)
{
static
$language_id
=
NULL
,
$primary_language_id
=
NULL
,
$template
=
NULL
;
if
(
!
isset
(
$language_id
)
)
{
$language_id
=
$this
->
Application
->
GetVar
(
'm_lang'
);
$primary_language_id
=
$this
->
Application
->
GetDefaultLanguageId
();
$template
=
$this
->
Application
->
GetVar
(
't'
);
}
$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
;
}
elseif
(
$page
[
'ItemPath'
]
==
$template
)
{
// physical template in menu
$active
=
true
;
}
$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'));
}*/
if
(
substr
(
$page
[
'ItemPath'
],
0
,
3
)
==
'id:'
)
{
// resolve ID path here, since it can be used directly without m_Link tag (that usually resolves it)
$page
[
'ItemPath'
]
=
$this
->
Application
->
getVirtualPageTemplate
(
substr
(
$page
[
'ItemPath'
],
3
));
}
$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'
=>
(
$page
[
'Type'
]
==
PAGE_TYPE_TEMPLATE
)
&&
(
$page
[
'ItemPath'
]
!=
'index'
),
'has_sub_menu'
=>
isset
(
$page
[
'sub_items'
])
&&
count
(
$this
->
_removeNonMenuItems
(
$page
[
'sub_items'
]))
>
0
,
'external_url'
=>
$page
[
'UseExternalUrl'
]
?
$page
[
'ExternalUrl'
]
:
false
,
// for backward compatibility
'menu_icon'
=>
$page
[
'UseMenuIconUrl'
]
?
$page
[
'MenuIconUrl'
]
:
false
,
);
if
(
isset
(
$this
->
categoryDummy
)
)
{
$this
->
categoryDummy
->
SetDBFieldsFromHash
(
$page
);
}
foreach
(
$this
->
itemParams
as
$param_name
=>
$category_field_data
)
{
$category_field_name
=
$category_field_data
[
0
];
if
(
array_key_exists
(
1
,
$category_field_data
)
)
{
$block_params
[
$param_name
]
=
$this
->
categoryDummy
->
GetField
(
$category_field_name
,
$category_field_data
[
1
]
);
}
else
{
$block_params
[
$param_name
]
=
$page
[
$category_field_name
];
}
}
return
$block_params
;
}
/**
* Returns only items, that are visible in menu
*
* @param Array $menu
* @return Array
* @access protected
*/
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
)
)
{
// don't show sections, that are not from menu OR system templates from other themes
unset
(
$menu
[
$menu_index
]);
}
}
return
$menu
;
}
/**
* Builds cache of all menu items and their parent categories
*
* @param int $top_category_id
* @return Array
* @access protected
*/
protected
function
_buildMenuStructure
(
$top_category_id
)
{
// 1. get parent paths of leaf categories, that are in menu (across all themes)
$sql
=
'SELECT ParentPath, CategoryId
FROM '
.
$this
->
Application
->
getUnitConfig
(
'c'
)->
getTableName
()
.
'
WHERE IsMenu = 1 AND Status = '
.
STATUS_ACTIVE
;
$this
->
parentPaths
=
$this
->
Conn
->
GetCol
(
$sql
,
'CategoryId'
);
// 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
));
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_category_id
,
$category_limit
);
// sort menu items
uasort
(
$items
,
Array
(&
$this
,
'_menuSort'
));
// process sub-menus of each menu
foreach
(
$items
as
$key
=>
$menu_item
)
{
if
(
$menu_item
[
'CategoryId'
]
==
$parent_category_id
)
{
// don't process myself - prevents recursion
continue
;
}
$sub_items
=
$this
->
_altBuildMenuStructure
(
$menu_item
[
'CategoryId'
],
$category_limit
);
if
(
$sub_items
)
{
$items
[
$key
][
'sub_items'
]
=
$sub_items
;
}
}
return
$items
;
}
/**
* 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
,
$lang_part
=
NULL
;
if
(
!
isset
(
$lang_part
)
)
{
/** @var kMultiLanguageHelper $ml_helper */
$ml_helper
=
$this
->
Application
->
recallObject
(
'kMultiLanguageHelper'
);
$lang_part
=
''
;
$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
();
$extra_select_clause
=
''
;
foreach
(
$this
->
itemParams
as
$category_field_data
)
{
$extra_select_clause
.=
', c.'
.
$category_field_data
[
0
];
}
// 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.`Type` = '
.
PAGE_TYPE_TEMPLATE
.
', c.Template, CONCAT("id:", c.CategoryId)) AS ItemPath,
c.ParentPath AS ParentPath,
c.ParentId As ParentId,
\'
cat
\'
AS ItemType,
c.IsMenu, c.Type, c.ThemeId, c.UseExternalUrl, c.ExternalUrl, c.UseMenuIconUrl, c.MenuIconUrl,
c.Status'
.
$extra_select_clause
.
'
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
)
{
$item_parent_id
=
$item_data
[
'ParentId'
];
if
(
!
array_key_exists
(
$item_parent_id
,
$items_by_parent
)
)
{
$items_by_parent
[
$item_parent_id
]
=
Array
();
}
$items_by_parent
[
$item_parent_id
][
$item_id
]
=
$item_data
;
}
}
return
array_key_exists
(
$parent_id
,
$items_by_parent
)
?
$items_by_parent
[
$parent_id
]
:
Array
();
}
/**
* Method for sorting pages by priority in descending 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
}
/**
* Determines if menu item parameters require formatting.
*
* @return boolean
*/
protected
function
menuItemsRequireFormatting
()
{
foreach
(
$this
->
itemParams
as
$category_field_data
)
{
if
(
array_key_exists
(
1
,
$category_field_data
)
)
{
return
true
;
}
}
return
false
;
}
}
Event Timeline
Log In to Comment