<?php
//
// +---------------------------------------------------------------------------+
// | Nitro :: Module :: Menu |
// +---------------------------------------------------------------------------+
// | Copyright (c) 2006 June Systems BV |
// +---------------------------------------------------------------------------+
// | This library is free software; you can redistribute it and/or modify it |
// | under the terms of the GNU Lesser General Public License as published by |
// | the Free Software Foundation; either version 2.1 of the License, or (at |
// | your option) any later version. |
// | |
// | This library is distributed in the hope that it will be useful, but |
// | WITHOUT ANY WARRANTY; without even the implied warranty of |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
// | General Public License for more details. |
// | |
// | You should have received a copy of the GNU Lesser General Public License |
// | along with this library; if not, write to the Free Software Foundation, |
// | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
// +---------------------------------------------------------------------------+
// | Authors: Siggi Oskarsson <hide@address.com> |
// | Jesper Avot <hide@address.com |
// +---------------------------------------------------------------------------+
//
// $Id: Menu.inc.php 229 2008-04-17 09:20:31Z oli $
//
// Nitro's default Menu class
//
/**
* This file contains the Nitro Menu Module
*
* @author Siggi Oskarsson
* @copyright June Systems BV, 2006
* @version $Revision: 1.4 $
* @package Modules
*/
/**
* Include prototype module class
*/
require_once "Nitro/Module.inc.php";
/**
* Include form library
*/
require_once "Nitro/Libraries/Form.inc.php";
/**
* Menu module class
*
* @package Modules
* @author Siggi Oskarsson <hide@address.com>
* @author Jesper Avot <hide@address.com>
* @copyright June Systems BV, 2006
* @access public
*/
class NitroModuleMenu extends NitroModule {
/**
* @var string Module ID string
*/
var $IDString = "NitroModuleMenu";
/**
* @var int Menu ID in database
*/
var $MenuID;
/**
* @var int Template ID of template to use to draw the menu
*/
var $TemplateID;
/**
* @var boolean Expand the menu?
*/
var $Expand;
/**
* @var array Array of menu
*/
var $Menu;
/**
* @var string Default menu template
*/
var $DefaultTemplate;
/**
* Menu module constructor function
*
* @param string $ObjectID String with the current ObjectID
* @param mixed $Settings Array with the Module Settings, default is FALSE
* @access public
*/
function NitroModuleMenu($ObjectID, $Settings = FALSE)
{
/**
* Call the parent constructor
*/
parent::NitroModule();
/**
* Set ObjectID, ModuleSettings and the DefaultTemplate.
*/
$this->ObjectID = $ObjectID;
$this->SetModuleSettings($Settings);
$this->DefaultTemplate = NITRO_PATH . "Defaults/Templates/Menu.tpl";
}
/**
* GetModuleRunTimeConfiguration function
*
* @return array Array for the form libraries.
*/
function GetModuleRuntimeConfiguration()
{
return Array("MenuID" => "SELECT/DB=NitroBO:Menu:MenuID:Name",
"TemplateID" => "SELECT/DB=NitroBO:Template:TemplateID:Name",
"Expand" => "RADIO/VALUES=1:True,0:False",
"Depth" => "SELECT/NUMLIST=1:12",
"Flatten" => "RADIO/VALUES=1:True,0:False",
"AllowCache" => "RADIO/VALUES=1:True,0:False",
"SelectedTreeOnly" => "RADIO/VALUES=1:True,0:False");
}
/**
* Draw function
*
* Draws the menu.
*
* @param mixed $RunTimeSettings The current RunTimeSettings.
* @retrun mixed The drawn menu or in case of failure FALSE.
*/
function Draw($RunTimeSettings)
{
$CacheID = $this->isMenuCacheable($RunTimeSettings);
Debug("Menu", "Draw", "Initialize Template engine (ID = " . $RunTimeSettings["TemplateID"] . ")", __FILE__, __LINE__, DEBUG_MOD_OK);
if ($Menu = new NitroTemplate($RunTimeSettings["TemplateID"])) {
if ($CacheID) {
$Menu->Caching(TRUE,($this->Conf['Default']['MenuCacheLifeTime'] ? $this->Conf['Default']['MenuCacheLifeTime'] : 1800));
if ($_GET["ByPassCache"]) $Menu->ClearCache($CacheID);
if ($Menu->IsCached($CacheID)) {
Debug("Menu", "Draw", "Cache found, using: $CacheID", __FILE__, __LINE__, DEBUG_MOD_OK);
return $Menu->Fetch($this->DefaultTemplate, $CacheID);
}
}
if ($this->CreateMenu($RunTimeSettings)) {
$Menu->Assign("Menu", $this->Menu["Children"]);
return $Menu->Fetch($this->DefaultTemplate, $CacheID);
} else {
return FALSE;
}
} else {
Debug("Menu", "Draw", "Template engine failed to initialize", __FILE__, __LINE__, DEBUG_MOD_ERR);
}
}
/**
* Create the menu tree
*
* This function is the base function for creating the menu tree. It
* is called from the Draw function.
*
* @see Menu::Draw()
* @param array $RuntimeSettings Runtimesettings to use to create the menu
* @return boolean (TRUE/FALSE)
* @access public
*/
function CreateMenu($RuntimeSettings)
{
global $__NSess;
if ((int)$RuntimeSettings["MenuID"]) {
$Query = "SELECT
M.*,
MD.*,
MAX(MD.Version) AS Version
FROM
`Menu` AS M
LEFT
JOIN
`MenuData` AS MD
ON
MD.MenuID = M.MenuID
AND
(MD.Language = " . NitroPrepareDB($__NSess->Language) . " OR MD.Language = '')
AND
(MD.VisibleFrom <= NOW() OR MD.VisibleFrom IS NULL)
AND
(MD.VisibleTill >= NOW() OR MD.VisibleTill IS NULL)
" . (!(array_key_exists('showUnpublished', $RuntimeSettings) && $RuntimeSettings["showUnpublished"]) ? "AND MD.Published = 1 " : "") . "
WHERE
M.MenuID = " . (int)$RuntimeSettings["MenuID"] . "
GROUP
BY
M.MenuID
ORDER
BY
MD.Language
DESC,
MD.Version
DESC
LIMIT
1";
$Menu = $this->DB->getRow($Query);
$Menu["inSelectedTree"] = FALSE;
$Menu["Children"] = $this->GetMenuChildren($Menu["MenuID"], $RuntimeSettings["Expand"], 0, 0, 0, (array_key_exists('showUnpublished', $RuntimeSettings) ? $RuntimeSettings["showUnpublished"] : 0));
if (array_key_exists('SelectedTreeOnly', $RuntimeSettings) && $RuntimeSettings["SelectedTreeOnly"]) {
$Menu["Children"] = $this->GetSelectedTree($Menu["Children"]);
} elseif (array_key_exists('Flatten', $RuntimeSettings) && $RuntimeSettings["Flatten"]) {
$Menu["Children"] = $this->FlattenMenu($Menu["Children"]);
}
if ($this->flagSelectedTree($Menu['Children'])) {
$Menu['inSelectedTree'] = TRUE;
}
$this->Menu = $Menu;
return TRUE;
} else {
return FALSE;
}
}
/**
* Retreive all children of a menu ID
*
* This function retreives all the cild menu items of the menu
* item given by ParentID.
*
* @param int $ParentID ID of menu item which the children are supposed to be retreived
* @param boolean $Expand Also retreive all the child elements of the cildren of the menu?
* @param int $Skip Skip X levels before starting to retreive items (only works if Expand is TRUE)
* @param int $Depth Depth of which cild items are supposed to be retreived (only works if Expand is TRUE)
* @param int $Level Internal counter used to iterate
* @param int $showUnpublished Show the Unpublished items or not, default is 0.
* @access private
*/
function GetMenuChildren($ParentID, $Expand = 0, $Skip = 0, $Depth = 0, $Level = 0, $showUnpublished = 0)
{
$Skip = (int)$Skip;
$Depth = (int)$Depth;
$Level = (int)$Level;
global $__NSess;
if ($Level > 99) {
$Menu = FALSE;
} else {
$Query = "SELECT
M.*,
MD.Language,
MD.Version,
MD.Title,
MD.Description,
MD.PageID,
MD.Forward,
MD.Target,
MD.Published,
P.IDString AS PageIDString
FROM
`Menu` AS M,
`MenuData` AS MD
LEFT
JOIN
`Page_SecurityGroup` AS PSG
ON
PSG.PageID = MD.PageID
AND
PSG.SecurityGroupID IN (" . implode(",", $this->Sess->SecurityGroups) . ")
LEFT
JOIN
`Page` AS P
ON
P.PageID = PSG.PageID
WHERE
M.ParentID = " . $ParentID . "
AND
M.MenuID != " . $ParentID . "
AND
MD.MenuID = M.MenuID
AND
(MD.Language = " . NitroPrepareDB($__NSess->Language) . " OR MD.Language = '')
" . (!$showUnpublished ? "AND MD.Published = 1 " : "") . "
AND
(MD.VisibleFrom <= NOW() OR MD.VisibleFrom IS NULL)
AND
(MD.VisibleTill >= NOW() OR MD.VisibleTill IS NULL)
AND
(MD.Forward IS NOT NULL OR P.PageID IS NOT NULL)
ORDER
BY
M.SortOrder,
MD.Language
ASC,
MD.Version
ASC,
MD.Title";
$Result = $this->DB->query($Query);
if ($Result->numRows()) {
$MenuTmp = array();
while ($Row = $Result->fetchArray()) {
$MenuTmp[$Row["MenuID"]] = $Row;
}
$Menu = Array();
$n = 0;
foreach ($MenuTmp AS $MenuID => $Row) {
if ($Row["PageIDString"]) {
$Link = $this->Conf["Settings"]["PageURL"].$Row["PageIDString"];
} elseif ($Row["Forward"]) {
$Link = $this->GetForwardURL($Row["Forward"]);
} else {
$Link = FALSE;
}
if ($Link) {
if ($Skip > $Level) {
$Menu[$n] = $this->GetMenuChildren($Row["MenuID"], $Expand, $Skip, $Depth, $Level++, $showUnpublished);
} else {
$Menu[$n] = $Row;
$Menu[$n]["ID"] = $Row["MenuID"];
$Menu[$n]["PageIDString"] = $Row["PageIDString"];
$Menu[$n]["Name"] = $Row["Title"];
$Menu[$n]["EncodedName"] = rawurlencode($Row["Title"]);
$Menu[$n]["Link"] = $Link;
$Menu[$n]['inSelectedTree'] = FALSE;
if ($Expand) {
$Menu[$n]["Children"] = $this->GetMenuChildren($Row["MenuID"], $Expand, $Skip, $Depth, $Level++, $showUnpublished);
} else {
$Menu[$n]["Children"] = FALSE;
}
}
$n++;
}
}
} else {
$Menu = FALSE;
}
$Result->free();
}
return $Menu;
}
/**
* Get Menu item forward
*
* This functions retreives the real page (and security) for the
* menu item, if the menu item is a forward to another menu item.
*
* @param int $MenuID ID of menu item to use
* @return mixed The result or in case of failure FALSE.
* @access public
*/
function GetForwardUrl($MenuID)
{
global $__NSess;
$Query = "SELECT
M.*,
MD.*,
P.IDString AS PageIDString
FROM
`Menu` AS M,
`MenuData` AS MD
LEFT
JOIN
`Page_SecurityGroup` AS PSG
ON
PSG.PageID = MD.PageID
AND
PSG.SecurityGroupID IN (" . implode(",", $this->Sess->SecurityGroups) . ")
LEFT
JOIN
`Page` AS P
ON
P.PageID = PSG.PageID
WHERE
M.MenuID = " . $MenuID . "
AND
MD.MenuID = M.MenuID
AND
(MD.Language = " . NitroPrepareDB($__NSess->Language) . " OR MD.Language = '')
AND
MD.Version = 1
AND
MD.Published = 1
AND
(MD.VisibleFrom <= NOW() OR MD.VisibleFrom IS NULL)
AND
(MD.VisibleTill >= NOW() OR MD.VisibleTill IS NULL)
AND
(MD.Forward IS NOT NULL OR P.PageID IS NOT NULL)
ORDER
BY
M.SortOrder,
MD.Language DESC,
MD.Version
DESC";
$Result = $this->DB->query($Query);
if ($Result->numRows()) {
$Row = $Result->fetchArray();
if ($Row["PageIDString"]) {
$RV = $this->Conf["Settings"]["PageURL"].$Row["PageIDString"];
} elseif ($Row["Forward"] && $Row["Forward"] != $MenuID) {
$RV = $this->GetForwardURL($Row["Forward"]);
} else {
$RV = FALSE;
}
} else {
$RV = FALSE;
}
$Result->free();
return $RV;
}
/**
* Get selected tree of menu
*
* This function returns only the items that are in the selected tree
* of the menu.
*
* @param array $Menu Reference to the Menu array
* @param mixed $P The current page, default is NULL
* @param int $Level The current menu level, default is 0
* @return boolean (TRUE/FALSE)
*/
function GetSelectedTree($Menu, $P = NULL, $Level = 0) {
if (!$P) $P = ($this->CurrentPage ? $this->CurrentPage : NitroGetPageIDString($this->Conf["Default"]["Page"]));
$SelectedTree = Array();
if (is_array($Menu)) {
foreach($Menu AS $ValArr) {
if ($ValArr["PageIDString"] == $P) {
$ST = $ValArr;
unset($ST["Children"]);
$SelectedTree[] = $ST;
} else {
$ST = $this->GetSelectedTree($ValArr["Children"], $P, $Level + 1);
if (is_array($ST)) {
$SelectedTree = array_merge($SelectedTree, $ST);
$ST = $ValArr;
unset($ST["Children"]);
array_unshift($SelectedTree, $ST);
}
}
}
if (count($SelectedTree)) {
return $SelectedTree;
} else {
return FALSE;
}
} else {
return FALSE;
}
}
/**
* Get selected tree of menu
*
* This function returns only the items that are in the selected tree
* of the menu.
*
* @param array $Menu Reference to the Menu array
* @param mixed $P The current page, default is NULL
* @param int $Level The current menu level, default is 0
* @return boolean (TRUE/FALSE)
*/
function flagSelectedTree(&$Menu, $P = NULL, $Level = 0)
{
if (!$P) $P = ($this->CurrentPage ? $this->CurrentPage : NitroGetPageIDString($this->Conf["Default"]["Page"]));
$selectedTree = FALSE;
if (is_array($Menu)) {
foreach($Menu AS $k => $ValArr) {
if ($ValArr["PageIDString"] == $P) {
$Menu[$k]['inSelectedTree'] = TRUE;
$selectedTree = TRUE;
} else {
if ($this->flagSelectedTree($Menu[$k]["Children"], $P, $Level + 1)) {
$Menu[$k]['inSelectedTree'] = TRUE;
$selectedTree = TRUE;
}
}
}
if ($selectedTree) {
return TRUE;
} else {
return FALSE;
}
} else {
return FALSE;
}
}
/**
* Flatten menu array
*
* This function takes as argument an array of a menu and flattens it
* to just one level. This can be used to create layers for for instance
* a pull down menu where each child level is its own element on the page.
*
* @param array $Menu Menu array
* @access public
*/
function FlattenMenu($Menu)
{
if (is_array($Menu)) {
$NewMenu = Array();
foreach($Menu AS $ValArr) {
if (is_array($ValArr["Children"])) {
$NewMenu[] = $ValArr;
$temp = $this->FlattenMenu($ValArr["Children"]);
foreach($temp AS $tempArr) {
$NewMenu[] = $tempArr;
}
}
}
$TempNewMenu = $NewMenu;
foreach($TempNewMenu AS $ID => $ValArr) {
if (is_array($ValArr["Children"])) {
foreach($ValArr["Children"] AS $CID => $Child) {
if (is_array($NewMenu[$ID]["Children"][$CID]["Children"])) {
$NewMenu[$ID]["Children"][$CID]["Children"] = TRUE;
} else {
$NewMenu[$ID]["Children"][$CID]["Children"] = FALSE;
}
}
} else {
unset($NewMenu[$ID]);
}
}
return $NewMenu;
} else {
return $Menu;
}
}
/**
* isMenuCacheable function
*
* Not used now, we let the caching to Nitro self.
*
* @param mixed $RunTimeSettings The current RunTimeSettings.
* @return boolean FALSE
*/
function isMenuCacheable($RunTimeSettings)
{
return FALSE;
}
/**
* isCacheable function
*
* Check if this Module is cacheable or not.
*
* @param mixed $RunTimeSettings The current RunTimeSettings.
* @return mixed Is the Module allowed to be cached or not.
*/
function isCacheable($RuntimeSettings)
{
global $__NSess;
$Settings = Array();
if ($RuntimeSettings["AllowCache"]) {
foreach($RuntimeSettings AS $ID => $Value) {
$Settings[] = "$ID-$Value";
}
if (!$P) $P = ($this->CurrentPage ? $this->CurrentPage : NitroGetPageIDString($this->Conf['Default']['Page']));
$AllowedPages = NitroGetAllowedPages((int)$this->Sess->UserID);
$RV = $P . '_' . md5(serialize($AllowedPages)) . '_' . NitroGetUserLanguage() . '_'.implode('_', $Settings) . '_' . NITRO_VERSION;
} else {
$RV = FALSE;
}
return $RV;
}
}
?>