Location: PHPKode > projects > OpenNitro > trunk/Nitro/Modules/Menu.inc.php
<?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;
	}
}
?>
Return current item: OpenNitro