Compare commits

..

1 Commits

Author SHA1 Message Date
Romain Quetiez
18529b1330 Official release 1.0.2
SVN:1.0.2[1056]
2011-01-19 10:01:55 +00:00
937 changed files with 25376 additions and 113252 deletions

View File

@@ -274,7 +274,7 @@ class UserRightsMatrix extends UserRightsAddOnAPI
return true;
}
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
public function GetSelectFilter($oUser, $sClass)
{
$oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter;

View File

@@ -47,7 +47,7 @@ class UserRightsNull extends UserRightsAddOnAPI
return true;
}
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
public function GetSelectFilter($oUser, $sClass)
{
$oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter;

File diff suppressed because it is too large Load Diff

View File

@@ -97,7 +97,7 @@ class URP_Profiles extends UserRightsBaseClass
function DoShowGrantSumary($oPage)
{
if ($this->GetRawName() == "Administrator")
if ($this->GetName() == "Administrator")
{
// Looks dirty, but ok that's THE ONE
$oPage->p(Dict::S('UI:UserManagement:AdminProfile+'));
@@ -119,7 +119,7 @@ class URP_Profiles extends UserRightsBaseClass
$oGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
if (is_object($oGrant) && ($oGrant->Get('permission') == 'yes'))
{
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription()).'">'.htmlentities($oStimulus->GetLabel()).'</span>';
}
}
$sStimuli = implode(', ', $aStimuli);
@@ -660,8 +660,7 @@ class UserRightsProjection extends UserRightsAddOnAPI
public function Init()
{
// CacheData to be invoked in a module extension
//MetaModel::RegisterPlugin('userrights', 'ACbyProfile', array($this, 'CacheData'));
MetaModel::RegisterPlugin('userrights', 'ACbyProfile', array($this, 'CacheData'));
}
protected $m_aDimensions = array(); // id -> object
@@ -734,7 +733,7 @@ exit;
return true;
}
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
public function GetSelectFilter($oUser, $sClass)
{
$aConditions = array();
foreach ($this->m_aDimensions as $iDimension => $oDimension)

View File

@@ -45,13 +45,11 @@ class ajax_page extends WebPage
{
parent::__construct($s_title);
$this->m_sReadyScript = "";
//$this->add_header("Content-type: text/html; charset=utf-8");
$this->add_header("Content-type: text/html; charset=utf-8");
$this->add_header("Cache-control: no-cache");
$this->m_sCurrentTabContainer = '';
$this->m_sCurrentTab = '';
$this->m_aTabs = array();
$this->sContentType = 'text/html';
$this->sContentDisposition = 'inline';
}
public function AddTabContainer($sTabContainer, $sPrefix = '')
@@ -88,67 +86,48 @@ class ajax_page extends WebPage
return $sPreviousTab;
}
public function GetCurrentTab()
{
return $this->m_sCurrentTab;
}
/**
* Echoes the content of the whole page
* @return void
*/
public function output()
{
if (!empty($this->sContentType))
{
$this->add_header('Content-type: '.$this->sContentType);
}
if (!empty($this->sContentDisposition))
{
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
}
foreach($this->a_headers as $s_header)
{
header($s_header);
}
if (count($this->m_aTabs) > 0)
{
$this->add_ready_script(
<<<EOF
// The "tab widgets" to handle.
var tabs = $('div[id^=tabbedContent]');
if ($.bbq)
// This selector will be reused when selecting actual tab widget A elements.
var tab_a_selector = 'ul.ui-tabs-nav a';
// Enable tabs on all tab widgets. The `event` property must be overridden so
// that the tabs aren't changed on click, and any custom event name can be
// specified. Note that if you define a callback for the 'select' event, it
// will be executed for the selected tab whenever the hash changes.
tabs.tabs({ event: 'change' });
// Define our own click handler for the tabs, overriding the default.
tabs.find( tab_a_selector ).click(function()
{
// This selector will be reused when selecting actual tab widget A elements.
var tab_a_selector = 'ul.ui-tabs-nav a';
var state = {};
// Get the id of this tab widget.
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
// Enable tabs on all tab widgets. The `event` property must be overridden so
// that the tabs aren't changed on click, and any custom event name can be
// specified. Note that if you define a callback for the 'select' event, it
// will be executed for the selected tab whenever the hash changes.
tabs.tabs({ event: 'change' });
// Define our own click handler for the tabs, overriding the default.
tabs.find( tab_a_selector ).click(function()
{
var state = {};
// Get the id of this tab widget.
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
// Get the index of this tab.
var idx = $(this).parent().prevAll().length;
// Set the state!
state[ id ] = idx;
$.bbq.pushState( state );
});
}
else
{
tabs.tabs();
}
// Get the index of this tab.
var idx = $(this).parent().prevAll().length;
// Set the state!
state[ id ] = idx;
$.bbq.pushState( state );
});
EOF
);
}
@@ -161,7 +140,7 @@ EOF
$container_index = 0;
if (count($m_aTabs) > 0)
{
$sTabs = "<!-- tabs -->\n<div id=\"tabbedContent_{$sPrefix}{$sTabContainerName}\" class=\"light\">\n";
$sTabs = "<!-- tabs -->\n<div id=\"tabbedContent_{$sPrefix}{$container_index}\" class=\"light\">\n";
$sTabs .= "<ul>\n";
// Display the unordered list that will be rendered as the tabs
$i = 0;
@@ -186,28 +165,14 @@ EOF
$s_captured_output = ob_get_contents();
ob_end_clean();
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
{
// inline content != attachment && html => filter all scripts for malicious XSS scripts
echo self::FilterXSS($this->s_content);
}
else
{
echo $this->s_content;
}
//echo $this->s_deferred_content;
echo $this->s_content;
echo $this->s_deferred_content;
if (count($this->a_scripts) > 0)
{
echo "<script type=\"text/javascript\">\n";
echo implode("\n", $this->a_scripts);
echo "\n</script>\n";
}
if (!empty($this->s_deferred_content))
{
echo "<script type=\"text/javascript\">\n";
echo "\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');\n";
echo "\n</script>\n";
}
if (!empty($this->m_sReadyScript))
{
echo "<script type=\"text/javascript\">\n";
@@ -216,7 +181,7 @@ EOF
}
if (trim($s_captured_output) != "")
{
echo self::FilterXSS($s_captured_output);
echo $s_captured_output;
}
}
@@ -241,64 +206,6 @@ EOF
parent::add($sHtml);
}
}
/**
* Records the current state of the 'html' part of the page output
* @return mixed The current state of the 'html' output
*/
public function start_capture()
{
if (!empty($this->m_sCurrentTabContainer) && !empty($this->m_sCurrentTab))
{
$iOffset = isset($this->m_aTabs[$this->m_sCurrentTabContainer]['content'][$this->m_sCurrentTab]) ? strlen($this->m_aTabs[$this->m_sCurrentTabContainer]['content'][$this->m_sCurrentTab]): 0;
return array('tc' => $this->m_sCurrentTabContainer, 'tab' => $this->m_sCurrentTab, 'offset' => $iOffset);
}
else
{
return parent::start_capture();
}
}
/**
* Returns the part of the html output that occurred since the call to start_capture
* and removes this part from the current html output
* @param $offset mixed The value returned by start_capture
* @return string The part of the html output that was added since the call to start_capture
*/
public function end_capture($offset)
{
if (is_array($offset))
{
if (isset($this->m_aTabs[$offset['tc']]['content'][$offset['tab']]))
{
$sCaptured = substr($this->m_aTabs[$offset['tc']]['content'][$offset['tab']], $offset['offset']);
$this->m_aTabs[$offset['tc']]['content'][$offset['tab']] = substr($this->m_aTabs[$offset['tc']]['content'][$offset['tab']], 0, $offset['offset']);
}
else
{
$sCaptured = '';
}
}
else
{
$sCaptured = parent::end_capture($offset);
}
return $sCaptured;
}
/**
* Add any text or HTML fragment (identified by an ID) at the end of the body of the page
* This is useful to add hidden content, DIVs or FORMs that should not
* be embedded into each other.
*/
public function add_at_the_end($s_html, $sId = '')
{
if ($sId != '')
{
$this->add_script("$('#{$sId}').remove();"); // Remove any previous instance of the same Id
}
$this->s_deferred_content .= $s_html;
}
/**
* Adds a script to be executed when the DOM is ready (typical JQuery use)
@@ -307,7 +214,10 @@ EOF
*/
public function add_ready_script($sScript)
{
$this->m_sReadyScript .= $sScript."\n";
// Does nothing in ajax rendered content.. for now...
// Maybe we should add this as a simple <script> tag at the end of the output
// considering that at this time everything in the page is "ready"...
$this->m_sReadyScript .= $sScript;
}
/**
@@ -320,10 +230,6 @@ EOF
return 0;
}
public static function FilterXSS($sHTML)
{
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
}
}
?>

View File

@@ -26,10 +26,8 @@
require_once(APPROOT.'/application/applicationcontext.class.inc.php');
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
require_once(APPROOT.'/application/sqlblock.class.inc.php');
require_once(APPROOT.'/application/audit.category.class.inc.php');
require_once(APPROOT.'/application/audit.rule.class.inc.php');
require_once(APPROOT.'/application/query.class.inc.php');
//require_once(APPROOT.'/application/menunode.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');

View File

@@ -24,43 +24,6 @@
*/
require_once(APPROOT."/application/utils.inc.php");
/**
* Interface for directing end-users to the relevant application
*/
interface iDBObjectURLMaker
{
public static function MakeObjectURL($sClass, $iId);
}
/**
* Direct end-users to the standard iTop application: UI.php
*/
class iTopStandardURLMaker implements iDBObjectURLMaker
{
public static function MakeObjectURL($sClass, $iId)
{
$sPage = DBObject::ComputeStandardUIPage($sClass);
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
$sUrl = "{$sAbsoluteUrl}pages/$sPage?operation=details&class=$sClass&id=$iId";
return $sUrl;
}
}
/**
* Direct end-users to the standard Portal application
*/
class PortalURLMaker implements iDBObjectURLMaker
{
public static function MakeObjectURL($sClass, $iId)
{
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
$sUrl = "{$sAbsoluteUrl}portal/index.php?operation=details&class=$sClass&id=$iId";
return $sUrl;
}
}
/**
* Helper class to store and manipulate the parameters that make the application's context
*
@@ -77,16 +40,12 @@ class ApplicationContext
protected $aValues;
protected static $aDefaultValues; // Cache shared among all instances
public function __construct($bReadContext = true)
public function __construct()
{
$this->aNames = array(
'org_id', 'menu'
);
if ($bReadContext)
{
$this->ReadContext();
}
$this->ReadContext();
}
/**
@@ -95,10 +54,10 @@ class ApplicationContext
*/
protected function ReadContext()
{
if (!isset(self::$aDefaultValues))
if (empty(self::$aDefaultValues))
{
self::$aDefaultValues = array();
$aContext = utils::ReadParam('c', array(), false, 'context_param');
$aContext = utils::ReadParam('c', array());
foreach($this->aNames as $sName)
{
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
@@ -115,7 +74,6 @@ class ApplicationContext
if (MetaModel::IsValidClass('Organization'))
{
$oSearchFilter = new DBObjectSearch('Organization');
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->Count();
if ($iCount == 1)
@@ -168,7 +126,7 @@ class ApplicationContext
$sContext = "";
foreach($this->aValues as $sName => $sValue)
{
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"$sValue\" />\n";
}
return $sContext;
}
@@ -208,154 +166,5 @@ class ApplicationContext
unset($this->aValues[$sParamName]);
}
}
/**
* Initializes the given object with the default values provided by the context
*/
public function InitObjectFromContext(DBObject &$oObj)
{
$sClass = get_class($oObj);
foreach($this->GetNames() as $key)
{
$aCallSpec = array($sClass, 'MapContextParam');
if (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsWritable())
{
$value = $this->GetCurrentValue($key, null);
if (!is_null($value))
{
$oObj->Set($sAttCode, $value);
}
}
}
}
}
}
static $m_sUrlMakerClass = null;
/**
* Set the current application url provider
* @param sClass string Class implementing iDBObjectURLMaker
* @return void
*/
public static function SetUrlMakerClass($sClass = 'iTopStandardURLMaker')
{
$sPrevious = self::GetUrlMakerClass();
self::$m_sUrlMakerClass = $sClass;
$_SESSION['UrlMakerClass'] = $sClass;
return $sPrevious;
}
/**
* Get the current application url provider
* @return string the name of the class
*/
public static function GetUrlMakerClass()
{
if (is_null(self::$m_sUrlMakerClass))
{
if (isset($_SESSION['UrlMakerClass']))
{
self::$m_sUrlMakerClass = $_SESSION['UrlMakerClass'];
}
else
{
self::$m_sUrlMakerClass = 'iTopStandardURLMaker';
}
}
return self::$m_sUrlMakerClass;
}
/**
* Get the current application url provider
* @return string the name of the class
*/
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
{
$oAppContext = new ApplicationContext();
if (is_null($sUrlMakerClass))
{
$sUrlMakerClass = self::GetUrlMakerClass();
}
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
if (strlen($sUrl) > 0)
{
if ($bWithNavigationContext)
{
return $sUrl."&".$oAppContext->GetForLink();
}
else
{
return $sUrl;
}
}
else
{
return '';
}
}
protected static $m_aPluginProperties = null;
/**
* Load plugin properties for the current session
* @return void
*/
protected static function LoadPluginProperties()
{
if (isset($_SESSION['PluginProperties']))
{
self::$m_aPluginProperties = $_SESSION['PluginProperties'];
}
else
{
self::$m_aPluginProperties = array();
}
}
/**
* Set plugin properties
* @param sPluginClass string Class implementing any plugin interface
* @param sProperty string Name of the property
* @param value scalar Value (numeric or string)
* @return void
*/
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
{
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
$_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value;
}
/**
* Get plugin properties
* @param sPluginClass string Class implementing any plugin interface
* @return array of sProperty=>value pairs
*/
public static function GetPluginProperties($sPluginClass)
{
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
{
return self::$m_aPluginProperties[$sPluginClass];
}
else
{
return array();
}
}
}
?>

View File

@@ -1,193 +0,0 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Class iPlugin
* Management of application plugin
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
interface iApplicationUIExtension
{
public function OnDisplayProperties($oObject, WebPage $oPage, $bEditMode = false);
public function OnDisplayRelations($oObject, WebPage $oPage, $bEditMode = false);
public function OnFormSubmit($oObject, $sFormPrefix = '');
public function OnFormCancel($sTempId); // temp id is made of session_id and transaction_id, it identifies the object in a unique way
public function EnumUsedAttributes($oObject); // Not yet implemented
public function GetIcon($oObject); // Not yet implemented
public function GetHilightClass($oObject);
public function EnumAllowedActions(DBObjectSet $oSet);
}
interface iApplicationObjectExtension
{
public function OnIsModified($oObject);
public function OnCheckToWrite($oObject);
public function OnCheckToDelete($oObject);
public function OnDBUpdate($oObject, $oChange = null);
public function OnDBInsert($oObject, $oChange = null);
public function OnDBDelete($oObject, $oChange = null);
}
/**
* New extension to add menu items in the "popup" menus inside iTop. Provides a greater flexibility than
* iApplicationUIExtension::EnumAllowedActions.
*
* To add some menus into iTop, declare a class that implements this interface, it will be called automatically
* by the application, as long as the class definition is included somewhere in the code
*/
interface iPopupMenuExtension
{
// Possible types of menu into which new items can be added
const MENU_OBJLIST_ACTIONS = 1; // $param is a DBObjectSet containing the list of objects
const MENU_OBJLIST_TOOLKIT = 2; // $param is a DBObjectSet containing the list of objects
const MENU_OBJDETAILS_ACTIONS = 3; // $param is a DBObject instance: the object currently displayed
const MENU_DASHBOARD_ACTIONS = 4; // $param is a Dashboard instance: the dashboard currently displayed
const MENU_USER_ACTIONS = 5; // $param is a null ??
/**
* Get the list of items to be added to a menu. The items will be inserted in the menu in the order of the returned array
* @param int $iMenuId The identifier of the type of menu, as listed by the constants MENU_xxx above
* @param mixed $param Depends on $iMenuId, see the constants defined above
* @return Array An array of ApplicationPopupMenuItem or an empty array if no action is to be added to the menu
*/
public static function EnumItems($iMenuId, $param);
}
/**
* Each menu items is defined by an instance of an object derived from the class
* ApplicationPopupMenu below
*
*/
abstract class ApplicationPopupMenuItem
{
protected $sUID;
protected $sLabel;
public function __construct($sUID, $sLabel)
{
$this->sUID = $sUID;
$this->sLabel = $sLabel;
}
public function GetUID()
{
return $this->sUID;
}
public function GetLabel()
{
return $this->sLabel;
}
/**
* Returns the components to create a popup menu item in HTML
* @return Hash A hash array: array('label' => , 'url' => , 'target' => , 'onclick' => )
*/
abstract public function GetMenuItem();
public function GetLinkedScripts()
{
return array();
}
}
/**
* Class for adding an item into a popup menu that browses to the given URL
*/
class URLPopupMenuItem extends ApplicationPopupMenuItem
{
protected $sURL;
protected $sTarget;
/**
* Class for adding an item that browses to the given URL
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
* @param string $sLabel The display label of the menu (must be localized)
* @param string $sURL If the menu is an hyperlink, provide the absolute hyperlink here
* @param string $sTarget In case the menu is an hyperlink and a specific target is needed (_blank for example), pass it here
*/
public function __construct($sUID, $sLabel, $sURL, $sTarget = '_top')
{
parent::__construct($sUID, $sLabel);
$this->sURL = $sURL;
$this->sTarget = $sTarget;
}
public function GetMenuItem()
{
return array ('label' => $this->GetLabel(), 'url' => $this->sURL, 'target' => $this->sTarget);
}
}
/**
* Class for adding an item into a popup menu that triggers some Javascript code
*/
class JSPopupMenuItem extends ApplicationPopupMenuItem
{
protected $sJSCode;
protected $aIncludeJSFiles;
/**
* Class for adding an item that triggers some Javascript code
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
* @param string $sLabel The display label of the menu (must be localized)
* @param string $sJSCode In case the menu consists in executing some havascript code inside the page, pass it here. If supplied $sURL ans $sTarget will be ignored
* @param array $aIncludeJSFiles An array of file URLs to be included (once) to provide some JS libraries for the page.
*/
public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = array())
{
parent::__construct($sUID, $sLabel);
$this->sJSCode = $sJSCode;
$this->aIncludeJSFiles = $aIncludeJSFiles;
}
public function GetMenuItem()
{
return array ('label' => $this->GetLabel(), 'onclick' => $this->sJSCode, 'url' => '#');
}
public function GetLinkedScripts()
{
return $this->aIncludeJSFiles;
}
}
/**
* Class for adding a separator (horizontal line, not selectable) the output
* will automatically reduce several consecutive separators to just one
*/
class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
{
/**
* Class for inserting a separator into a popup menu
*/
public function __construct()
{
parent::__construct('', '');
}
public function GetMenuItem()
{
return array ('label' => '<hr class="menu-separator">', 'url' => '');
}
}

View File

@@ -26,7 +26,7 @@
require_once(APPROOT."/application/webpage.class.inc.php");
class CLIPage implements Page
class CLIPage
{
function __construct($s_title)
{

File diff suppressed because it is too large Load Diff

View File

@@ -1,699 +0,0 @@
<?php
// Copyright (C) 2012 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
require_once(APPROOT.'application/dashlet.class.inc.php');
/**
* A user editable dashboard page
*
*/
abstract class Dashboard
{
protected $sTitle;
protected $sLayoutClass;
protected $aWidgetsData;
protected $oDOMNode;
protected $sId;
protected $aCells;
public function __construct($sId)
{
$this->sLayoutClass = null;
$this->aCells = array();
$this->oDOMNode = null;
$this->sId = $sId;
}
public function FromXml($sXml)
{
$this->aCells = array(); // reset the content of the dashboard
set_error_handler(array('Dashboard', 'ErrorHandler'));
$oDoc = new DOMDocument();
$oDoc->loadXML($sXml);
restore_error_handler();
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
$oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0);
$this->sLayoutClass = $oLayoutNode->textContent;
$oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0);
$this->sTitle = $oTitleNode->textContent;
$oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0);
$oCellsList = $oCellsNode->getElementsByTagName('cell');
foreach($oCellsList as $oCellNode)
{
$aDashletList = array();
$oDashletList = $oCellNode->getElementsByTagName('dashlet');
foreach($oDashletList as $oDomNode)
{
$sDashletClass = $oDomNode->getAttribute('xsi:type');
$sId = $oDomNode->getAttribute('id');
$oNewDashlet = new $sDashletClass($sId);
$oNewDashlet->FromDOMNode($oDomNode);
$aDashletList[] = $oNewDashlet;
}
$this->aCells[] = $aDashletList;
}
}
/**
* Error handler to turn XML loading warnings into exceptions
*/
public static function ErrorHandler($errno, $errstr, $errfile, $errline)
{
if ($errno == E_WARNING && (substr_count($errstr,"DOMDocument::loadXML()")>0))
{
throw new DOMException($errstr);
}
else
{
return false;
}
}
public function ToXml()
{
$oDoc = new DOMDocument();
$oDoc->formatOutput = true; // indent (must be loaded with option LIBXML_NOBLANKS)
$oDoc->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect
$oMainNode = $oDoc->createElement('dashboard');
$oMainNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
$oDoc->appendChild($oMainNode);
$oNode = $oDoc->createElement('layout', $this->sLayoutClass);
$oMainNode->appendChild($oNode);
$oNode = $oDoc->createElement('title', $this->sTitle);
$oMainNode->appendChild($oNode);
$oCellsNode = $oDoc->createElement('cells');
$oMainNode->appendChild($oCellsNode);
foreach ($this->aCells as $aCell)
{
$oCellNode = $oDoc->createElement('cell');
$oCellsNode->appendChild($oCellNode);
foreach ($aCell as $oDashlet)
{
$oNode = $oDoc->createElement('dashlet');
$oCellNode->appendChild($oNode);
$oNode->setAttribute('id', $oDashlet->GetID());
$oNode->setAttribute('xsi:type', get_class($oDashlet));
$oDashlet->ToDOMNode($oNode);
}
}
$sXml = $oDoc->saveXML();
return $sXml;
}
public function FromParams($aParams)
{
$this->sLayoutClass = $aParams['layout_class'];
$this->sTitle = $aParams['title'];
foreach($aParams['cells'] as $aCell)
{
$aCellDashlets = array();
foreach($aCell as $aDashletParams)
{
$sDashletClass = $aDashletParams['dashlet_class'];
$sId = $aDashletParams['dashlet_id'];
$oNewDashlet = new $sDashletClass($sId);
$oForm = $oNewDashlet->GetForm();
$oForm->SetParamsContainer($sId);
$oForm->SetPrefix('');
$aValues = $oForm->ReadParams();
$oNewDashlet->FromParams($aValues);
$aCellDashlets[] = $oNewDashlet;
}
$this->aCells[] = $aCellDashlets;
}
}
public function Save()
{
}
public function GetLayout()
{
return $this->sLayoutClass;
}
public function SetLayout($sLayoutClass)
{
$this->sLayoutClass = $sLayoutClass;
}
public function GetTitle()
{
return $this->sTitle;
}
public function SetTitle($sTitle)
{
$this->sTitle = $sTitle;
}
public function AddDashlet($oDashlet)
{
$sId = $this->GetNewDashletId();
$oDashlet->SetId($sId);
$this->aCells[] = array($oDashlet);
}
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$oPage->add('<h1>'.Dict::S($this->sTitle).'</h1>');
$oLayout = new $this->sLayoutClass;
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
$oPage->add_linked_script('../js/dashlet.js');
$oPage->add_linked_script('../js/dashboard.js');
}
}
public function RenderProperties($oPage)
{
// menu to pick a layout and edit other properties of the dashboard
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div style="text-align:center">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
$oPage->add('<div id="select_layout" style="text-align:center">');
foreach( get_declared_classes() as $sLayoutClass)
{
if (is_subclass_of($sLayoutClass, 'DashboardLayout'))
{
$oReflection = new ReflectionClass($sLayoutClass);
if (!$oReflection->isAbstract())
{
$aCallSpec = array($sLayoutClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec);
$sChecked = ($this->sLayoutClass == $sLayoutClass) ? 'checked' : '';
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" /></label>'); // title="" on either the img or the label does nothing !
}
}
}
$oPage->add('</div>');
$oForm = new DesignerForm();
$oField = new DesignerLongTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
$oForm->AddField($oField);
$this->SetFormParams($oForm);
$oForm->RenderAsPropertySheet($oPage, false, ':itop-dashboard');
$oPage->add('</div>');
$oPage->add_ready_script(
<<<EOF
$('#select_layout').buttonset();
$('#select_layout input').click( function() {
var sLayoutClass = $(this).val();
$(':itop-dashboard').dashboard('option', {layout_class: sLayoutClass});
} );
$('#row_attr_dashboard_title').property_field('option', {parent_selector: ':itop-dashboard', auto_apply: false, 'do_apply': function() {
var sTitle = $('#attr_dashboard_title').val();
$(':itop-dashboard').dashboard('option', {title: sTitle});
return true;
}
});
EOF
);
}
public function RenderDashletsSelection($oPage)
{
// Toolbox/palette to drag and drop dashlets
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div id="select_dashlet" style="text-align:center">');
foreach( get_declared_classes() as $sDashletClass)
{
if (is_subclass_of($sDashletClass, 'Dashlet'))
{
$oReflection = new ReflectionClass($sDashletClass);
if (!$oReflection->isAbstract())
{
$aCallSpec = array($sDashletClass, 'IsVisible');
$bVisible = call_user_func($aCallSpec);
if ($bVisible)
{
$aCallSpec = array($sDashletClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec);
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="dashlet_icon ui-widget-content ui-corner-all" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'" style="width:34px; height:34px; display:inline-block; margin:2px;"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
}
}
}
}
$oPage->add('</div>');
$oPage->add('</div>');
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
$oPage->add_ready_script("$('.layout_cell').droppable({accept:'.dashlet_icon', hoverClass:'dragHover'});");
}
public function RenderDashletsProperties($oPage)
{
// Toolbox/palette to edit the properties of each dashlet
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
foreach($this->aCells as $aCell)
{
foreach($aCell as $oDashlet)
{
$sId = $oDashlet->GetID();
$sClass = get_class($oDashlet);
if ($oDashlet->IsVisible())
{
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
$oForm = $oDashlet->GetForm();
$this->SetFormParams($oForm);
$oForm->RenderAsPropertySheet($oPage, false, ':itop-dashboard');
$oPage->add('</div>');
}
}
}
$oPage->add('</div>');
$oPage->add('</div>');
}
protected function GetNewDashletId()
{
$iNewId = 0;
foreach($this->aCells as $aDashlets)
{
foreach($aDashlets as $oDashlet)
{
$iNewId = max($iNewId, (int)$oDashlet->GetID());
}
}
return $iNewId + 1;
}
abstract protected function SetFormParams($oForm);
}
class RuntimeDashboard extends Dashboard
{
protected $bCustomized;
public function __construct($sId)
{
parent::__construct($sId);
$this->bCustomized = false;
}
public function SetCustomFlag($bCustomized)
{
$this->bCustomized = $bCustomized;
}
protected function SetFormParams($oForm)
{
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property'));
}
public function Save()
{
$sXml = $this->ToXml();
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$oUserDashboard->Set('contents', $sXml);
$oUserDashboard->DBUpdate();
}
else
{
// No such customized dasboard for the current user, let's create a new record
$oUserDashboard = new UserDashboard();
$oUserDashboard->Set('user_id', UserRights::GetUserId());
$oUserDashboard->Set('menu_code', $this->sId);
$oUserDashboard->Set('contents', $sXml);
$oUserDashboard->DBInsert();
}
}
public function Revert()
{
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$oUserDashboard->DBDelete();
}
}
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
parent::Render($oPage, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
$sEditMenu = "<td><span id=\"DashboardMenu\"><ul><li><img src=\"../images/edit.png\"><ul>";
$aActions = array();
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}')");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
if ($this->bCustomized)
{
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}'); else return false");
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
}
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
$sEditMenu = addslashes($sEditMenu);
//$sEditBtn = addslashes('<div style="display: inline-block; height: 55px; width:200px;vertical-align:center;line-height:60px;text-align:left;"><button onclick="EditDashboard(\''.$this->sId.'\');">Edit This Page</button></div>');
$oPage->add_ready_script(
<<<EOF
$('#logOffBtn').parent().before('$sEditMenu');
$('#DashboardMenu>ul').popupmenu();
EOF
);
$oPage->add_script(
<<<EOF
function EditDashboard(sId)
{
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId},
function(data)
{
$('body').append(data);
}
);
return false;
}
function RevertDashboard(sId)
{
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId},
function(data)
{
$('body').append(data);
}
);
return false;
}
EOF
);
}
}
public function RenderEditor($oPage)
{
$oPage->add('<div id="dashboard_editor">');
$oPage->add('<div class="ui-layout-center">');
$this->Render($oPage, true);
$oPage->add('</div>');
$oPage->add('<div class="ui-layout-east">');
$this->RenderProperties($oPage);
$this->RenderDashletsSelection($oPage);
$this->RenderDashletsProperties($oPage);
$oPage->add('</div>');
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:DashboardEdit:Title');
$sOkButtonLabel = Dict::S('UI:Button:Save');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$sId = addslashes($this->sId);
$sLayoutClass = addslashes($this->sLayoutClass);
$sTitle = addslashes($this->sTitle);
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
$sAutoApplyConfirmationMessage = addslashes(Dict::S('UI:AutoApplyConfirmationMessage'));
$oPage->add_ready_script(
<<<EOF
window.bLeavingOnUserAction = false;
$('#dashboard_editor').dialog({
height: $('body').height() - 50,
width: $('body').width() - 50,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sOkButtonLabel", click: function() {
var oDashboard = $(':itop-dashboard').data('dashboard');
if (oDashboard.is_dirty())
{
if (!confirm('$sAutoApplyConfirmationMessage'))
{
return;
}
else
{
oDashboard.apply_changes();
}
}
window.bLeavingOnUserAction = true;
oDashboard.save();
} },
{ text: "$sCancelButtonLabel", click: function() {
var oDashboard = $(':itop-dashboard').data('dashboard');
if (oDashboard.is_modified())
{
if (!confirm('$sCancelConfirmationMessage'))
{
return;
}
}
window.bLeavingOnUserAction = true;
$(this).dialog( "close" );
$(this).remove();
} },
],
close: function() { $(this).remove(); }
});
$('#dashboard_editor .ui-layout-center').dashboard({
dashboard_id: '$sId', layout_class: '$sLayoutClass', title: '$sTitle',
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard'},
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard'},
new_dashlet_parameters: {operation: 'new_dashlet'}
});
$('#select_dashlet').droppable({
accept: '.dashlet',
drop: function(event, ui) {
$( this ).find( ".placeholder" ).remove();
var oDashlet = ui.draggable;
oDashlet.remove();
},
});
$('#event_bus').bind('dashlet-selected', function(event, data){
var sDashletId = data.dashlet_id;
var sPropId = 'dashlet_properties_'+sDashletId;
$('.dashlet_properties').each(function() {
var sId = $(this).attr('id');
var bShow = (sId == sPropId);
if (bShow)
{
$(this).show();
}
else
{
$(this).hide();
}
});
});
dashboard_prop_size = GetUserPreference('dashboard_prop_size', 350);
$('#dashboard_editor').layout({
east: {
minSize: 200,
size: dashboard_prop_size,
togglerLength_open: 0,
togglerLength_closed: 0,
onresize_end: function(name, elt, state, options, layout)
{
if (state.isSliding == false)
{
SetUserPreference('dashboard_prop_size', state.size, true);
}
},
}
});
window.onbeforeunload = function() {
if (!window.bLeavingOnUserAction)
{
var oDashboard = $(':itop-dashboard').data('dashboard');
if (oDashboard)
{
if (oDashboard.is_dirty())
{
return '$sExitConfirmationMessage';
}
if (oDashboard.is_modified())
{
return '$sExitConfirmationMessage';
}
}
}
// return nothing ! safer for IE
};
EOF
);
$oPage->add_ready_script("");
}
public static function GetDashletCreationForm($sOQL = null)
{
$oForm = new DesignerForm();
// Get the list of all 'dashboard' menus in which we can insert a dashlet
$aAllMenus = ApplicationMenu::ReflectionMenuNodes();
$aAllowedDashboards = array();
foreach($aAllMenus as $idx => $aMenu)
{
$oMenu = $aMenu['node'];
$sParentId = $aMenu['parent'];
if ($oMenu instanceof DashboardMenuNode)
{
$sMenuLabel = $oMenu->GetTitle();
$sParentLabel = Dict::S('Menu:'.$sParentId);
if ($sParentLabel != $sMenuLabel)
{
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
}
else
{
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
}
}
}
asort($aAllowedDashboards);
$aKeys = array_keys($aAllowedDashboards); // Select the first one by default
$sDefaultDashboard = $aKeys[0];
$oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard);
$oField->SetAllowedValues($aAllowedDashboards);
$oField->SetMandatory(true);
$oForm->AddField($oField);
// Get the list of possible dashlets that support a creation from
// an OQL
$aDashlets = array();
foreach(get_declared_classes() as $sDashletClass)
{
if (is_subclass_of($sDashletClass, 'Dashlet'))
{
$oReflection = new ReflectionClass($sDashletClass);
if (!$oReflection->isAbstract())
{
$aCallSpec = array($sDashletClass, 'CanCreateFromOQL');
$bShorcutMode = call_user_func($aCallSpec);
if ($bShorcutMode)
{
$aCallSpec = array($sDashletClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec);
$aDashlets[$sDashletClass] = array('label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']);
}
}
}
}
$oSelectorField = new DesignerFormSelectorField('dashlet_class', Dict::S('UI:DashletCreation:DashletType'), '');
$oForm->AddField($oSelectorField);
foreach($aDashlets as $sDashletClass => $aDashletInfo)
{
$oSubForm = new DesignerForm();
$oDashlet = new $sDashletClass(0);
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
$oSelectorField->AddSubForm($oSubForm, $aDashletInfo['label'], $aDashletInfo['class']);
}
$oField = new DesignerBooleanField('open_editor', Dict::S('UI:DashletCreation:EditNow'), true);
$oForm->AddField($oField);
return $oForm;
}
public static function GetDashletCreationDlgFromOQL($oPage, $sOQL)
{
$oPage->add('<div id="dashlet_creation_dlg">');
$oForm = self::GetDashletCreationForm($sOQL);
$oForm->Render($oPage);
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:DashletCreation:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$oPage->add_ready_script(
<<<EOF
$('#dashlet_creation_dlg').dialog({
width: 400,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sOkButtonLabel", click: function() {
var oForm = $(this).find('form');
var sFormId = oForm.attr('id');
var oParams = null;
var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0)
{
oParams = ReadFormParams(sFormId);
}
oParams.operation = 'add_dashlet';
var me = $(this);
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
me.dialog( "close" );
me.remove();
$('body').append(data);
});
} },
{ text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove();
} },
],
close: function() { $(this).remove(); }
});
EOF
);
}
}

View File

@@ -1,185 +0,0 @@
<?php
abstract class DashboardLayout
{
public function __construct()
{
}
abstract public function Render($oPage, $aDashlets, $bEditMode = false);
static public function GetInfo()
{
return array(
'label' => '',
'icon' => '',
'description' => '',
);
}
}
abstract class DashboardLayoutMultiCol extends DashboardLayout
{
protected $iNbCols;
public function __construct()
{
$this->iNbCols = 1;
}
protected function TrimCell($aDashlets)
{
$aKeys = array_reverse(array_keys($aDashlets));
$idx = 0;
$bNoVisibleFound = true;
while($idx < count($aKeys) && $bNoVisibleFound)
{
$oDashlet = $aDashlets[$aKeys[$idx]];
if ($oDashlet->IsVisible())
{
$bNoVisibleFound = false;
}
else
{
unset($aDashlets[$aKeys[$idx]]);
}
$idx++;
}
return $aDashlets;
}
protected function TrimCellsArray($aCells)
{
foreach($aCells as $key => $aDashlets)
{
$aCells[$key] = $this->TrimCell($aDashlets);
}
$aKeys = array_reverse(array_keys($aCells));
$idx = 0;
$bNoVisibleFound = true;
while($idx < count($aKeys) && $bNoVisibleFound)
{
$aDashlets = $aCells[$aKeys[$idx]];
if (count($aDashlets) > 0)
{
$bNoVisibleFound = false;
}
else
{
unset($aCells[$aKeys[$idx]]);
}
$idx++;
}
return $aCells;
}
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = array())
{
// Trim the list of cells to remove the invisible/empty ones at the end of the array
$aCells = $this->TrimCellsArray($aCells);
$oPage->add('<table style="width:100%"><tbody>');
$iCellIdx = 0;
$fColSize = 100 / $this->iNbCols;
$sStyle = $bEditMode ? 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode"' : 'style="width: '.$fColSize.'%;" class="dashboard"';
$iNbRows = ceil(count($aCells) / $this->iNbCols);
for($iRows = 0; $iRows < $iNbRows; $iRows++)
{
$oPage->add('<tr>');
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
{
$oPage->add("<td $sStyle>");
if (array_key_exists($iCellIdx, $aCells))
{
$aDashlets = $aCells[$iCellIdx];
if (count($aDashlets) > 0)
{
foreach($aDashlets as $oDashlet)
{
if ($oDashlet->IsVisible())
{
$oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams);
}
}
}
else
{
$oPage->add('&nbsp;');
}
}
else
{
$oPage->add('&nbsp;');
}
$oPage->add('</td>');
$iCellIdx++;
}
$oPage->add('</tr>');
}
if ($bEditMode) // Add one row for extensibility
{
$sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension"';
$oPage->add('<tr>');
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
{
$oPage->add("<td $sStyle>");
$oPage->add('&nbsp;');
$oPage->add('</td>');
}
$oPage->add('</tr>');
}
$oPage->add('</tbody></table>');
}
}
class DashboardLayoutOneCol extends DashboardLayoutMultiCol
{
public function __construct()
{
parent::__construct();
$this->iNbCols = 1;
}
static public function GetInfo()
{
return array(
'label' => 'One Column',
'icon' => 'images/layout_1col.png',
'description' => '',
);
}
}
class DashboardLayoutTwoCols extends DashboardLayoutMultiCol
{
public function __construct()
{
parent::__construct();
$this->iNbCols = 2;
}
static public function GetInfo()
{
return array(
'label' => 'Two Columns',
'icon' => 'images/layout_2col.png',
'description' => '',
);
}
}
class DashboardLayoutThreeCols extends DashboardLayoutMultiCol
{
public function __construct()
{
parent::__construct();
$this->iNbCols = 3;
}
static public function GetInfo()
{
return array(
'label' => 'Two Columns',
'icon' => 'images/layout_3col.png',
'description' => '',
);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,833 +0,0 @@
<?php
// Copyright (C) 2012 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Data Table to display a set of objects in a tabular manner in HTML
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html GPL
*/
class DataTable
{
protected $iListId; // Unique ID inside the web page
protected $sTableId; // identifier for saving the settings (combined with the class aliases)
protected $oSet; // The set of objects to display
protected $aClassAliases; // The aliases (alias => class) inside the set
protected $iNbObjects; // Total number of objects inthe set
protected $bUseCustomSettings; // Whether or not the current display uses custom settings
protected $oDefaultSettings; // the default settings for displaying such a list
/**
* @param $iListId mixed Unique ID for this div/table in the page
* @param $oSet DBObjectSet The set of data to display
* @param $aClassAliases Hash The list of classes/aliases to be displayed in this set $sAlias => $sClassName
* @param $sTableId mixed A string (or null) identifying this table in order to persist its settings
*/
public function __construct($iListId, $oSet, $aClassAliases, $sTableId = null)
{
$this->iListId = $iListId;
$this->oSet = $oSet;
$this->aClassAliases = $aClassAliases;
$this->sTableId = $sTableId;
$this->iNbObjects = $oSet->Count();
$this->bUseCustomSettings = false;
$this->oDefaultSettings = null;
}
public function Display(WebPage $oPage, DataTableSettings $oSettings, $bActionsMenu, $sSelectMode, $bViewLink, $aExtraParams)
{
$this->oDefaultSettings = $oSettings;
// Identified tables can have their own specific settings
$oCustomSettings = DataTableSettings::GetTableSettings($this->aClassAliases, $this->sTableId);
if ($oCustomSettings != null)
{
// Custom settings overload the default ones
$this->bUseCustomSettings = true;
}
else
{
$oCustomSettings = $oSettings;
}
if ($oCustomSettings->iDefaultPageSize > 0)
{
$this->oSet->SetLimit($oCustomSettings->iDefaultPageSize);
}
$this->oSet->SetOrderBy($oCustomSettings->GetSortOrder());
$bToolkitMenu = true;
if (UserRights::IsPortalUser())
{
// Portal users have a limited access to data, for now they can only see what's configured for them
$bToolkitMenu = false;
}
return $this->GetAsHTML($oPage, $oCustomSettings->iDefaultPageSize, $oCustomSettings->iDefaultPageSize, 0, $oCustomSettings->aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams);
}
public function GetAsHTML(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex, $aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams)
{
$sObjectsCount = $this->GetObjectCount($oPage, $sSelectMode);
$sPager = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
$sActionsMenu = '';
$sToolkitMenu = '';
if ($bActionsMenu)
{
$sActionsMenu = $this->GetActionsMenu($oPage, $aExtraParams);
}
if ($bToolkitMenu)
{
$sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
}
$sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize);
$sHtml = "<table id=\"datatable_{$this->iListId}\" class=\"datatable\">";
$sHtml .= "<tr><td>";
$sHtml .= "<table style=\"width:100%;\">";
$sHtml .= "<tr><td class=\"pagination_container\">$sObjectsCount</td><td class=\"menucontainer\">$sToolkitMenu $sActionsMenu</td></tr>";
$sHtml .= "<tr>$sPager</tr>";
$sHtml .= "</table>";
$sHtml .= "</td></tr>";
$sHtml .= "<tr><td class=\"datacontents\">$sDataTable</td></tr>";
$sHtml .= "</table>\n";
$oPage->add_at_the_end($sConfigDlg);
$aOptions = array(
'sPersistentId' => '',
'sFilter' => $this->oSet->GetFilter()->serialize(),
'oColumns' => $aColumns,
'sSelectMode' => $sSelectMode,
'sViewLink' => ($bViewLink ? 'true' : 'false'),
'iNbObjects' => $this->iNbObjects,
'iDefaultPageSize' => $iDefaultPageSize,
'iPageSize' => $iPageSize,
'iPageIndex' => $iPageIndex,
'oClassAliases' => $this->aClassAliases,
'sTableId' => $this->sTableId,
'oExtraParams' => $aExtraParams,
'sRenderUrl' => utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php',
'oRenderParameters' => array('str' => ''), // Forces JSON to encode this as a object...
'oDefaultSettings' => array('str' => ''), // Forces JSON to encode this as a object...
'oLabels' => array('moveup' => Dict::S('UI:Button:MoveUp'), 'movedown' => Dict::S('UI:Button:MoveDown')),
);
if($this->oDefaultSettings != null)
{
$aOptions['oDefaultSettings'] = $this->GetAsHash($this->oDefaultSettings);
}
$sJSOptions = json_encode($aOptions);
$oPage->add_ready_script("$('#datatable_{$this->iListId}').datatable($sJSOptions);");
return $sHtml;
}
/**
* When refreshing the body of a paginated table, get the rows of the table (inside the TBODY)
* return string The HTML rows to insert inside the <tbody> node
*/
public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams)
{
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sHtml = '';
foreach($aValues as $aRow)
{
$sHtml .= $oPage->GetTableRow($aRow, $aAttribs);
}
return $sHtml;
}
protected function GetObjectCount(WebPage $oPage, $sSelectMode)
{
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
{
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderSelection', '<span id="total">'.$this->iNbObjects.'</span>', '<span class="selectedCount">0</span>').'</div>';
}
else
{
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderNoSelection', '<span id="total">'.$this->iNbObjects.'</span>').'</div>';
}
return $sHtml;
}
protected function GetPager(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex)
{
$sHtml = '';
if ($iPageSize < 1) // Display all
{
$sPagerStyle = 'style="display:none"'; // no limit: display the full table, so hide the "pager" UI
}
else
{
$sPagerStyle = '';
}
$sCombo = '<select class="pagesize">';
for($iPage = 1; $iPage < 5; $iPage++)
{
$iNbItems = $iPage * $iDefaultPageSize;
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
}
$sSelected = ($iPageSize < 1) ? 'selected="selected"' : '';
$sCombo .= "<option $sSelected value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
$sCombo .= '</select>';
$sPages = Dict::S('UI:Pagination:PagesLabel');
$sPageSizeCombo = Dict::Format('UI:Pagination:PageSize', $sCombo);
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
if ($iNbPages == 1)
{
// No need to display the pager
$sPagerStyle = 'style="display:none"';
}
$aPagesToDisplay = array();
for($idx = 0; $idx <= min(4, $iNbPages-1); $idx++)
{
if ($idx == 0)
{
$aPagesToDisplay[$idx] = '<span page="0" class="curr_page">1</span>';
}
else
{
$aPagesToDisplay[$idx] = "<span id=\"gotopage_$idx\" class=\"gotopage\" page=\"$idx\">".(1+$idx)."</span>";
}
}
$iLastPageIdx = $iNbPages - 1;
if (!isset($aPagesToDisplay[$iLastPageIdx]))
{
unset($aPagesToDisplay[$idx - 1]); // remove the last page added to make room for the very last page
$aPagesToDisplay[$iLastPageIdx] = "<span id=\"gotopage_$iLastPageIdx\" class=\"gotopage\" page=\"$iLastPageIdx\">... $iNbPages</span>";
}
$sPagesLinks = implode('', $aPagesToDisplay);
$sPagesList = '['.implode(',', array_keys($aPagesToDisplay)).']';
$sSelectionMode = ($iNbPages == 1) ? '' : 'positive';
$sHtml =
<<<EOF
<td $sPagerStyle colspan="2">
<table id="pager{$this->iListId}" class="pager"><tr>
<td>$sPages</td>
<td><img src="../images/first.png" class="first"/></td>
<td><img src="../images/prev.png" class="prev"/></td>
<td><span id="index">$sPagesLinks</span></td>
<td><img src="../images/next.png" class="next"/></td>
<td><img src="../images/last.png" class="last"/></td>
<td>$sPageSizeCombo</td>
<td><span id="loading">&nbsp;</span><input type="hidden" name="selectionMode" value="$sSelectionMode"></input>
</td>
</tr>
</table>
</td>
EOF;
return $sHtml;
}
protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
{
$oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list');
$sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
return $sHtml;
}
protected function GetToolkitMenu(WebPage $oPage, $aExtraParams)
{
$sMenuTitle = Dict::S('UI:ConfigureThisList');
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li><img src="../images/toolkit_menu.png"><ul>';
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');");
$aActions = array(
$oMenuItem1->GetUID() => $oMenuItem1->GetMenuItem(),
);
$this->oSet->Rewind();
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $this->oSet, $aActions);
$this->oSet->Rewind();
$sHtml .= $oPage->RenderPopupMenuItems($aActions);
return $sHtml;
}
protected function GetTableConfigDlg(WebPage $oPage, $aColumns, $bViewLink, $iDefaultPageSize)
{
$sHtml = "<div id=\"datatable_dlg_{$this->iListId}\" style=\"display: none;\">";
$sHtml .= "<form onsubmit=\"return false\">";
$sChecked = ($this->bUseCustomSettings) ? '' : 'checked';
$sHtml .= "<p><input id=\"dtbl_dlg_settings_{$this->iListId}\" type=\"radio\" name=\"settings\" $sChecked value=\"defaults\"><label for=\"dtbl_dlg_settings_{$this->iListId}\">&nbsp;".Dict::S('UI:UseDefaultSettings').'</label></p>';
$sHtml .= "<fieldset>";
$sChecked = ($this->bUseCustomSettings) ? 'checked': '';
$sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_specific_{$this->iListId}\" type=\"radio\" class=\"specific_settings\" name=\"settings\" $sChecked value=\"specific\"><label for=\"dtbl_dlg_specific_{$this->iListId}\">&nbsp;".Dict::S('UI:UseSpecificSettings')."</label></legend>";
$sHtml .= Dict::S('UI:ColumnsAndSortOrder').'<br/><ul class="sortable_field_list" id="sfl_'.$this->iListId.'"></ul>';
$sHtml .= '<p>'.Dict::Format('UI:Display_X_ItemsPerPage', '<input type="text" size="4" name="page_size" value="'.$iDefaultPageSize.'">').'</p>';
$sHtml .= "</fieldset>";
$sHtml .= "<fieldset>";
$sSaveChecked = ($this->sTableId != null) ? 'checked' : '';
$sCustomDisabled = ($this->sTableId == null) ? 'disabled="disabled" stay-disabled="true" ' : '';
$sCustomChecked = ($this->sTableId != null) ? 'checked' : '';
$sGenericChecked = ($this->sTableId == null) ? 'checked' : '';
$sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_save_{$this->iListId}\" type=\"checkbox\" $sSaveChecked name=\"save_settings\"><label for=\"dtbl_dlg_save_{$this->iListId}\">&nbsp;".Dict::S('UI:UseSavetheSettings')."</label></legend>";
$sHtml .= "<p><input id=\"dtbl_dlg_this_list_{$this->iListId}\" type=\"radio\" name=\"scope\" $sCustomChecked $sCustomDisabled value=\"this_list\"><label for=\"dtbl_dlg_this_list_{$this->iListId}\">&nbsp;".Dict::S('UI:OnlyForThisList').'</label>&nbsp;&nbsp;&nbsp;&nbsp;';
$sHtml .= "<input id=\"dtbl_dlg_all_{$this->iListId}\" type=\"radio\" name=\"scope\" $sGenericChecked value=\"defaults\"><label for=\"dtbl_dlg_all_{$this->iListId}\">&nbsp;".Dict::S('UI:ForAllLists').'</label></p>';
$sHtml .= "</fieldset>";
$sHtml .= '<table style="width:100%"><tr><td style="text-align:center;">';
$sHtml .= '<button type="button" onclick="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgCancel\'); $(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\')">'.Dict::S('UI:Button:Cancel').'</button>';
$sHtml .= '</td><td style="text-align:center;">';
$sHtml .= '<button type="submit" onclick="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgOk\');$(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\');">'.Dict::S('UI:Button:Ok').'</button>';
$sHtml .= '</td></tr></table>';
$sHtml .= "</form>";
$sHtml .= "</div>";
$sDlgTitle = addslashes(Dict::S('UI:ListConfigurationTitle'));
$oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#datatable_{$this->iListId}').datatable('onDlgCancel'); } });");
return $sHtml;
}
public function GetAsHash($oSetting)
{
$aSettings = array('iDefaultPageSize' => $oSetting->iDefaultPageSize, 'oColumns' => $oSetting->aColumns);
return $aSettings;
}
protected function GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink)
{
$aAttribs = array();
if ($sSelectMode == 'multiple')
{
$aAttribs['form::select'] = array('label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->iListId}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>", 'description' => Dict::S('UI:SelectAllToggle+'));
}
else if ($sSelectMode == 'single')
{
$aAttribs['form::select'] = array('label' => "", 'description' => '');
}
foreach($this->aClassAliases as $sAlias => $sClassName)
{
foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
if ($sAttCode == '_key_')
{
$aAttribs['key_'.$sAlias] = array('label' => MetaModel::GetName($sClassName), 'description' => '');
}
else
{
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
$aAttribs[$sAttCode.'_'.$sAlias] = array('label' => MetaModel::GetLabel($sClassName, $sAttCode), 'description' => $oAttDef->GetOrderByHint());
}
}
}
}
return $aAttribs;
}
protected function GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{
$aValues = array();
$this->oSet->Seek(0);
$iMaxObjects = $iPageSize;
while (($aObjects = $this->oSet->FetchAssoc()) && ($iMaxObjects != 0))
{
$bFirstObject = true;
$aRow = array();
foreach($this->aClassAliases as $sAlias => $sClassName)
{
$sHilightClass = $aObjects[$sAlias]->GetHilightClass();
if ($sHilightClass != '')
{
$aRow['@class'] = $sHilightClass;
}
if ((($sSelectMode == 'single') || ($sSelectMode == 'multiple')) && $bFirstObject)
{
if (array_key_exists('selection_enabled', $aExtraParams) && isset($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]))
{
$sDisabled = ($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]) ? '' : ' disabled="disabled"';
}
else
{
$sDisabled = '';
}
if ($sSelectMode == 'single')
{
$aRow['form::select'] = "<input type=\"radio\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
}
else
{
$aRow['form::select'] = "<input type=\"checkBox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
}
}
foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
if ($sAttCode == '_key_')
{
$aRow['key_'.$sAlias] = $aObjects[$sAlias]->GetHyperLink();
}
else
{
$aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode);
}
}
}
$bFirstObject = false;
}
$aValues[] = $aRow;
$iMaxObjects--;
}
return $aValues;
}
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
if ($iPageSize < 1)
{
$iPageSize = -1; // convention: no pagination
}
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sHtml = '<table class="listContainer">';
foreach($this->oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
{
$aExtraParams['query_params'][$sName] = $sValue;
}
$sHtml .= "<tr><td>";
$sHtml .= $oPage->GetTable($aAttribs, $aValues);
$sHtml .= '</td></tr>';
$sHtml .= '</table>';
$iCount = $this->iNbObjects;
$aArgs = $this->oSet->GetArgs();
$sExtraParams = addslashes(str_replace('"', "'", json_encode(array_merge($aExtraParams, $aArgs)))); // JSON encode, change the style of the quotes and escape them
$sSelectModeJS = '';
$sHeaders = '';
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
{
$sSelectModeJS = $sSelectMode;
$sHeaders = 'headers: { 0: {sorter: false}},';
}
$sDisplayKey = ($bViewLink) ? 'true' : 'false';
// Protect against duplicate elements in the Zlist
$aUniqueOrderedList = array();
foreach($this->aClassAliases as $sAlias => $sClassName)
{
foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
$aUniqueOrderedList[$sAttCode] = true;
}
}
}
$aUniqueOrderedList = array_keys($aUniqueOrderedList);
$sJSColumns = json_encode($aColumns);
$sJSClassAliases = json_encode($this->aClassAliases);
$sCssCount = isset($aExtraParams['cssCount']) ? ", cssCount: '{$aExtraParams['cssCount']}'" : '';
$this->oSet->ApplyParameters();
// Display the actual sort order of the table
$aRealSortOrder = $this->oSet->GetRealSortOrder();
$aDefaultSort = array();
$iColOffset = 0;
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
{
$iColOffset += 1;
}
if ($bViewLink)
{
// $iColOffset += 1;
}
foreach($aRealSortOrder as $sColCode => $bAscending)
{
$iPos = array_search($sColCode, $aUniqueOrderedList);
if ($iPos !== false)
{
$aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
}
else if (($iPos = array_search(preg_replace('/_friendlyname$/', '', $sColCode), $aUniqueOrderedList)) !== false)
{
// if sorted on the friendly name of an external key, then consider it sorted on the column that shows the links
$aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
}
else if($sColCode == 'friendlyname' && $bViewLink)
{
$aDefaultSort[] = "[".($iColOffset).",".($bAscending ? '0' : '1')."]";
}
}
$sSortList = '';
if (count($aDefaultSort) > 0)
{
$sSortList = ', sortList: ['.implode(',', $aDefaultSort).']';
}
$sOQL = addslashes($this->oSet->GetFilter()->serialize());
$oPage->add_ready_script(
<<<EOF
var oTable = $('#{$this->iListId} table.listResults');
oTable.tablesorter( { $sHeaders widgets: ['myZebra', 'truncatedList'] $sSortList} ).tablesorterPager({container: $('#pager{$this->iListId}'), totalRows:$iCount, size: $iPageSize, filter: '$sOQL', extra_params: '$sExtraParams', select_mode: '$sSelectModeJS', displayKey: $sDisplayKey, columns: $sJSColumns, class_aliases: $sJSClassAliases $sCssCount});
EOF
);
//if ($iNbPages == 1)
if (false)
{
if (isset($aExtraParams['cssCount']))
{
$sCssCount = $aExtraParams['cssCount'];
if ($sSelectMode == 'single')
{
$sSelectSelector = ":radio[name^=selectObj]";
}
else if ($sSelectMode == 'multiple')
{
$sSelectSelector = ":checkbox[name^=selectObj]";
}
$oPage->add_ready_script(
<<<EOF
$('#{$this->iListId} table.listResults $sSelectSelector').change(function() {
var c = $('{$sCssCount}');
var v = $('#{$this->iListId} table.listResults $sSelectSelector:checked').length;
c.val(v);
$('#{$this->iListId} .selectedCount').text(v);
c.trigger('change');
});
EOF
);
}
}
return $sHtml;
}
public function UpdatePager(WebPage $oPage, $iDefaultPageSize, $iStart)
{
$iPageSize = ($iDefaultPageSize < 1) ? 1 : $iDefaultPageSize;
$iPageIndex = 1 + floor($iStart / $iPageSize);
$sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".str_replace("\n", ' ', addslashes($sHtml))."');");
if ($iDefaultPageSize < 1)
{
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().hide()");
}
else
{
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().show()");
}
}
}
class DataTableSettings implements Serializable
{
public $aClassAliases;
public $sTableId;
public $iDefaultPageSize;
public $aColumns;
public function __construct($aClassAliases, $sTableId = null)
{
$this->aClassAliases = $aClassAliases;
$this->sTableId = $sTableId;
$this->iDefaultPageSize = 10;
$this->aColumns = array();
}
protected function Init($iDefaultPageSize, $aSortOrder, $aColumns)
{
$this->iDefaultPageSize = $iDefaultPageSize;
$this->aColumns = $aColumns;
$this->FixVisibleColumns();
}
public function serialize()
{
// Save only the 'visible' columns
$aColumns = array();
foreach($this->aClassAliases as $sAlias => $sClass)
{
$aColumns[$sAlias] = array();
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
unset($aData['label']); // Don't save the display name
unset($aData['alias']); // Don't save the alias (redundant)
unset($aData['code']); // Don't save the code (redundant)
if ($aData['checked'])
{
$aColumns[$sAlias][$sAttCode] = $aData;
}
}
}
return serialize(
array(
'iDefaultPageSize' => $this->iDefaultPageSize,
'aColumns' => $aColumns,
)
);
}
public function unserialize($sData)
{
$aData = unserialize($sData);
$this->iDefaultPageSize = $aData['iDefaultPageSize'];
$this->aColumns = $aData['aColumns'];
foreach($this->aClassAliases as $sAlias => $sClass)
{
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
$aFieldData = false;
if ($sAttCode == '_key_')
{
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, null, true /* bChecked */, $aData['sort']);
}
else if (MetaModel::isValidAttCode($sClass, $sAttCode))
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $aData['sort']);
}
if ($aFieldData)
{
$this->aColumns[$sAlias][$sAttCode] = $aFieldData;
}
else
{
unset($this->aColumns[$sAlias][$sAttCode]);
}
}
}
$this->FixVisibleColumns();
}
static public function GetDataModelSettings($aClassAliases, $bViewLink, $aDefaultLists)
{
$oSettings = new DataTableSettings($aClassAliases);
// Retrieve the class specific settings for each class/alias based on the 'list' ZList
//TODO let the caller pass some other default settings (another Zlist, extre fields...)
$aColumns = array();
foreach($aClassAliases as $sAlias => $sClass)
{
if ($aDefaultLists == null)
{
$aList = cmdbAbstract::FlattenZList(MetaModel::GetZListItems($sClass, 'list'));
}
else
{
$aList = $aDefaultLists[$sAlias];
}
$aSortOrder = MetaModel::GetOrderByDefault($sClass);
if ($bViewLink)
{
$sSort = 'none';
if(array_key_exists('friendlyname', $aSortOrder))
{
$sSort = $aSortOrder['friendlyname'] ? 'asc' : 'desc';
}
$aColumns[$sAlias]['_key_'] = $oSettings->GetFieldData($sAlias, '_key_', null, true /* bChecked */, $sSort);
}
foreach($aList as $sAttCode)
{
$sSort = 'none';
if(array_key_exists($sAttCode, $aSortOrder))
{
$sSort = $aSortOrder[$sAttCode] ? 'asc' : 'desc';
}
$oAttDef = Metamodel::GetAttributeDef($sClass, $sAttCode);
$aFieldData = $oSettings->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $sSort);
if ($aFieldData) $aColumns[$sAlias][$sAttCode] = $aFieldData;
}
}
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
$oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns);
return $oSettings;
}
protected function FixVisibleColumns()
{
foreach($this->aClassAliases as $sAlias => $sClass)
{
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
// Remove non-existent columns
// TODO: check if the existing ones are still valid (in case their type changed)
if (($sAttCode != '_key_') && (!MetaModel::IsValidAttCode($sClass, $sAttCode)))
{
unset($this->aColumns[$sAlias][$sAttCode]);
}
}
$aList = MetaModel::ListAttributeDefs($sClass);
// Add the other (non visible ones), sorted in alphabetical order
$aTempData = array();
foreach($aList as $sAttCode => $oAttDef)
{
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!$oAttDef instanceof AttributeLinkSet))
{
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;
}
}
ksort($aTempData);
foreach($aTempData as $sLabel => $aFieldData)
{
$this->aColumns[$sAlias][$aFieldData['code']] = $aFieldData;
}
}
}
static public function GetTableSettings($aClassAliases, $sTableId = null)
{
$pref = null;
$oSettings = new DataTableSettings($aClassAliases, $sTableId);
if ($sTableId != null)
{
// An identified table, let's fetch its own settings (if any)
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey($sTableId), null);
}
if ($pref == null)
{
// Try the global preferred values for this class / set of classes
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey(null), null);
if ($pref == null)
{
// no such settings, use the default values provided by the data model
return null;
}
}
$oSettings->unserialize($pref);
return $oSettings;
}
public function GetSortOrder()
{
$aSortOrder = array();
foreach($this->aColumns as $sAlias => $aColumns)
{
foreach($aColumns as $aColumn)
{
if ($aColumn['sort'] != 'none')
{
$sCode = ($aColumn['code'] == '_key_') ? 'friendlyname' : $aColumn['code'];
$aSortOrder[$sCode] = ($aColumn['sort']=='asc'); // true for ascending, false for descending
}
}
break; // TODO: For now the Set object supports only sorting on the first class of the set
}
return $aSortOrder;
}
public function Save()
{
if ($this->sTableId == null) return false; // Cannot save, the table is not identified, use SaveAsDefault instead
$sSettings = $this->serialize();
appUserPreferences::SetPref($this->GetPrefsKey($this->sTableId), $sSettings);
return true;
}
public function SaveAsDefault()
{
$sSettings = $this->serialize();
appUserPreferences::SetPref($this->GetPrefsKey(null), $sSettings);
return true;
}
/**
* Clear the preferences for this particular table
* @param $bResetAll boolean If true,the settings for all tables of the same class(es)/alias(es) are reset
*/
public function ResetToDefault($bResetAll)
{
if (($this->sTableId == null) && (!$bResetAll)) return false; // Cannot reset, the table is not identified, use force $bResetAll instead
if ($bResetAll)
{
// Turn the key into a suitable PCRE pattern
$sKey = $this->GetPrefsKey(null);
$sPattern = str_replace(array('|'), array('\\|'), $sKey); // escape the | character
$sPattern = '#^'.str_replace(array('*'), array('.*'), $sPattern).'$#'; // Don't use slash as the delimiter since it's used in our key to delimit aliases
appUserPreferences::UnsetPref($sPattern, true);
}
else
{
appUserPreferences::UnsetPref($this->GetPrefsKey($this->sTableId), false);
}
return true;
}
protected function GetPrefsKey($sTableId = null)
{
if ($sTableId == null) $sTableId = '*';
$aKeys = array();
foreach($this->aClassAliases as $sAlias => $sClass)
{
$aKeys[] = $sAlias.'-'.$sClass;
}
return implode('/', $aKeys).'|'.$sTableId;
}
protected function GetFieldData($sAlias, $sAttCode, $oAttDef, $bChecked, $sSort)
{
$ret = false;
if ($sAttCode == '_key_')
{
$sLabel = Dict::Format('UI:ExtKey_AsLink', MetaModel::GetName($this->aClassAliases[$sAlias]));
$ret = array(
'label' => $sLabel,
'checked' => true,
'disabled' => true,
'alias' => $sAlias,
'code' => $sAttCode,
'sort' => $sSort,
);
}
else if (!$oAttDef->IsLinkSet())
{
$sLabel = $oAttDef->GetLabel();
if ($oAttDef->IsExternalKey())
{
$sLabel = Dict::Format('UI:ExtKey_AsLink', $oAttDef->GetLabel());
}
else if ($oAttDef->IsExternalField())
{
$oExtAttDef = $oAttDef->GetExtAttDef();
$sLabel = Dict::Format('UI:ExtField_AsRemoteField', $oAttDef->GetLabel(), $oExtAttDef->GetLabel());
}
elseif ($oAttDef instanceof AttributeFriendlyName)
{
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
}
$ret = array(
'label' => $sLabel,
'checked' => $bChecked,
'disabled' => false,
'alias' => $sAlias,
'code' => $sAttCode,
'sort' => $sSort,
);
}
return $ret;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -48,7 +48,7 @@ class iTopWizardWebPage extends iTopWebPage
$sStyle = ($iIndex == $this->m_iCurrentStep) ? 'wizActiveStep' : 'wizStep';
$aSteps[] = "<div class=\"$sStyle\"><span>$sStepTitle</span></div>";
}
$sWizardHeader = "<div class=\"wizHeader\"><h1>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</h1>\n".implode("<div class=\"wizSeparator\"><img align=\"bottom\" src=\"../images/wizArrow.gif\"></div>", $aSteps)."<br style=\"clear:both;\"/></div>\n";
$sWizardHeader = "<div class=\"wizHeader\"><h1>{$this->s_title}</h1>\n".implode("<div class=\"wizSeparator\"><img align=\"bottom\" src=\"../images/wizArrow.gif\"></div>", $aSteps)."<br style=\"clear:both;\"/></div>\n";
$this->s_content = "$sWizardHeader<div class=\"wizContainer\">".$this->s_content."</div>";
parent::output();
}

View File

@@ -27,11 +27,8 @@ require_once(APPROOT."/application/nicewebpage.class.inc.php");
/**
* Web page used for displaying the login form
*/
class LoginWebPage extends NiceWebPage
{
protected static $m_sLoginFailedMessage = '';
public function __construct()
{
parent::__construct("iTop Login");
@@ -91,21 +88,10 @@ EOF
);
}
public static function SetLoginFailedMessage($sMessage)
{
self::$m_sLoginFailedMessage = $sMessage;
}
public function DisplayLoginForm($sLoginType, $bFailedLogin = false)
{
switch($sLoginType)
{
case 'cas':
utils::InitCASClient();
// force CAS authentication
phpCAS::forceAuthentication(); // Will redirect the user and exit since the user is not yet authenticated
break;
case 'basic':
case 'url':
$this->add_header('WWW-Authenticate: Basic realm="'.Dict::Format('UI:iTopVersion:Short', ITOP_VERSION));
@@ -117,8 +103,8 @@ EOF
case 'external':
case 'form':
default: // In case the settings get messed up...
$sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data');
$sAuthPwd = utils::ReadParam('suggest_pwd', '', true, 'raw_data');
$sAuthUser = utils::ReadParam('auth_user', '');
$sAuthPwd = utils::ReadParam('suggest_pwd', '');
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION);
$this->add("<div id=\"login-logo\"><a href=\"http://www.combodo.com/itop\"><img title=\"$sVersionShort\" src=\"../images/itop-logo-external.png\"></a></div>\n");
@@ -126,14 +112,7 @@ EOF
$this->add("<h1>".Dict::S('UI:Login:Welcome')."</h1>\n");
if ($bFailedLogin)
{
if (self::$m_sLoginFailedMessage != '')
{
$this->add("<p class=\"hilite\">".self::$m_sLoginFailedMessage."</p>\n");
}
else
{
$this->add("<p class=\"hilite\">".Dict::S('UI:Login:IncorrectLoginPassword')."</p>\n");
}
$this->add("<p class=\"hilite\">".Dict::S('UI:Login:IncorrectLoginPassword')."</p>\n");
}
else
{
@@ -141,13 +120,12 @@ EOF
}
$this->add("<form method=\"post\">\n");
$this->add("<table width=\"100%\">\n");
$this->add("<tr><td style=\"text-align:right\"><label for=\"user\">".Dict::S('UI:Login:UserNamePrompt').":</label></td><td style=\"text-align:left\"><input id=\"user\" type=\"text\" name=\"auth_user\" value=\"".htmlentities($sAuthUser, ENT_QUOTES, 'UTF-8')."\" /></td></tr>\n");
$this->add("<tr><td style=\"text-align:right\"><label for=\"pwd\">".Dict::S('UI:Login:PasswordPrompt').":</label></td><td style=\"text-align:left\"><input id=\"pwd\" type=\"password\" name=\"auth_pwd\" value=\"".htmlentities($sAuthPwd, ENT_QUOTES, 'UTF-8')."\" /></td></tr>\n");
$this->add("<tr><td style=\"text-align:right\"><label for=\"user\">".Dict::S('UI:Login:UserNamePrompt').":</label></td><td style=\"text-align:left\"><input id=\"user\" type=\"text\" name=\"auth_user\" value=\"$sAuthUser\" /></td></tr>\n");
$this->add("<tr><td style=\"text-align:right\"><label for=\"pwd\">".Dict::S('UI:Login:PasswordPrompt').":</label></td><td style=\"text-align:left\"><input id=\"pwd\" type=\"password\" name=\"auth_pwd\" value=\"$sAuthPwd\" /></td></tr>\n");
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"> <input type=\"submit\" value=\"".Dict::S('UI:Button:Login')."\" /></td></tr>\n");
$this->add("</table>\n");
$this->add("<input type=\"hidden\" name=\"loginop\" value=\"login\" />\n");
$this->add("</form>\n");
$this->add(Dict::S('UI:Login:About'));
$this->add("</div>\n");
break;
}
@@ -155,7 +133,8 @@ EOF
public function DisplayChangePwdForm($bFailedLogin = false)
{
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
$sAuthUser = utils::ReadParam('auth_user', '');
$sAuthPwd = utils::ReadParam('suggest_pwd', '');
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION);
$sInconsistenPwdMsg = Dict::S('UI:Login:RetypePwdDoesNotMatch');
@@ -206,10 +185,15 @@ EOF
$sPreviousLoginMode = '';
}
// Unset all of the session variables.
unset($_SESSION['auth_user']);
unset($_SESSION['login_mode']);
$_SESSION = array();
// If it's desired to kill the session, also delete the session cookie.
// Note: This will destroy the session, and not just the session data!
if (isset($_COOKIE[session_name()]))
{
setcookie(session_name(), '', time()-3600, '/');
}
// Finally, destroy the session.
session_destroy();
}
static function SecureConnectionRequired()
@@ -232,8 +216,10 @@ EOF
{
if (self::SecureConnectionRequired() && !self::IsConnectionSecure())
{
// Non secured URL... request for a secure connection
throw new Exception('Secure connection required!');
// Non secured URL... redirect to a secured one
$sUrl = Utils::GetAbsoluteUrl(true /* query string */, true /* force HTTPS */);
header("Location: $sUrl");
exit;
}
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
@@ -255,22 +241,10 @@ EOF
$sLoginType = $aAllowedLoginTypes[$index];
switch($sLoginType)
{
case 'cas':
utils::InitCASClient();
// check CAS authentication
if (phpCAS::isAuthenticated())
{
$sAuthUser = phpCAS::getUser();
$sAuthPwd = '';
$sLoginMode = 'cas';
$sAuthentication = 'external';
}
break;
case 'form':
// iTop standard mode: form based authentication
$sAuthUser = utils::ReadPostedParam('auth_user', '', false, 'raw_data');
$sAuthPwd = utils::ReadPostedParam('auth_pwd', '', false, 'raw_data');
$sAuthUser = utils::ReadPostedParam('auth_user', '');
$sAuthPwd = utils::ReadPostedParam('auth_pwd', '');
if ($sAuthUser != '')
{
$sLoginMode = 'form';
@@ -296,10 +270,12 @@ EOF
case 'external':
// Web server supplied authentication
$bExternalAuth = false;
$sExtAuthVar = MetaModel::GetConfig()->GetExternalAuthenticationVariable(); // In which variable is the info passed ?
eval('$sAuthUser = isset('.$sExtAuthVar.') ? '.$sExtAuthVar.' : false;'); // Retrieve the value
if ($sAuthUser && (strlen($sAuthUser) > 0))
{
$sExtAuthVar = MetaModel::GetConfig()->GetExternalAuthenticationVariable(); // In which variable is the info passed ?
$sEval = '$bExternalAuth = isset('.$sExtAuthVar.');';
eval($sEval);
if ($bExternalAuth)
{
eval('$sAuthUser = '.$sExtAuthVar.';'); // Retrieve the value
$sAuthPwd = ''; // No password in this case the web server already authentified the user...
$sLoginMode = 'external';
$sAuthentication = 'external';
@@ -308,10 +284,10 @@ EOF
case 'url':
// Credentials passed directly in the url
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data');
if (($sAuthUser != '') && ($sAuthPwd != null))
$sAuthUser = utils::ReadParam('auth_user', '');
if ($sAuthUser != '')
{
$sAuthPwd = utils::ReadParam('auth_pwd', '');
$sLoginMode = 'url';
}
break;
@@ -338,9 +314,8 @@ EOF
}
else
{
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $sLoginMode, $sAuthentication))
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $sAuthentication))
{
//echo "Check Credentials returned false for user $sAuthUser!";
self::ResetSession();
$oPage = new LoginWebPage();
$oPage->DisplayLoginForm( $sLoginMode, true /* failed attempt */);
@@ -351,16 +326,6 @@ EOF
{
// User is Ok, let's save it in the session and proceed with normal login
UserRights::Login($sAuthUser, $sAuthentication); // Login & set the user's language
if (MetaModel::GetConfig()->Get('log_usage'))
{
$oLog = new EventLoginUsage();
$oLog->Set('userinfo', UserRights::GetUser());
$oLog->Set('user_id', UserRights::GetUserObject()->GetKey());
$oLog->Set('message', 'Successful login');
$oLog->DBInsertNoReload();
}
$_SESSION['auth_user'] = $sAuthUser;
$_SESSION['login_mode'] = $sLoginMode;
}
@@ -377,8 +342,9 @@ EOF
*/
static function DoLogin($bMustBeAdmin = false, $bIsAllowedToPortalUsers = false)
{
$sMessage = ''; // In case we need to return a message to the calling web page
$operation = utils::ReadParam('loginop', '');
session_name(MetaModel::GetConfig()->Get('session_name'));
session_start();
if ($operation == 'logoff')
{
@@ -417,15 +383,14 @@ EOF
{
$sAuthUser = $_SESSION['auth_user'];
UserRights::Login($sAuthUser); // Set the user's language
$sOldPwd = utils::ReadPostedParam('old_pwd', '', false, 'raw_data');
$sNewPwd = utils::ReadPostedParam('new_pwd', '', false, 'raw_data');
$sOldPwd = utils::ReadPostedParam('old_pwd');
$sNewPwd = utils::ReadPostedParam('new_pwd');
if (UserRights::CanChangePassword() && ((!UserRights::CheckCredentials($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd))))
{
$oPage = new LoginWebPage();
$oPage->DisplayChangePwdForm(true); // old pwd was wrong
$oPage->output();
}
$sMessage = Dict::S('UI:Login:PasswordChanged');
}
self::Login();
@@ -433,18 +398,18 @@ EOF
if ($bMustBeAdmin && !UserRights::IsAdministrator())
{
require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new SetupPage(Dict::S('UI:PageTitle:FatalError'));
$oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:Login:Error:AccessAdmin')."</h1>\n");
$oP->p("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a>");
$oP->p("<a href=\"../pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a>");
$oP->output();
exit;
}
elseif ( (!$bIsAllowedToPortalUsers) && (UserRights::IsPortalUser()))
{
// No rights to be here, redirect to the portal
header('Location: '.utils::GetAbsoluteUrlAppRoot().'portal/index.php');
header('Location: ../portal/index.php');
}
return $sMessage;
}
}
} // End of class
?>

View File

@@ -25,7 +25,6 @@
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/application/template.class.inc.php');
require_once(APPROOT."/application/user.dashboard.class.inc.php");
/**
@@ -60,106 +59,42 @@ require_once(APPROOT."/application/user.dashboard.class.inc.php");
class ApplicationMenu
{
static $bAdditionalMenusLoaded = false;
static $aRootMenus = array();
static $aMenusIndex = array();
static $sFavoriteSiloQuery = 'SELECT Organization';
static public function LoadAdditionalMenus()
{
if (!self::$bAdditionalMenusLoaded)
{
// Build menus from module handlers
//
foreach(get_declared_classes() as $sPHPClass)
{
if (is_subclass_of($sPHPClass, 'ModuleHandlerAPI'))
{
$aCallSpec = array($sPHPClass, 'OnMenuCreation');
call_user_func($aCallSpec);
}
}
self::$bAdditionalMenusLoaded = true;
}
}
/**
* Set the query used to limit the list of displayed organizations in the drop-down menu
* @param $sOQL string The OQL query returning a list of Organization objects
* @return none
*/
static public function SetFavoriteSiloQuery($sOQL)
{
self::$sFavoriteSiloQuery = $sOQL;
}
/**
* Get the query used to limit the list of displayed organizations in the drop-down menu
* @return string The OQL query returning a list of Organization objects
*/
static public function GetFavoriteSiloQuery()
{
return self::$sFavoriteSiloQuery;
}
/**
* Main function to add a menu entry into the application, can be called during the definition
* of the data model objects
*/
static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex = -1, $fRank)
{
$index = self::GetMenuIndexById($oMenuNode->GetMenuId());
if ($index == -1)
{
// The menu does not already exist, insert it
$index = count(self::$aMenusIndex);
self::$aMenusIndex[$index] = array( 'node' => $oMenuNode, 'children' => array());
if ($iParentIndex == -1)
{
$sParentId = '';
self::$aRootMenus[] = array ('rank' => $fRank, 'index' => $index);
}
else
{
$sParentId = self::$aMenusIndex[$iParentIndex]['node']->GetMenuId();
self::$aMenusIndex[$iParentIndex]['children'][] = array ('rank' => $fRank, 'index' => $index);
}
// Note: At the time when 'parent', 'rank' and 'source_file' have been added for the reflection API,
// they were not used to display the menus (redundant or unused)
//
$aBacktrace = debug_backtrace();
$sFile = $aBacktrace[2]["file"];
self::$aMenusIndex[$index] = array('node' => $oMenuNode, 'children' => array(), 'parent' => $sParentId, 'rank' => $fRank, 'source_file' => $sFile);
}
else
{
// the menu already exists, let's combine the conditions that make it visible
self::$aMenusIndex[$index]['node']->AddCondition($oMenuNode);
}
return $index;
}
/**
* Reflection API - Get menu entries
*/
static public function ReflectionMenuNodes()
{
self::LoadAdditionalMenus();
return self::$aMenusIndex;
}
/**
* Entry point to display the whole menu into the web page, used by iTopWebPage
*/
static public function DisplayMenu(iTopWebPage $oPage, $aExtraParams)
{
self::LoadAdditionalMenus();
// Sort the root menu based on the rank
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
$iAccordion = 0;
$iActiveMenu = self::GetMenuIndexById(self::GetActiveNodeId());
$iActiveMenu = ApplicationMenu::GetActiveNodeId();
foreach(self::$aRootMenus as $aMenu)
{
$oMenuNode = self::GetMenuNode($aMenu['index']);
@@ -278,21 +213,22 @@ class ApplicationMenu
/**
* Retrieves the currently active menu (if any, otherwise the first menu is the default)
* @return string The Id of the currently active menu
* @return MenuNode or null if there is no menu at all !
*/
static public function GetActiveNodeId()
{
$oAppContext = new ApplicationContext();
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
if ($sMenuId === null)
$iMenuIndex = $oAppContext->GetCurrentValue('menu', -1);
if ($iMenuIndex == -1)
{
// Make sure the root menu is sorted on 'rank'
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
$oFirstGroup = self::GetMenuNode(self::$aRootMenus[0]['index']);
$oMenuNode = self::GetMenuNode(self::$aMenusIndex[$oFirstGroup->GetIndex()]['children'][0]['index']);
$sMenuId = $oMenuNode->GetMenuId();
$iMenuIndex = $oMenuNode->GetIndex();
}
return $sMenuId;
return $iMenuIndex;
}
}
@@ -327,30 +263,25 @@ abstract class MenuNode
protected $sMenuId;
protected $index;
/**
* Properties reflecting how the node has been declared
*/
protected $aReflectionProperties;
/**
* Class of objects to check if the menu is enabled, null if none
*/
protected $m_aEnableClasses;
protected $m_sEnableClass;
/**
* User Rights Action code to check if the menu is enabled, null if none
*/
protected $m_aEnableActions;
protected $m_iEnableAction;
/**
* User Rights allowed results (actually a bitmask) to check if the menu is enabled, null if none
*/
protected $m_aEnableActionResults;
protected $m_iEnableActionResults;
/**
* Stimulus to check: if the user can 'apply' this stimulus, then she/he can see this menu
*/
protected $m_aEnableStimuli;
protected $m_sEnableStimulus;
/**
* Create a menu item, sets the condition to have it displayed and inserts it into the application's main menu
@@ -366,25 +297,12 @@ abstract class MenuNode
public function __construct($sMenuId, $iParentIndex = -1, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
$this->sMenuId = $sMenuId;
$this->aReflectionProperties = array();
if (strlen($sEnableClass) > 0)
{
$this->aReflectionProperties['enable_class'] = $sEnableClass;
$this->aReflectionProperties['enable_action'] = $iActionCode;
$this->aReflectionProperties['enable_permission'] = $iAllowedResults;
$this->aReflectionProperties['enable_stimulus'] = $sEnableStimulus;
}
$this->m_aEnableClasses = array($sEnableClass);
$this->m_aEnableActions = array($iActionCode);
$this->m_aEnableActionResults = array($iAllowedResults);
$this->m_aEnableStimuli = array($sEnableStimulus);
$this->m_sEnableClass = $sEnableClass;
$this->m_iEnableAction = $iActionCode;
$this->m_iEnableActionResults = $iAllowedResults;
$this->m_sEnableStimulus = $sEnableStimulus;
$this->index = ApplicationMenu::InsertMenu($this, $iParentIndex, $fRank);
}
public function ReflectionProperties()
{
return $this->aReflectionProperties;
}
public function GetMenuId()
{
@@ -393,12 +311,12 @@ abstract class MenuNode
public function GetTitle()
{
return Dict::S("Menu:$this->sMenuId", str_replace('_', ' ', $this->sMenuId));
return Dict::S("Menu:$this->sMenuId");
}
public function GetLabel()
{
return Dict::S("Menu:$this->sMenuId+", "");
return Dict::S("Menu:$this->sMenuId+");
}
public function GetIndex()
@@ -408,58 +326,42 @@ abstract class MenuNode
public function GetHyperlink($aExtraParams)
{
$aExtraParams['c[menu]'] = $this->GetMenuId();
return $this->AddParams(utils::GetAbsoluteUrlAppRoot().'pages/UI.php', $aExtraParams);
$aExtraParams['c[menu]'] = $this->GetIndex();
return $this->AddParams('../pages/UI.php', $aExtraParams);
}
/**
* Add a limiting display condition for the same menu node. The conditions will be combined with a AND
* @param $oMenuNode MenuNode Another definition of the same menu node, with potentially different access restriction
* @return void
*/
public function AddCondition(MenuNode $oMenuNode)
{
foreach($oMenuNode->m_aEnableClasses as $index => $sClass )
{
$this->m_aEnableClasses[] = $sClass;
$this->m_aEnableActions[] = $oMenuNode->m_aEnableActions[$index];
$this->m_aEnableActionResults[] = $oMenuNode->m_aEnableActionResults[$index];
$this->m_aEnableStimuli[] = $oMenuNode->m_aEnableStimuli[$index];
}
}
/**
* Tells whether the menu is enabled (i.e. displayed) for the current user
* @return bool True if enabled, false otherwise
*/
public function IsEnabled()
{
foreach($this->m_aEnableClasses as $index => $sClass)
if ($this->m_sEnableClass != null)
{
if ($sClass != null)
if (MetaModel::IsValidClass($this->m_sEnableClass))
{
if (MetaModel::IsValidClass($sClass))
if ($this->m_sEnableStimulus != null)
{
if ($this->m_aEnableStimuli[$index] != null)
if (!UserRights::IsStimulusAllowed($this->m_sEnableClass, $this->m_sEnableStimulus))
{
if (!UserRights::IsStimulusAllowed($sClass, $this->m_aEnableStimuli[$index]))
{
return false;
}
}
if ($this->m_aEnableActions[$index] != null)
{
$iResult = UserRights::IsActionAllowed($sClass, $this->m_aEnableActions[$index]);
if (!($iResult & $this->m_aEnableActionResults[$index]))
{
return false;
}
return false;
}
}
else
if ($this->m_iEnableAction != null)
{
return false;
$iResult = UserRights::IsActionAllowed($this->m_sEnableClass, $this->m_iEnableAction);
if (($iResult & $this->m_iEnableActionResults))
{
return true;
}
else
{
return false;
}
}
return true;
}
return false;
}
return true;
}
@@ -535,7 +437,6 @@ class TemplateMenuNode extends MenuNode
{
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sTemplateFile = $sTemplateFile;
$this->aReflectionProperties['template_file'] = $sTemplateFile;
}
public function GetHyperlink($aExtraParams)
@@ -549,7 +450,6 @@ class TemplateMenuNode extends MenuNode
$sTemplate = @file_get_contents($this->sTemplateFile);
if ($sTemplate !== false)
{
$aExtraParams['table_id'] = 'Menu_'.$this->GetMenuId();
$oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, $aExtraParams);
}
@@ -595,8 +495,6 @@ class OQLMenuNode extends MenuNode
$this->sOQL = $sOQL;
$this->bSearch = $bSearch;
$this->m_aParams = array();
$this->aReflectionProperties['oql'] = $sOQL;
$this->aReflectionProperties['do_search'] = $bSearch;
// Enhancement: we could set as the "enable" condition that the user has enough rights to "read" the objects
// of the class specified by the OQL...
}
@@ -608,10 +506,6 @@ class OQLMenuNode extends MenuNode
public function SetParameters($aParams)
{
$this->m_aParams = $aParams;
foreach($aParams as $sKey => $value)
{
$this->aReflectionProperties[$sKey] = $value;
}
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
@@ -626,19 +520,31 @@ class OQLMenuNode extends MenuNode
{
$sIcon = '';
}
// The standard template used for all such pages: a (closed) search form at the top and a list of results at the bottom
$sTemplate = '';
if ($this->bSearch)
{
$aParams = array_merge(array('open' => true, 'table_id' => 'Menu_'.$this->GetMenuId()), $aExtraParams);
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
$oBlock->Display($oPage, 0);
$sTemplate .= <<<EOF
<itopblock BlockClass="DisplayBlock" type="search" asynchronous="false" encoding="text/oql">$this->sOQL</itopblock>
EOF;
}
$oPage->add("<p class=\"page-header\">$sIcon ".Dict::S($this->sPageTitle)."</p>");
$aParams = array_merge(array('table_id' => 'Menu_'.$this->GetMenuId()), $aExtraParams);
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
$oBlock->Display($oPage, 1);
$sParams = '';
if (!empty($this->m_aParams))
{
$sParams = 'parameters="';
foreach($this->m_aParams as $sName => $sValue)
{
$sParams .= $sName.':'.$sValue.';';
}
$sParams .= '"';
}
$sTemplate .= <<<EOF
<p class="page-header">$sIcon<itopstring>$this->sPageTitle</itopstring></p>
<itopblock BlockClass="DisplayBlock" type="list" asynchronous="false" encoding="text/oql" $sParams>$this->sOQL</itopblock>
EOF;
$oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, $aExtraParams);
}
}
/**
@@ -666,15 +572,16 @@ class SearchMenuNode extends MenuNode
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sPageTitle = "Menu:$sMenuId+";
$this->sClass = $sClass;
$this->aReflectionProperties['class'] = $sClass;
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
$oSearch = new DBObjectSearch($this->sClass);
$aParams = array_merge(array('open' => true, 'table_id' => 'Menu_'.$this->GetMenuId()), $aExtraParams);
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
$oBlock->Display($oPage, 0);
// The standard template used for all such pages: an open search form at the top
$sTemplate = <<<EOF
<itopblock BlockClass="DisplayBlock" type="search" asynchronous="false" encoding="text/oql" parameters="open:true">SELECT $this->sClass</itopblock>
EOF;
$oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, $aExtraParams);
}
}
@@ -704,12 +611,11 @@ class WebPageMenuNode extends MenuNode
{
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sHyperlink = $sHyperlink;
$this->aReflectionProperties['url'] = $sHyperlink;
}
public function GetHyperlink($aExtraParams)
{
$aExtraParams['c[menu]'] = $this->GetMenuId();
$aExtraParams['c[menu]'] = $this->GetIndex();
return $this->AddParams( $this->sHyperlink, $aExtraParams);
}
@@ -742,13 +648,12 @@ class NewObjectMenuNode extends MenuNode
{
parent::__construct($sMenuId, $iParentIndex, $fRank);
$this->sClass = $sClass;
$this->aReflectionProperties['class'] = $sClass;
}
public function GetHyperlink($aExtraParams)
{
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$this->sClass;
$aExtraParams['c[menu]'] = $this->GetMenuId();
$sHyperlink = '../pages/UI.php?operation=new&class='.$this->sClass;
$aExtraParams['c[menu]'] = $this->GetIndex();
return $this->AddParams($sHyperlink, $aExtraParams);
}
@@ -779,116 +684,4 @@ class NewObjectMenuNode extends MenuNode
assert(false); // Shall never be called, the external web page will handle the display by itself
}
}
require_once(APPROOT.'application/dashboard.class.inc.php');
/**
* This class defines a menu item which content is based on XML dashboard.
*/
class DashboardMenuNode extends MenuNode
{
protected $sDashboardFile;
/**
* Create a menu item based on a custom template and inserts it into the application's main menu
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
* @param string $sTemplateFile Path (or URL) to the file that will be used as a template for displaying the page's content
* @param integer $iParentIndex ID of the parent menu
* @param float $fRank Number used to order the list, any number will do, but for a given level (i.e same parent) all menus are sorted based on this value
* @param string $sEnableClass Name of class of object
* @param integer $iActionCode Either UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_DELETE, UR_ACTION_BULKREAD, UR_ACTION_BULKMODIFY or UR_ACTION_BULKDELETE
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
* @return MenuNode
*/
public function __construct($sMenuId, $sDashboardFile, $iParentIndex, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sDashboardFile = $sDashboardFile;
$this->aReflectionProperties['definition_file'] = $sDashboardFile;
}
public function GetHyperlink($aExtraParams)
{
if ($this->sDashboardFile == '') return '';
return parent::GetHyperlink($aExtraParams);
}
public function GetDashboard()
{
$sDashboardDefinition = @file_get_contents($this->sDashboardFile);
if ($sDashboardDefinition !== false)
{
$bCustomized = false;
// Search for an eventual user defined dashboard, overloading the existing one
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->sMenuId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$sDashboardDefinition = $oUserDashboard->Get('contents');
$bCustomized = true;
}
$oDashboard = new RuntimeDashboard($this->sMenuId);
$oDashboard->FromXml($sDashboardDefinition);
$oDashboard->SetCustomFlag($bCustomized);
}
else
{
$oDashboard = null;
}
return $oDashboard;
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
$oDashboard = $this->GetDashboard();
if ($oDashboard != null)
{
$oDashboard->Render($oPage, false, $aExtraParams);
$bEdit = utils::ReadParam('edit', false);
if ($bEdit)
{
$sId = addslashes($this->sMenuId);
$oPage->add_ready_script("EditDashboard('$sId');");
}
}
else
{
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
}
}
public function RenderEditor(WebPage $oPage)
{
$oDashboard = $this->GetDashboard();
if ($oDashboard != null)
{
$oDashboard->RenderEditor($oPage);
}
else
{
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
}
}
public function AddDashlet($oDashlet)
{
$oDashboard = $this->GetDashboard();
if ($oDashboard != null)
{
$oDashboard->AddDashlet($oDashlet);
$oDashboard->Save();
}
else
{
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
}
}
}
?>

View File

@@ -30,125 +30,30 @@ require_once(APPROOT."/application/webpage.class.inc.php");
class NiceWebPage extends WebPage
{
var $m_aReadyScripts;
var $m_sRootUrl;
public function __construct($s_title)
{
parent::__construct($s_title);
$this->m_aReadyScripts = array();
$this->add_linked_script("../js/jquery-1.7.1.min.js");
$this->add_linked_stylesheet('../css/ui-lightness/jquery-ui-1.8.17.custom.css');
$this->add_linked_script('../js/jquery-ui-1.8.17.custom.min.js');
$this->add_linked_script("../js/jquery-1.4.2.min.js");
//$this->add_linked_script("../js/jquery.history_remote.pack.js");
$this->add_linked_stylesheet('../css/ui-lightness/jquery-ui-1.8.2.custom.css');
$this->add_linked_script('../js/jquery-ui-1.8.2.custom.min.js');
//$this->add_linked_script("../js/ui.resizable.js");
// $this->add_linked_script("../js/ui.tabs.js");
$this->add_linked_script("../js/hovertip.js");
// table sorting
$this->add_linked_script("../js/jquery.tablesorter.min.js");
$this->add_linked_script("../js/jquery.tablesorter.pager.js");
$this->add_linked_script("../js/jquery.tablehover.js");
$this->add_ready_script(
<<< EOF
//add new widget called TruncatedList to properly display truncated lists when they are sorted
$.tablesorter.addWidget({
// give the widget a id
id: "truncatedList",
// format is called when the on init and when a sorting has finished
format: function(table)
{
// Check if there is a "truncated" line
this.truncatedList = false;
if ($("tr td.truncated",table).length > 0)
{
this.truncatedList = true;
}
if (this.truncatedList)
{
$("tr td",table).removeClass('truncated');
$("tr:last td",table).addClass('truncated');
}
}
});
$.tablesorter.addWidget({
// give the widget a id
id: "myZebra",
// format is called when the on init and when a sorting has finished
format: function(table)
{
// Replace the 'red even' lines by 'red_even' since most browser do not support 2 classes selector in CSS, etc..
$("tbody tr:even",table).addClass('even');
$("tbody tr.red:even",table).removeClass('red').removeClass('even').addClass('red_even');
$("tbody tr.orange:even",table).removeClass('orange').removeClass('even').addClass('orange_even');
$("tbody tr.green:even",table).removeClass('green').removeClass('even').addClass('green_even');
// In case we sort again the table, we need to remove the added 'even' classes on odd rows
$("tbody tr:odd",table).removeClass('even');
$("tbody tr.red_even:odd",table).removeClass('even').removeClass('red_even').addClass('red');
$("tbody tr.orange_even:odd",table).removeClass('even').removeClass('orange_even').addClass('orange');
$("tbody tr.green_even:odd",table).removeClass('even').removeClass('green_even').addClass('green');
}
});
$("table.listResults").tableHover(); // hover tables
EOF
);
// $this->add_linked_script("../js/jqModal.js");
$this->add_linked_stylesheet("../css/light-grey.css");
$this->m_sRootUrl = $this->GetAbsoluteUrlAppRoot();
$sAbsURLAppRoot = addslashes($this->m_sRootUrl);
$sAbsURLModulesRoot = addslashes($this->GetAbsoluteUrlModulesRoot());
$sAppContext = addslashes($this->GetApplicationContext());
$this->add_script(
<<<EOF
function GetAbsoluteUrlAppRoot()
{
return '$sAbsURLAppRoot';
}
function GetAbsoluteUrlModulesRoot()
{
return '$sAbsURLModulesRoot';
}
function AddAppContext(sURL)
{
var sContext = '$sAppContext';
if (sContext.length > 0)
{
if (sURL.indexOf('?') == -1)
{
return sURL+'?'+sContext;
}
return sURL+'&'+sContext;
}
return sURL;
}
EOF
);
}
public function SetRootUrl($sRootUrl)
{
$this->m_sRootUrl = $sRootUrl;
// $this->add_linked_stylesheet("../js/themes/light/light.tabs.css");
//$this->add_linked_stylesheet("../css/jquery.tabs-ie.css", "lte IE 7");
// $this->add_linked_stylesheet("../css/jqModal.css");
$this->add_ready_script(' window.setTimeout(hovertipInit, 1);');
}
public function small_p($sText)
{
$this->add("<p style=\"font-size:smaller\">$sText</p>\n");
}
public function GetAbsoluteUrlAppRoot()
{
return utils::GetAbsoluteUrlAppRoot();
}
public function GetAbsoluteUrlModulesRoot()
{
return utils::GetAbsoluteUrlModulesRoot();
}
function GetApplicationContext()
{
$oAppContext = new ApplicationContext();
return $oAppContext->GetForLink();
}
}
// By Rom, used by CSVImport and Advanced search
public function MakeClassesSelect($sName, $sDefaultValue, $iWidthPx, $iActionCode = null)
@@ -195,7 +100,6 @@ EOF
*/
public function output()
{
$this->set_base($this->m_sRootUrl.'pages/');
if (count($this->m_aReadyScripts)>0)
{
$this->add_script("\$(document).ready(function() {\n".implode("\n", $this->m_aReadyScripts)."\n});");

View File

@@ -26,18 +26,6 @@
require_once(APPROOT."/application/nicewebpage.class.inc.php");
require_once(APPROOT."/application/applicationcontext.class.inc.php");
require_once(APPROOT."/application/user.preferences.class.inc.php");
define('BUTTON_CANCEL', 1);
define('BUTTON_BACK', 2);
define('BUTTON_NEXT', 4);
define('BUTTON_FINISH', 8);
define('PARAM_ARROW_SEP', '_x_');
class TransactionException extends Exception
{
}
/**
* Web page with some associated CSS and scripts (jquery) for a fancier display
* of the Portal web page
@@ -47,22 +35,16 @@ class PortalWebPage extends NiceWebPage
/**
* Portal menu
*/
protected $m_sWelcomeMsg;
protected $m_aMenuButtons;
public function __construct($sTitle, $sAlternateStyleSheet = '')
{
$this->m_sWelcomeMsg = '';
$this->m_aMenuButtons = array();
parent::__construct($sTitle);
$this->add_header("Content-type: text/html; charset=utf-8");
$this->add_header("Cache-control: no-cache");
$this->add_linked_stylesheet("../css/jquery.treeview.css");
$this->add_linked_stylesheet("../css/jquery.autocomplete.css");
$sAbsURLAppRoot = addslashes(utils::GetAbsoluteUrlAppRoot()); // Pass it to Javascript scripts
$sAbsURLModulesRoot = addslashes(utils::GetAbsoluteUrlModulesRoot()); // Pass it to Javascript scripts
$oAppContext = new ApplicationContext();
$sAppContext = addslashes($oAppContext->GetForLink());
if ($sAlternateStyleSheet != '')
{
$this->add_linked_stylesheet("../portal/$sAlternateStyleSheet/portal.css");
@@ -76,16 +58,15 @@ class PortalWebPage extends NiceWebPage
$this->add_linked_script("../js/jquery.tablehover.js");
$this->add_linked_script("../js/jquery.treeview.js");
$this->add_linked_script("../js/jquery.autocomplete.js");
$this->add_linked_script("../js/jquery.bgiframe.js");
$this->add_linked_script("../js/jquery.positionBy.js");
$this->add_linked_script("../js/jquery.popupmenu.js");
$this->add_linked_script("../js/date.js");
$this->add_linked_script("../js/jquery.tablesorter.min.js");
$this->add_linked_script("../js/jquery.tablesorter.pager.js");
$this->add_linked_script("../js/jquery.blockUI.js");
$this->add_linked_script("../js/utils.js");
$this->add_linked_script("../js/forms-json-utils.js");
$this->add_linked_script("../js/swfobject.js");
$this->add_linked_script("../js/jquery.qtip-1.0.min.js");
$this->add_ready_script(
<<<EOF
try
@@ -126,6 +107,8 @@ try
}
});
$("table.listResults").tableHover(); // hover tables
$(".listResults").tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
$(".date-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
@@ -135,8 +118,7 @@ try
changeMonth: true,
changeYear: true
});
//$('.resizable').resizable(); // Make resizable everything that claims to be resizable !
$('.caselog_header').click( function () { $(this).toggleClass('open').next('.caselog_entry').toggle(); });
$('.resizable').resizable(); // Make resizable everything that claims to be resizable !
}
catch(err)
{
@@ -148,18 +130,9 @@ EOF
$this->add_script(
<<<EOF
function CheckSelection(sMessage, sInputId)
function CheckSelection(sMessage)
{
var bResult;
if (sInputId.length > 0)
{
bResult = ($('input[name='+sInputId+']:checked').length > 0);
}
else
{
// First select found...
bResult = ($('input:checked').length > 0);
}
var bResult = ($('input:checked').length > 0);
if (!bResult)
{
alert(sMessage);
@@ -167,72 +140,19 @@ EOF
return bResult;
}
function GetAbsoluteUrlAppRoot()
function GoBack()
{
return '$sAbsURLAppRoot';
}
function GetAbsoluteUrlModulesRoot()
{
return '$sAbsURLModulesRoot';
}
function AddAppContext(sURL)
{
var sContext = '$sAppContext';
if (sContext.length > 0)
{
if (sURL.indexOf('?') == -1)
{
return sURL+'?'+sContext;
}
return sURL+'&'+sContext;
}
return sURL;
}
function GoBack(sFormId)
{
var form = $('#'+sFormId);
var step_back = $('input[name=step_back]');
var form = $('#request_form');
var step = $('input[name=step]');
form.unbind('submit'); // De-activate validation
step_back.val(1);
step.val(step.val() -2); // To go Back one step: next step is x, current step is x-1, previous step is x-2
form.submit(); // Go
}
function GoHome()
{
var form = $('FORM');
form.unbind('submit'); // De-activate validation
window.location.href = '?operation=';
return false;
}
function SetWizardNextStep(sStep)
{
var next_step = $('input[id=next_step]');
next_step.val(sStep);
}
EOF
);
}
public function SetCurrentTab($sTabLabel = '')
{
}
/**
* Specify a welcome message (optional)
*/
public function SetWelcomeMessage($sMsg)
{
$this->m_sWelcomeMsg = $sMsg;
}
/**
* Add a button to the portal's main menu
@@ -241,594 +161,17 @@ EOF
{
$this->m_aMenuButtons[] = array('id' => $sId, 'label' => $sLabel, 'hyperlink' => $sHyperlink);
}
var $m_bEnableDisconnectButton = true;
public function EnableDisconnectButton($bEnable)
{
$this->m_bEnableDisconnectButton = $bEnable;
}
public function output()
{
$sMenu = '';
if ($this->m_bEnableDisconnectButton)
{
$this->AddMenuButton('logoff', 'Portal:Disconnect', utils::GetAbsoluteUrlAppRoot().'pages/logoff.php'); // This menu is always present and is the last one
}
$this->AddMenuButton('logoff', 'Portal:Disconnect', '../pages/logoff.php?portal=1'); // This menu is always present and is the last one
foreach($this->m_aMenuButtons as $aMenuItem)
{
$sMenu .= "<a class=\"button\" id=\"{$aMenuItem['id']}\" href=\"{$aMenuItem['hyperlink']}\"><span>".Dict::S($aMenuItem['label'])."</span></a>";
}
$this->s_content = '<div id="portal"><div id="welcome">'.$this->m_sWelcomeMsg.'</div><div id="banner"><div id="logo"></div><div id="menu">'.$sMenu.'</div></div><div id="content">'.$this->s_content.'</div></div>';
$this->s_content = '<div id="portal"><div id="banner"><div id="logo"></div>'.$sMenu.'</div><div id="content">'.$this->s_content.'</div></div>';
parent::output();
}
/**
* Displays a list of objects, without any hyperlink (except for the object's details)
* @param DBObjectSet $oSet The set of objects to display
* @param Array $aZList The ZList (list of field codes) to use for the tabular display
* @param String $sEmptyListMessage Message displayed whenever the list is empty
* @return string The HTML text representing the list
*/
public function DisplaySet($oSet, $aZList, $sEmptyListMessage = '')
{
if ($oSet->Count() > 0)
{
$sClass = $oSet->GetClass();
if (is_subclass_of($sClass, 'cmdbAbstractObject'))
{
// Home-made and very limited display of an object set
//
//$oSet->Seek(0);// juste pour que le warning soit moins crado
//$oSet->Fetch();// juste pour que le warning soit moins crado
//
$this->add("<div id=\"listOf$sClass\">\n");
cmdbAbstractObject::DisplaySet($this, $oSet, array('currentId' => $this->GetUniqueId()."$sClass", 'menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList)));
$this->add("</div>\n");
}
else
{
// Home-made and very limited display of an object set
$aAttribs = array();
$aValues = array();
$aAttribs['key'] = array('label' => MetaModel::GetName($sClass), 'description' => '');
foreach($aZList as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$aAttribs[$sAttCode] = array('label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
}
while($oObj = $oSet->Fetch())
{
$aRow = array();
$aRow['key'] = '<a href="./index.php?operation=details&class='.get_class($oObj).'&id='.$oObj->GetKey().'">'.$oObj->GetName().'</a>';
$sHilightClass = $oObj->GetHilightClass();
if ($sHilightClass != '')
{
$aRow['@class'] = $sHilightClass;
}
foreach($aZList as $sAttCode)
{
$aRow[$sAttCode] = $oObj->GetAsHTML($sAttCode);
}
$aValues[$oObj->GetKey()] = $aRow;
}
$this->table($aAttribs, $aValues);
}
}
elseif (strlen($sEmptyListMessage) > 0)
{
$this->add($sEmptyListMessage);
}
}
/**
* Display the attributes of an object (no title, no form)
* @param Object $oObj Any kind of object
* @param aAttList The list of attributes to display
* @return void
*/
public function DisplayObjectDetails($oObj, $aAttList)
{
$sClass = get_class($oObj);
$aDetails = array();
foreach($aAttList as $sAttCode)
{
$iFlags = $oObj->GetAttributeFlags($sAttCode);
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
if ( (!$oAttDef->IsLinkSet()) && (($iFlags & OPT_ATT_HIDDEN) == 0) )
{
// Don't display linked set and non-visible attributes (in this state)
$sDisplayValue = $oObj->GetAsHTML($sAttCode);
$aDetails[] = array('label' => '<span title="'.MetaModel::GetDescription($sClass, $sAttCode).'">'.MetaModel::GetLabel($sClass, $sAttCode).'</span>', 'value' => $sDisplayValue);
}
}
$this->details($aDetails);
}
/**
* DisplayObjectLinkset
* @param Object $oObj Any kind of object
* @param $sLinkSetAttCode The attribute code of the link set attribute to display
* @param $sRemoteAttCode The external key on the linked class, pointing to the remote objects
* @param $aZList The list of attribute of the remote object
* @param $sEmptyListMessage The message to display if the list is empty
* @return void
*/
public function DisplayObjectLinkset($oObj, $sLinkSetAttCode, $sRemoteAttCode, $aZList, $sEmptyListMessage = '', $oSearchRestriction = null)
{
if (empty($sEmptyListMessage))
{
$sEmptyListMessage = Dict::S('UI:Search:NoObjectFound');
}
$oLinkSet = $oObj->Get($sLinkSetAttCode);
if ($oLinkSet->Count() > 0)
{
$sClass = $oLinkSet->GetClass();
$oExtKeyToRemote = MetaModel::GetAttributeDef($sClass, $sRemoteAttCode);
$sRemoteClass = $oExtKeyToRemote->GetTargetClass();
if (is_null($oSearchRestriction))
{
$oObjSearch = new DBObjectSearch($sRemoteClass);
}
else
{
$oObjSearch = $oSearchRestriction;
}
$oObjSearch->AddCondition_ReferencedBy($oLinkSet->GetFilter(), $sRemoteAttCode);
$aExtraParams = array('menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList));
$oBlock = new DisplayBlock($oObjSearch, 'list', false);
$oBlock->Display($this, 1, $aExtraParams);
}
elseif (strlen($sEmptyListMessage) > 0)
{
$this->add($sEmptyListMessage);
}
}
protected function DisplaySearchField($sClass, $sAttSpec, $aExtraParams, $sPrefix, $sFieldName = null)
{
if (is_null($sFieldName))
{
$sFieldName = str_replace('->', PARAM_ARROW_SEP, $sAttSpec);
}
$iPos = strpos($sAttSpec, '->');
if ($iPos !== false)
{
$sAttCode = substr($sAttSpec, 0, $iPos);
$sSubSpec = substr($sAttSpec, $iPos + 2);
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
{
throw new Exception("Invalid attribute code '$sClass/$sAttCode' in search specification '$sAttSpec'");
}
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsLinkSet())
{
$sTargetClass = $oAttDef->GetLinkedClass();
}
elseif ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
{
$sTargetClass = $oAttDef->GetTargetClass(EXTKEY_ABSOLUTE);
}
else
{
throw new Exception("Attribute specification '$sAttSpec', '$sAttCode' should be either a link set or an external key");
}
$this->DisplaySearchField($sTargetClass, $sSubSpec, $aExtraParams, $sPrefix, $sFieldName);
}
else
{
// $sAttSpec is an attribute code
//
$this->add('<span style="white-space: nowrap;padding:5px;display:inline-block;">');
$sFilterValue = '';
$sFilterValue = utils::ReadParam($sPrefix.$sFieldName, '', false, 'raw_data');
$sFilterOpCode = null; // Use the default 'loose' OpCode
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttSpec);
if ($oAttDef->IsExternalKey())
{
$sTargetClass = $oAttDef->GetTargetClass();
$oAllowedValues = new DBObjectSet(new DBObjectSearch($sTargetClass));
$iFieldSize = $oAttDef->GetMaxSize();
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
$this->add("<label>".MetaModel::GetFilterLabel($sClass, $sAttSpec).":</label>&nbsp;");
//$oWidget = UIExtKeyWidget::DIsplayFromAttCode($sAttSpec, $sClass, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sPrefix.$sFieldName, false, '', $sPrefix, '');
//$this->add($oWidget->Display($this, $aExtraParams, true /* bSearchMode */));
$aExtKeyParams = $aExtraParams;
$aExtKeyParams['iFieldSize'] = $oAttDef->GetMaxSize();
$aExtKeyParams['iMinChars'] = $oAttDef->GetMinAutoCompleteChars();
// DisplayFromAttCode($this, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false)
$sHtml = UIExtKeyWidget::DisplayFromAttCode($this, $sAttSpec, $sClass, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sPrefix.$sFieldName, false, $sPrefix.$sFieldName, $sPrefix, $aExtKeyParams, true);
$this->add($sHtml);
}
else
{
$aAllowedValues = MetaModel::GetAllowedValues_flt($sClass, $sAttSpec, $aExtraParams);
if (is_null($aAllowedValues))
{
// Any value is possible, display an input box
$this->add("<label>".MetaModel::GetFilterLabel($sClass, $sAttSpec).":</label>&nbsp;<input class=\"textSearch\" name=\"$sPrefix$sFieldName\" value=\"$sFilterValue\"/>\n");
}
else
{
//Enum field or external key, display a combo
$sValue = "<select name=\"$sPrefix$sFieldName\">\n";
$sValue .= "<option value=\"\">".Dict::S('UI:SearchValue:Any')."</option>\n";
foreach($aAllowedValues as $key => $value)
{
if ($sFilterValue == $key)
{
$sSelected = ' selected';
}
else
{
$sSelected = '';
}
$sValue .= "<option value=\"$key\"$sSelected>$value</option>\n";
}
$sValue .= "</select>\n";
$this->add("<label>".MetaModel::GetFilterLabel($sClass, $sAttSpec).":</label>&nbsp;$sValue\n");
}
}
unset($aExtraParams[$sFieldName]);
$this->add('</span> ');
$sTip = $oAttDef->GetHelpOnSmartSearch();
if (strlen($sTip) > 0)
{
$sTip = addslashes($sTip);
$sTip = str_replace(array("\n", "\r"), " ", $sTip);
// :input does represent in form visible input (INPUT, SELECT, TEXTAREA)
$this->add_ready_script("$(':input[name={$sPrefix}$sFieldName]').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
}
}
}
public function DisplaySearchForm($sClass, $aAttList, $aExtraParams, $sPrefix, $bClosed = true)
{
$sCSSClass = ($bClosed) ? 'DrawerClosed' : '';
$this->add("<div id=\"ds_$sPrefix\" class=\"SearchDrawer $sCSSClass\">\n");
$this->add_ready_script(
<<<EOF
$("#dh_$sPrefix").click( function() {
$("#ds_$sPrefix").slideToggle('normal', function() { $("#ds_$sPrefix").parent().resize(); } );
$("#dh_$sPrefix").toggleClass('open');
});
EOF
);
$this->add("<form id=\"search_$sClass\" action=\"\" method=\"post\">\n"); // Don't use $_SERVER['SCRIPT_NAME'] since the form may be called asynchronously (from ajax.php)
// $this->add("<h2>".Dict::Format('UI:SearchFor_Class_Objects', 'xxxxxx')."</h2>\n");
$this->add("<p>\n");
foreach($aAttList as $sAttSpec)
{
//$oAppContext->Reset($sAttSpec); // Make sure the same parameter will not be passed twice
$this->DisplaySearchField($sClass, $sAttSpec, $aExtraParams, $sPrefix);
}
$this->add("</p>\n");
$this->add("<p align=\"right\"><input type=\"submit\" value=\"".Dict::S('UI:Button:Search')."\"></p>\n");
foreach($aExtraParams as $sName => $sValue)
{
$this->add("<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n");
}
// $this->add($oAppContext->GetForForm());
$this->add("</form>\n");
$this->add("</div>\n");
$this->add("<div class=\"HRDrawer\"></div>\n");
$this->add("<div id=\"dh_$sPrefix\" class=\"DrawerHandle\">".Dict::S('UI:SearchToggle')."</div>\n");
}
/**
* Read parameters from the page
* Parameters that were absent from the page's parameters are not set in the resulting hash array
* @input string $sMethod Either get or post
* @return Hash Array of name => value corresponding to the parameters that were passed to the page
*/
public function ReadAllParams($sParamList, $sPrefix = 'attr_')
{
$aParams = explode(',', $sParamList);
$aValues = array();
foreach($aParams as $sName)
{
$sName = trim($sName);
$value = utils::ReadParam($sPrefix.$sName, null, false, 'raw_data');
if (!is_null($value))
{
$aValues[$sName] = $value;
}
}
return $aValues;
}
/**
* Outputs a list of parameters as hidden fields
* Example: attr_dummy[-123][id] = "blah"
* @param Hash $aParameters Array name => value for the parameters
* @param Array $aExclude The list of parameters that must not be handled this way (probably already in the visible part of the form)
* @return void
*/
protected function DumpHiddenParamsInternal($sName, $value)
{
if (is_array($value))
{
foreach($value as $sKey => $item)
{
$this->DumpHiddenParamsInternal($sName.'['.$sKey.']', $item);
}
}
else
{
$this->Add("<input type=\"hidden\" name=\"$sName\" value=\"$value\">");
}
}
/**
* Outputs a list of parameters as hidden field into the current page
* (must be called when inside a form)
* @param Hash $aParameters Array name => value for the parameters
* @param Array $aExclude The list of parameters that must not be handled this way (probably already in the visible part of the form)
* @return void
*/
public function DumpHiddenParams($aParameters, $aExclude = null, $sPrefix = 'attr_')
{
foreach($aParameters as $sAttCode => $value)
{
if (is_null($aExclude) || !in_array($sAttCode, $aExclude))
{
$this->DumpHiddenParamsInternal($sPrefix.$sAttCode, $value);
}
}
}
public function PostedParamsToFilter($sClass, $aAttList, $sPrefix)
{
$oFilter = new DBObjectSearch($sClass);
$iCountParams = 0;
foreach($aAttList as $sAttSpec)
{
$sFieldName = str_replace('->', PARAM_ARROW_SEP, $sAttSpec);
$value = utils::ReadPostedParam($sPrefix.$sFieldName, null, 'raw_data');
if (!is_null($value) && strlen($value) > 0)
{
$oFilter->AddConditionAdvanced($sAttSpec, $value);
$iCountParams++;
}
}
if ($iCountParams == 0)
{
return null;
}
else
{
return $oFilter;
}
}
/**
* Updates the object form POSTED arguments, and writes it into the DB (applies a stimuli if requested)
* @param DBObject $oObj The object to update
* $param array $aAttList If set, this will limit the list of updated attributes
* @return void
*/
public function DoUpdateObjectFromPostedForm(DBObject $oObj, $aAttList = null)
{
$sTransactionId = utils::ReadPostedParam('transaction_id', '');
if (!utils::IsTransactionValid($sTransactionId))
{
throw new TransactionException();
}
$sClass = get_class($oObj);
$sStimulus = trim(utils::ReadPostedParam('apply_stimulus', ''));
$sTargetState = '';
if (!empty($sStimulus))
{
// Compute the target state
$aTransitions = $oObj->EnumTransitions();
if (!isset($aTransitions[$sStimulus]))
{
throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
}
$sTargetState = $aTransitions[$sStimulus]['target_state'];
}
$oObj->UpdateObjectFromPostedForm('' /* form prefix */, $aAttList, $sTargetState);
// Optional: apply a stimulus
//
if (!empty($sStimulus))
{
if (!$oObj->ApplyStimulus($sStimulus))
{
throw new Exception("Cannot apply stimulus '$sStimulus' to {$oObj->GetName()}");
}
}
// Record the change
//
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$sUserString = CMDBChange::GetCurrentUserName();
$oMyChange->Set("userinfo", $sUserString);
$iChangeId = $oMyChange->DBInsert();
$oObj->DBUpdateTracked($oMyChange);
// Trigger ?
//
$aClasses = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL);
$sClassList = implode(", ", CMDBSource::Quote($aClasses));
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnPortalUpdate AS t WHERE t.target_class IN ($sClassList)"));
while ($oTrigger = $oSet->Fetch())
{
$oTrigger->DoActivate($oObj->ToArgs('this'));
}
$this->p("<h1>".Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName())."</h1>\n");
}
/**
* Find the object of the specified Class/ID.
* @param WebPage $oP The current page
* @return DBObject The found object, or throws an exception in case of failure
*/
public function FindObjectFromArgs($aAllowedClasses = null)
{
$sClass = utils::ReadParam('class', '', true, 'class');
$iId = utils::ReadParam('id', 0, true, 'integer');
if (empty($sClass))
{
throw new Exception("Missing argument 'class'");
}
if (!MetaModel::IsValidClass($sClass))
{
throw new Exception("Wrong value for argument 'class': $sClass");
}
if ($iId == 0)
{
throw new Exception("Missing argument 'id'");
}
if(!is_null($aAllowedClasses))
{
$bAllowed = false;
foreach($aAllowedClasses as $sParentClass)
{
if (MetaModel::IsParentClass($sParentClass, $sClass))
{
$bAllowed = true;
}
}
if (!$bAllowed)
{
throw new Exception("Class '$sClass not allowed in this implementation'");
}
}
$oObj = MetaModel::GetObject($sClass, $iId, false);
if (!is_object($oObj))
{
throw new Exception("Could not find the object $sClass/$iId");
}
return $oObj;
}
var $m_sWizardId = null;
public function WizardFormStart($sId = '', $sNextStep = null, $bAttachment = false, $sMethod = 'post')
{
$this->m_sWizardId = $sId;
// multipart... needed for file upload
$this->add("<form id=\"{$this->m_sWizardId}\" method=\"$sMethod\" enctype=\"multipart/form-data\">\n");
$aPreviousSteps = $this->GetWizardStepHistory();
if (utils::ReadParam('step_back', 0) == 1)
{
// Back into the past history
array_pop($aPreviousSteps);
}
else
{
// Moving forward
array_push($aPreviousSteps, utils::ReadParam('next_step'));
}
$sStepHistory = implode(',', $aPreviousSteps);
$this->add("<input type=\"hidden\" id=\"step_history\" name=\"step_history\" value=\"$sStepHistory\">");
if (!is_null($sNextStep))
{
$this->add("<input type=\"hidden\" id=\"next_step\" name=\"next_step\" value=\"$sNextStep\">");
}
$this->add("<input type=\"hidden\" id=\"step_back\" name=\"step_back\" value=\"0\">");
$sTransactionId = utils::GetNewTransactionId();
$this->SetTransactionId($sTransactionId);
$this->add("<input type=\"hidden\" id=\"transaction_id\" name=\"transaction_id\" value=\"$sTransactionId\">\n");
$this->add_ready_script("$(window).unload(function() { OnUnload('$sTransactionId') } );\n");
}
public function WizardFormButtons($iButtonFlags)
{
$aButtons = array();
if ($iButtonFlags & BUTTON_CANCEL)
{
$aButtons[] = "<input id=\"btn_cancel\" type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"GoHome();\">";
}
if ($iButtonFlags & BUTTON_BACK)
{
$aButtons[] = "<input id=\"btn_back\" type=\"submit\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoBack('{$this->m_sWizardId}');\">";
}
if ($iButtonFlags & BUTTON_NEXT)
{
$aButtons[] = "<input id=\"btn_next\" type=\"submit\" value=\"".Dict::S('UI:Button:Next')."\">";
}
if ($iButtonFlags & BUTTON_FINISH)
{
$aButtons[] = "<input id=\"btn_finish\" type=\"submit\" value=\"".Dict::S('UI:Button:Finish')."\">";
}
$this->add('<div id="buttons">');
$this->add(implode('', $aButtons));
$this->add('</div>');
}
public function WizardFormEnd()
{
$this->add("</form>\n");
}
public function GetWizardStep()
{
if (utils::ReadParam('step_back', 0) == 1)
{
// Take the value into the history - one level above
$aPreviousSteps = $this->GetWizardStepHistory();
array_pop($aPreviousSteps);
return end($aPreviousSteps);
}
else
{
return utils::ReadParam('next_step');
}
}
protected function GetWizardStepHistory()
{
$sRawHistory = trim(utils::ReadParam('step_history', '', false, 'raw_data'));
if (strlen($sRawHistory) == 0)
{
return array();
}
else
{
return explode(',', $sRawHistory);
}
}
public function WizardCheckSelectionOnSubmit($sMessageIfNoSelection, $sInputName = '')
{
$this->add_ready_script(
<<<EOF
$('#{$this->m_sWizardId}').submit(function() {
return CheckSelection('$sMessageIfNoSelection', '$sInputName');
});
EOF
);
}
}
?>

View File

@@ -1,107 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Persistent class Event and derived
* Application internal events
* There is also a file log
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
abstract class Query extends cmdbAbstractObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui,application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_query",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'fields')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
class QueryOQL extends Query
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui,application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_query_oql",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{
parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams);
if (!$bEditMode)
{
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
$sOql = $this->Get('oql');
$oSearch = DBObjectSearch::FromOQL($sOql);
$aParameters = $oSearch->GetQueryParams();
foreach($aParameters as $sParam => $val)
{
$sUrl .= '&arg_'.$sParam.'=["'.$sParam.'"]';
}
$oPage->p(Dict::S('UI:Query:UrlForExcel').':<br/><textarea cols="80" rows="3" READONLY>'.$sUrl.'</textarea>');
}
}
}
?>

View File

@@ -1,531 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* SqlBlock - display tables or charts, given an SQL query - use cautiously!
*
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/pages/php-ofc-library/open-flash-chart.php');
/**
* Helper class to design optimized dashboards, based on an SQL query
*
*/
class SqlBlock
{
protected $m_sQuery;
protected $m_aColumns;
protected $m_sTitle;
protected $m_sType;
protected $m_aParams;
public function __construct($sQuery, $aColumns, $sTitle, $sType, $aParams = array())
{
$this->m_sQuery = $sQuery;
$this->m_aColumns = $aColumns;
$this->m_sTitle = $sTitle;
$this->m_sType = $sType;
$this->m_aParams = $aParams;
}
/**
* Constructs a SqlBlock object from an XML template
/*
*
* <sqlblock>
* <sql>SELECT date_format(start_date, '%d') AS Date, count(*) AS Count FROM ticket WHERE DATE_SUB(NOW(), INTERVAL 15 DAY) &lt; start_date AND finalclass = 'UserIssue' GROUP BY date_format(start_date, '%d') AND $CONDITION(param1, ticket.org_id)$</sql>
* <type>table</type>
* <title>UserRequest:Overview-Title</title>
* <parameter>
* <name>param1</name>
* <type>context</type>
* <mapping>org_id</mapping>
* </parameter>
* <column>
* <name>Date</name>
* <label>UserRequest:Overview-Date</label>
* <drilldown></drilldown>
* </column>
* <column>
* <name>Count</name>
* <label>UserRequest:Overview-Count</label>
* <drilldown>SELECT UserIssue WHERE date_format(start_date, '%d') = :Date</drilldown>
* </column>
* </sqlblock>
*
* Tags
* - sql: a (My)SQL query. Do not forget to use html entities (e.g. &lt; for <)
* - type: table (default), bars or pie. If bars or pie is selected only the two first columns are taken into account.
* - title: optional title, typed in clear or given as a dictionnary entry
* - parameter: specifies how to map the context parameters (namely org_id) to a given named parameter in the query.
* The expression $CONDITION(<param_name>, <sql_column_name>) will be automatically replaced by:
* either the string "1" if there is no restriction on the organisation in iTop
* or the string "(<sql_column_name>=<value_of_org_id>)" if there is a limitation to one organizations in iTop
* or the string "(<sql_column_name> IN (<values_of_org_id>))" if there is a limitation to a given set of organizations in iTop
* - column: specification of a column (not displayed if omitted)
* - column / name: name of the column in the SQL query (use aliases)
* - column / label: label, typed in clear or given as a dictionnary entry
* - column / drilldown: NOT IMPLEMENTED YET - OQL with parameters corresponding to column names (in the query)
*
* @param $sTemplate string The XML template
* @return DisplayBlock The DisplayBlock object, or null if the template is invalid
*/
public static function FromTemplate($sTemplate)
{
$oXml = simplexml_load_string('<root>'.$sTemplate.'</root>', 'SimpleXMLElement', LIBXML_NOCDATA);
if (false)
{
// Debug
echo "<pre>\n";
print_r($oXml);
echo "</pre>\n";
}
if (isset($oXml->title))
{
$sTitle = (string)$oXml->title;
}
if (isset($oXml->type))
{
$sType = (string)$oXml->type;
}
else
{
$sType = 'table';
}
if (!isset($oXml->sql))
{
throw new Exception('Missing tag "sql" in sqlblock');
}
$sQuery = (string)$oXml->sql;
$aColumns = array();
if (isset($oXml->column))
{
foreach ($oXml->column AS $oColumnData)
{
if (!isset($oColumnData->name))
{
throw new Exception("Missing tag 'name' in sqlblock/column");
}
$sName = (string) $oColumnData->name;
if (strlen($sName) == 0)
{
throw new Exception("Empty tag 'name' in sqlblock/column");
}
$aColumns[$sName] = array();
if (isset($oColumnData->label))
{
$sLabel = (string)$oColumnData->label;
if (strlen($sLabel) > 0)
{
$aColumns[$sName]['label'] = Dict::S($sLabel);
}
}
if (isset($oColumnData->drilldown))
{
$sDrillDown = (string)$oColumnData->drilldown;
if (strlen($sDrillDown) > 0)
{
$aColumns[$sName]['drilldown'] = $sDrillDown;
}
}
}
}
$aParams = array();
if (isset($oXml->parameter))
{
foreach ($oXml->parameter AS $oParamData)
{
if (!isset($oParamData->name))
{
throw new Exception("Missing tag 'name' for parameter in sqlblock/column");
}
$sName = (string) $oParamData->name;
if (strlen($sName) == 0)
{
throw new Exception("Empty tag 'name' for parameter in sqlblock/column");
}
if (!isset($oParamData->mapping))
{
throw new Exception("Missing tag 'mapping' for parameter in sqlblock/column");
}
$sMapping = (string) $oParamData->mapping;
if (strlen($sMapping) == 0)
{
throw new Exception("Empty tag 'mapping' for parameter in sqlblock/column");
}
if (isset($oParamData->type))
{
$sParamType = $oParamData->type;
}
else
{
$sParamType = 'context';
}
$aParams[$sName] = array('mapping' => $sMapping, 'type' => $sParamType);
}
}
return new SqlBlock($sQuery, $aColumns, $sTitle, $sType, $aParams);
}
/**
* Applies the defined parameters into the SQL query
* @return string the SQL query to execute
*/
public function BuildQuery()
{
$oAppContext = new ApplicationContext();
$sQuery = $this->m_sQuery;
$sQuery = str_replace('$DB_PREFIX$', MetaModel::GetConfig()->GetDBSubname(), $sQuery); // put the tables DB prefix (if any)
foreach($this->m_aParams as $sName => $aParam)
{
if ($aParam['type'] == 'context')
{
$sSearchPattern = '/\$CONDITION\('.$sName.',([^\)]+)\)\$/';
$value = $oAppContext->GetCurrentValue($aParam['mapping']);
if (empty($value))
{
$sSQLExpr = '(1)';
}
else
{
// Special case for managing the hierarchy of organizations
if (($aParam['mapping'] == 'org_id') && ( MetaModel::IsValidClass('Organization')))
{
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
if ($sHierarchicalKeyCode != false)
{
// organizations are in hierarchy... gather all the orgs below the given one...
$sOQL = "SELECT Organization AS node JOIN Organization AS root ON node.$sHierarchicalKeyCode BELOW root.id WHERE root.id = :value";
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array(), array('value' => $value));
$aOrgIds = array();
while($oOrg = $oSet->Fetch())
{
$aOrgIds[]= $oOrg->GetKey();
}
$sSQLExpr = '($1 IN('.implode(',', $aOrgIds).'))';
}
else
{
$sSQLExpr = '($1 = '.CMDBSource::Quote($value).')';
}
}
else
{
$sSQLExpr = '($1 = '.CMDBSource::Quote($value).')';
}
}
$sQuery = preg_replace($sSearchPattern, $sSQLExpr, $sQuery);
}
}
return $sQuery;
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
if (empty($aExtraParams['currentId']))
{
$sId = 'sqlblock_'.$oPage->GetUniqueId(); // Works only if the page is not an Ajax one !
}
else
{
$sId = $aExtraParams['currentId'];
}
// $oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId));
$sQuery = $this->BuildQuery();
$res = CMDBSource::Query($sQuery);
$aQueryCols = CMDBSource::GetColumns($res);
// Prepare column definitions (check + give default values)
//
foreach($this->m_aColumns as $sName => $aColumnData)
{
if (!in_array($sName, $aQueryCols))
{
throw new Exception("Unknown column name '$sName' in sqlblock column");
}
if (!isset($aColumnData['label']))
{
$this->m_aColumns[$sName]['label'] = $sName;
}
if (isset($aColumnData['drilldown']) && !empty($aColumnData['drilldown']))
{
// Check if the OQL is valid
try
{
$this->m_aColumns[$sName]['filter'] = DBObjectSearch::FromOQL($aColumnData['drilldown']);
}
catch(OQLException $e)
{
unset($aColumnData['drilldown']);
}
}
}
if (strlen($this->m_sTitle) > 0)
{
$oPage->add("<h2>".Dict::S($this->m_sTitle)."</h2>\n");
}
switch ($this->m_sType)
{
case 'bars':
case 'pie':
$aColNames = array_keys($this->m_aColumns);
$sXColName = $aColNames[0];
$sYColName = $aColNames[1];
$aData = array();
$aRows = array();
while($aRow = CMDBSource::FetchArray($res))
{
$aData[$aRow[$sXColName]] = $aRow[$sYColName];
$aRows[$aRow[$sXColName]] = $aRow;
}
$this->RenderChart($oPage, $sId, $aData, $this->m_aColumns[$sYColName]['drilldown'], $aRows);
break;
default:
case 'table':
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink();
if (!empty($sContext))
{
$sContext = '&'.$sContext;
}
$aDisplayConfig = array();
foreach($this->m_aColumns as $sName => $aColumnData)
{
$aDisplayConfig[$sName] = array('label' => $aColumnData['label'], 'description' => '');
}
$aDisplayData = array();
while($aRow = CMDBSource::FetchArray($res))
{
$aSQLColNames = array_keys($aRow);
$aDisplayRow = array();
foreach($this->m_aColumns as $sName => $aColumnData)
{
if (isset($aColumnData['filter']))
{
$sFilter = $aColumnData['drilldown'];
$sClass = $aColumnData['filter']->GetClass();
$sFilter = str_replace('SELECT '.$sClass, '', $sFilter);
foreach($aSQLColNames as $sColName)
{
$sFilter = str_replace(':'.$sColName, "'".addslashes( $aRow[$sColName] )."'", $sFilter);
}
$sURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_oql&search_form=0&oql_class='.$sClass.'&oql_clause='.urlencode($sFilter).'&format=html'.$sContext;
$aDisplayRow[$sName] = '<a href="'.$sURL.'">'.$aRow[$sName]."</a>";
}
else
{
$aDisplayRow[$sName] = $aRow[$sName];
}
}
$aDisplayData[] = $aDisplayRow;
}
$oPage->table($aDisplayConfig, $aDisplayData);
break;
}
}
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
{
$sHtml = '';
return $sHtml;
}
protected function RenderChart($oPage, $sId, $aValues, $sDrillDown = '', $aRows = array())
{
// 1- Compute Open Flash Chart data
//
$aValueKeys = array();
$index = 0;
if ((count($aValues) > 0) && ($sDrillDown != ''))
{
$oFilter = DBObjectSearch::FromOQL($sDrillDown);
$sClass = $oFilter->GetClass();
$sOQLClause = str_replace('SELECT '.$sClass, '', $sDrillDown);
$aSQLColNames = array_keys(current($aRows)); // Read the list of columns from the current (i.e. first) element of the array
$oAppContext = new ApplicationContext();
$sURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_oql&search_form=0&oql_class='.$sClass.'&format=html&'.$oAppContext->GetForLink().'&oql_clause=';
}
$aURLs = array();
foreach($aValues as $key => $value)
{
// Make sure that values are integers (so that max() will work....)
// and build an array of STRING with the keys (numeric keys are transformed into string by PHP :-(
$aValues[$key] = (int)$value;
$aValueKeys[] = (string)$key;
// Build the custom query for the 'drill down' on each element
if ($sDrillDown != '')
{
$sFilter = $sOQLClause;
foreach($aSQLColNames as $sColName)
{
$sFilter = str_replace(':'.$sColName, "'".addslashes( $aRows[$key][$sColName] )."'", $sFilter);
$aURLs[$index] = $sURL.urlencode($sFilter);
}
}
$index++;
}
$oChart = new open_flash_chart();
if ($this->m_sType == 'bars')
{
$oChartElement = new bar_glass();
if (count($aValues) > 0)
{
$maxValue = max($aValues);
}
else
{
$maxValue = 1;
}
$oYAxis = new y_axis();
$aMagicValues = array(1,2,5,10);
$iMultiplier = 1;
$index = 0;
$iTop = $aMagicValues[$index % count($aMagicValues)]*$iMultiplier;
while($maxValue > $iTop)
{
$index++;
$iTop = $aMagicValues[$index % count($aMagicValues)]*$iMultiplier;
if (($index % count($aMagicValues)) == 0)
{
$iMultiplier = $iMultiplier * 10;
}
}
//echo "oYAxis->set_range(0, $iTop, $iMultiplier);\n";
$oYAxis->set_range(0, $iTop, $iMultiplier);
$oChart->set_y_axis( $oYAxis );
$aBarValues = array();
foreach($aValues as $iValue)
{
$oBarValue = new bar_value($iValue);
$oBarValue->on_click("ofc_drilldown_{$sId}");
$aBarValues[] = $oBarValue;
}
$oChartElement->set_values($aBarValues);
//$oChartElement->set_values(array_values($aValues));
$oXAxis = new x_axis();
$oXLabels = new x_axis_labels();
// set them vertical
$oXLabels->set_vertical();
// set the label text
$oXLabels->set_labels($aValueKeys);
// Add the X Axis Labels to the X Axis
$oXAxis->set_labels( $oXLabels );
$oChart->set_x_axis( $oXAxis );
}
else
{
$oChartElement = new pie();
$oChartElement->set_start_angle( 35 );
$oChartElement->set_animate( true );
$oChartElement->set_tooltip( '#label# - #val# (#percent#)' );
$oChartElement->set_colours( array('#FF8A00', '#909980', '#2C2B33', '#CCC08D', '#596664') );
$aData = array();
foreach($aValues as $sValue => $iValue)
{
$oPieValue = new pie_value($iValue, $sValue); //@@ BUG: not passed via ajax !!!
$oPieValue->on_click("ofc_drilldown_{$sId}");
$aData[] = $oPieValue;
}
$oChartElement->set_values( $aData );
$oChart->x_axis = null;
}
// Title given in HTML
//$oTitle = new title($this->m_sTitle);
//$oChart->set_title($oTitle);
$oChart->set_bg_colour('#FFFFFF');
$oChart->add_element( $oChartElement );
$sData = $oChart->toPrettyString();
$sData = json_encode($sData);
// 2- Declare the Javascript function that will render the chart data\
//
$oPage->add_script(
<<< EOF
function ofc_get_data_{$sId}()
{
return $sData;
}
EOF
);
if (count($aURLs) > 0)
{
$sURLList = '';
foreach($aURLs as $index => $sURL)
{
$sURLList .= "\taURLs[$index] = '".addslashes($sURL)."';\n";
}
$oPage->add_script(
<<< EOF
function ofc_drilldown_{$sId}(index)
{
var aURLs = new Array();
{$sURLList}
var sURL = aURLs[index];
window.location.href = sURL; // Navigate !
}
EOF
);
}
// 3- Insert the Open Flash chart
//
$oPage->add("<div id=\"$sId\"><div>\n");
$oPage->add_ready_script(
<<<EOF
swfobject.embedSWF( "../images/open-flash-chart.swf",
"{$sId}",
"100%", "300","9.0.0",
"expressInstall.swf",
{"get-data":"ofc_get_data_{$sId}", "id":"{$sId}"},
{'wmode': 'transparent'}
);
EOF
);
}
}
?>

View File

@@ -25,24 +25,7 @@
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
session_name('itop-'.md5(APPROOT));
session_start();
if (isset($_REQUEST['switch_env']))
{
$sEnv = $_REQUEST['switch_env'];
$_SESSION['itop_env'] = $sEnv;
// TODO: reset the credentials as well ??
}
else if (isset($_SESSION['itop_env']))
{
$sEnv = $_SESSION['itop_env'];
}
else
{
$sEnv = ITOP_DEFAULT_ENV;
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
}
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
MetaModel::Startup($sConfigFile);
MetaModel::Startup(ITOP_CONFIG_FILE);
?>

View File

@@ -35,15 +35,7 @@ class DisplayTemplate
public function __construct($sTemplate)
{
$this->m_aTags = array (
'itopblock',
'itopcheck',
'itoptabs',
'itoptab',
'itoptoggle',
'itopstring',
'sqlblock'
);
$this->m_aTags = array('itopblock', 'itopcheck', 'itoptabs', 'itoptab', 'itoptoggle', 'itopstring');
$this->m_sTemplate = $sTemplate;
}
@@ -169,7 +161,7 @@ class DisplayTemplate
$oPage->AddTabContainer('Tabs_'.$iTabContainerCount);
$oPage->SetCurrentTabContainer('Tabs_'.$iTabContainerCount);
$iTabContainerCount++;
//$oPage->p('Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
//$oPage->p('Content:<pre>'.htmlentities($sContent).'</pre>');
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
$oPage->SetCurrentTabContainer('');
@@ -193,7 +185,7 @@ class DisplayTemplate
$oPage->SetCurrentTab(Dict::S(str_replace('_', ' ', $aAttributes['name'])));
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent).'</pre>');
$oPage->SetCurrentTab('');
break;
@@ -203,7 +195,7 @@ class DisplayTemplate
$oPage->StartCollapsibleSection(Dict::S($sName), $bOpen);
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent).'</pre>');
$oPage->EndCollapsibleSection();
break;
@@ -211,11 +203,6 @@ class DisplayTemplate
$oPage->add(Dict::S($sContent));
break;
case 'sqlblock':
$oBlock = SqlBlock::FromTemplate($sContent);
$oBlock->RenderContent($oPage);
break;
case 'itopblock': // No longer used, handled by DisplayBlock::FromTemplate see above
$oPage->add("<!-- Application Error: should be handled by DisplayBlock::FromTemplate -->");
break;
@@ -240,6 +227,7 @@ class DisplayTemplate
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = \'$class$\'</itopblock>
</div>
<img src="../../images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
<itopblock blockclass="DisplayBlock" asynchronous="false" type="bare_details" encoding="text/oql">SELECT NetworkDevice AS d WHERE d.id = $id$</itopblock>
<itoptabs>
<itoptab name="Interfaces">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Interface AS i WHERE i.device_id = $id$</itopblock>
@@ -253,150 +241,13 @@ class DisplayTemplate
</itoptabs>';
$oPage = new iTopWebPage('Unit Test');
//$oPage->add("Template content: <pre>".htmlentities($sTemplate, ENT_QUOTES, 'UTF-8')."</pre>\n");
//$oPage->add("Template content: <pre>".htmlentities($sTemplate)."</pre>\n");
$oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, array('class'=>'Network device','pkey'=> 271, 'name' => 'deliversw01.mecanorama.fr', 'org_id' => 3));
$oPage->output();
}
}
/**
* Special type of template for displaying the details of an object
* On top of the defaut 'blocks' managed by the parent class, the following placeholders
* are available in such a template:
* $attribute_code$ An attribute of the object (in edit mode this is the input for the attribute)
* $attribute_code->label()$ The label of an attribute
* $PlugIn:plugInClass->properties()$ The ouput of OnDisplayProperties of the specified plugInClass
*/
class ObjectDetailsTemplate extends DisplayTemplate
{
public function __construct($sTemplate, $oObj, $sFormPrefix = '')
{
parent::__construct($sTemplate);
$this->m_oObj = $oObj;
$this->m_sPrefix = $sFormPrefix;
}
public function Render(WebPage $oPage, $aParams = array(), $bEditMode = false)
{
$sStateAttCode = MetaModel :: GetStateAttributeCode(get_class($this->m_oObj));
$aTemplateFields = array();
preg_match_all('/\\$this->([a-z0-9_]+)\\$/', $this->m_sTemplate, $aMatches);
$aTemplateFields = $aMatches[1];
preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches);
$aTemplateFields = array_merge($aTemplateFields, $aMatches[1]);
$aFieldsComments = (isset($aParams['fieldsComments'])) ? $aParams['fieldsComments'] : array();
$aFieldsMap = array();
$sClass = get_class($this->m_oObj);
// Renders the fields used in the template
foreach(MetaModel::ListAttributeDefs(get_class($this->m_oObj)) as $sAttCode => $oAttDef)
{
$aParams['this->label('.$sAttCode.')'] = $oAttDef->GetLabel();
$aParams['this->comments('.$sAttCode.')'] = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '';
$iInputId = '2_'.$sAttCode; // TODO: generate a real/unique prefix...
if (in_array($sAttCode, $aTemplateFields))
{
if ($this->m_oObj->IsNew())
{
$iFlags = $this->m_oObj->GetInitialStateAttributeFlags($sAttCode);
}
else
{
$iFlags = $this->m_oObj->GetAttributeFlags($sAttCode);
}
if (($iFlags & OPT_ATT_MANDATORY) && $this->m_oObj->IsNew())
{
$iFlags = $iFlags & ~OPT_ATT_READONLY; // Mandatory fields cannot be read-only when creating an object
}
if ((!$oAttDef->IsWritable()) || ($sStateAttCode == $sAttCode))
{
$iFlags = $iFlags | OPT_ATT_READONLY;
}
if ($iFlags & OPT_ATT_HIDDEN)
{
$aParams['this->label('.$sAttCode.')'] = '';
$aParams['this->field('.$sAttCode.')'] = '';
$aParams['this->comments('.$sAttCode.')'] = '';
$aParams['this->'.$sAttCode] = '';
}
else
{
if ($bEditMode && ($iFlags & (OPT_ATT_READONLY|OPT_ATT_SLAVE)))
{
// Check if the attribute is not read-only because of a synchro...
$aReasons = array();
$sSynchroIcon = '';
if ($iFlags & OPT_ATT_SLAVE)
{
$iSynchroFlags = $this->m_oObj->GetSynchroReplicaFlags($sAttCode, $aReasons);
$sSynchroIcon = "&nbsp;<img id=\"synchro_$sInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
$sTip = '';
foreach($aReasons as $aRow)
{
$sTip .= "<p>Synchronized with {$aRow['name']} - {$aRow['description']}</p>";
}
$oPage->add_ready_script("$('#synchro_$iInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
}
// Attribute is read-only
$sHTMLValue = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetAsHTML($sAttCode);
$sHTMLValue .= '<input type="hidden" id="'.$iInputId.'" name="attr_'.$sAttCode.'" value="'.htmlentities($this->m_oObj->Get($sAttCode), ENT_QUOTES, 'UTF-8').'"/></span>';
$aFieldsMap[$sAttCode] = $iInputId;
$aParams['this->comments('.$sAttCode.')'] = $sSynchroIcon;
}
if ($bEditMode && !($iFlags & OPT_ATT_READONLY)) //TODO: check the data synchro status...
{
$aParams['this->field('.$sAttCode.')'] = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,
$this->m_oObj->Get($sAttCode),
$this->m_oObj->GetEditValue($sAttCode),
$iInputId, // InputID
'',
$iFlags,
array('this' => $this->m_oObj) // aArgs
).'</span>';
$aFieldsMap[$sAttCode] = $iInputId;
}
else
{
$aParams['this->field('.$sAttCode.')'] = $this->m_oObj->GetAsHTML($sAttCode);
}
$aParams['this->'.$sAttCode] = "<table class=\"field\"><tr><td class=\"label\">".$aParams['this->label('.$sAttCode.')'].":</td><td>".$aParams['this->field('.$sAttCode.')']."</td><td>".$aParams['this->comments('.$sAttCode.')']."</td></tr></table>";
}
}
}
// Renders the PlugIns used in the template
preg_match_all('/\\$PlugIn:([A-Za-z0-9_]+)->properties\\(\\)\\$/', $this->m_sTemplate, $aMatches);
$aPlugInProperties = $aMatches[1];
foreach($aPlugInProperties as $sPlugInClass)
{
$oInstance = MetaModel::GetPlugins('iApplicationUIExtension', $sPlugInClass);
if ($oInstance != null) // Safety check...
{
$offset = $oPage->start_capture();
$oInstance->OnDisplayProperties($this->m_oObj, $oPage, $bEditMode);
$sContent = $oPage->end_capture($offset);
$aParams["PlugIn:{$sPlugInClass}->properties()"]= $sContent;
}
else
{
$aParams["PlugIn:{$sPlugInClass}->properties()"]= "Missing PlugIn: $sPlugInClass";
}
}
$offset = $oPage->start_capture();
parent::Render($oPage, $aParams);
$sContent = $oPage->end_capture($offset);
// Remove empty table rows in case some attributes are hidden...
$sContent = preg_replace('/<tr[^>]*>\s*(<td[^>]*>\s*<\\/td>)+\s*<\\/tr>/im', '', $sContent);
$oPage->add($sContent);
return $aFieldsMap;
}
}
//DisplayTemplate::UnitTest();
?>

View File

@@ -1,6 +1,15 @@
<div style="width:100%;background: #fff url(../images/welcome.jpg) top left no-repeat;">
<div style="width:100%;background: url(../images/welcome.jpg) top left no-repeat;">
<style>
.welcome_popup_cell {
.dashboard {
vertical-align:top;
width:50%;
border:0px solid #000;
background-color:#F9F9F1;
padding:10px;
text-align:left;
font-size:10pt;
}
.dashboard2 {
vertical-align:top;
width:50%;
border:0px solid #000;
@@ -8,7 +17,15 @@ border:0px solid #000;
padding:5px;
text-align:left;
}
tr td.welcome_popup_cell, tr td.welcome_popup_cell ul {
td.dashboard li {
margin-top: 5px;
display: list-item;
}
td div.display_block {
padding:0;
}
tr td.dashboard2, tr td.dashboard2 ul {
font-size:10pt;
}
</style>
@@ -18,10 +35,10 @@ font-size:10pt;
<p></p>
<table border="0" style="padding:10px;border-spacing: 10px;width:100%">
<tr>
<td class="welcome_popup_cell">
<td class="dashboard2">
<itopstring>UI:WelcomeMenu:LeftBlock</itopstring>
</td>
<td class="welcome_popup_cell">
<td class="dashboard2">
<itopstring>UI:WelcomeMenu:RightBlock</itopstring>
</td>
</tr>

View File

@@ -38,11 +38,11 @@ class privUITransaction
// Strictly speaking, the two lines below should be grouped together
// by a critical section
// sem_acquire($rSemIdentified);
$id = str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
$id = 1 + count($_SESSION['transactions']);
$_SESSION['transactions'][$id] = true;
// sem_release($rSemIdentified);
return (string)$id;
return sprintf("%d", $id);
}
/**

View File

@@ -63,36 +63,27 @@ require_once(APPROOT.'/application/displayblock.class.inc.php');
class UIExtKeyWidget
{
protected $iId;
protected $sTargetClass;
protected static $iWidgetIndex = 0;
protected $sAttCode;
protected $bSearchMode;
protected $sNameSuffix;
protected $iId;
protected $sTitle;
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
static public function DisplayFromAttCode($oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false)
public function __construct($sAttCode, $sClass, $sTitle, $aAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$sTargetClass = $oAttDef->GetTargetClass();
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
$bAllowTargetCreation = $oAttDef->AllowTargetCreation();
if (!$bSearchMode)
{
$sDisplayStyle = $oAttDef->GetDisplayStyle();
}
else
{
$sDisplayStyle = 'select'; // In search mode, always use a drop-down list
}
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode);
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix, $aArgs, null, $sDisplayStyle);
}
public function __construct($sTargetClass, $iInputId, $sAttCode = '', $bSearchMode = false)
{
$this->sTargetClass = $sTargetClass;
$this->iId = $iInputId;
self::$iWidgetIndex++;
$this->sAttCode = $sAttCode;
$this->bSearchMode = $bSearchMode;
$this->sClass = $sClass;
$this->oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$this->sNameSuffix = $sNameSuffix;
$this->iId = $iInputId;
$this->aAllowedValues = $aAllowedValues;
$this->value = $value;
$this->sFieldPrefix = $sFieldPrefix;
$this->sTargetClass = $this->oAttDef->GetTargetClass();
$this->sTitle = $sTitle;
$this->sFormPrefix = $sFormPrefix;
$this->bMandatory = $bMandatory;
}
/**
@@ -101,203 +92,100 @@ class UIExtKeyWidget
* @param Hash $aArgs Extra context arguments
* @return string The HTML fragment to be inserted into the page
*/
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = null, $sDisplayStyle = 'select')
public function Display(WebPage $oPage, $aArgs = array())
{
if (!is_null($bSearchMode))
{
$this->bSearchMode = $bSearchMode;
}
$sTitle = addslashes($sTitle);
$oPage->add_linked_script('../js/extkeywidget.js');
$oPage->add_linked_script('../js/forms-json-utils.js');
$bCreate = (!$this->bSearchMode) && (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
$bExtensions = true;
$bCreate = (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $this->oAttDef->AllowTargetCreation());
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
$sHTMLValue = "<span style=\"white-space:nowrap\">"; // no wrap
$sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL());
if($this->bSearchMode)
if (count($this->aAllowedValues) < $this->oAttDef->GetMaximumComboLength())
{
$sWizHelper = 'null';
$sWizHelperJSON = "''";
$sJSSearchMode = 'true';
}
else
{
if (isset($aArgs['wizHelper']))
{
$sWizHelper = $aArgs['wizHelper'];
}
else
{
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
}
$sWizHelperJSON = $sWizHelper.'.UpdateWizardToJSON()';
$sJSSearchMode = 'false';
}
if (is_null($oAllowedValues))
{
throw new Exception('Implementation: null value for allowed values definition');
}
elseif ($oAllowedValues->Count() < $iMaxComboLength)
{
// Discrete list of values, use a SELECT or RADIO buttons depending on the config
switch($sDisplayStyle)
{
case 'radio':
case 'radio_horizontal':
case 'radio_vertical':
$sValidationField = "<span id=\"v_{$this->iId}\"></span>";
$sHTMLValue = '';
$bVertical = ($sDisplayStyle != 'radio_horizontal');
$bExtensions = false;
$oAllowedValues->Rewind();
$aAllowedValues = array();
while($oObj = $oAllowedValues->Fetch())
{
$aAllowedValues[$oObj->GetKey()] = $oObj->GetName();
}
$sHTMLValue = $oPage->GetRadioButtons($aAllowedValues, $value, $this->iId, "{$sAttrFieldPrefix}{$sFieldName}", $bMandatory, $bVertical, $sValidationField);
$aEventsList[] ='change';
break;
// Few choices, use a normal 'select'
$sSelectMode = 'true';
$sHelpText = $this->oAttDef->GetHelpOnEdition();
case 'select':
default:
$sSelectMode = 'true';
$sHelpText = ''; //$this->oAttDef->GetHelpOnEdition();
$sHTMLValue = "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n";
if ($this->bSearchMode)
// In case there are no valid values, the select will be empty, thus blocking the user from validating the form
$sHTMLValue = "<select title=\"$sHelpText\" name=\"attr_{$this->sFieldPrefix}{$this->sAttCode}{$this->sNameSuffix}\" id=\"$this->iId\">\n";
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n";
foreach($this->aAllowedValues as $key => $display_value)
{
if ((count($this->aAllowedValues) == 1) && ($this->bMandatory == 'true') )
{
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : Dict::S('UI:SearchValue:Any');
$sHTMLValue .= "<option value=\"\">$sDisplayValue</option>\n";
// When there is only once choice, select it by default
$sSelected = ' selected';
}
else
{
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n";
$sSelected = ($this->value == $key) ? ' selected' : '';
}
$oAllowedValues->Rewind();
while($oObj = $oAllowedValues->Fetch())
{
$key = $oObj->GetKey();
$display_value = $oObj->GetName();
if (($oAllowedValues->Count() == 1) && ($bMandatory == 'true') )
{
// When there is only once choice, select it by default
$sSelected = ' selected';
}
else
{
$sSelected = ($value == $key) ? ' selected' : '';
}
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
}
$sHTMLValue .= "</select>\n";
$oPage->add_ready_script(
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
}
$sHTMLValue .= "</select>\n";
$oPage->add_ready_script(
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sClass}', '{$this->sAttCode}', '{$this->sNameSuffix}', $sSelectMode, oWizardHelper{$this->sFormPrefix});
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
$('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
EOF
);
} // Switch
);
}
else
{
// Too many choices, use an autocomplete
$sSelectMode = 'false';
if (is_null($value) || ($value == 0)) // Null values are displayed as ''
if ($this->oAttDef->IsNull($this->value)) // Null values are displayed as ''
{
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : '';
$sDisplayValue = '';
}
else
{
$sDisplayValue = $this->GetObjectName($value);
$sDisplayValue = $this->GetObjectName($this->value);
}
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 3; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
$iFieldSize = isset($aArgs['iFieldSize']) ? $aArgs['iFieldSize'] : 30; //@@@ $this->oAttDef->GetMaxSize();
$sFormPrefix = $this->sFormPrefix;
$iMinChars = $this->oAttDef->GetMinAutoCompleteChars();
$iFieldSize = $this->oAttDef->GetMaxSize();
// the input for the auto-complete
$sHTMLValue = "<input count=\"".$oAllowedValues->Count()."\" type=\"text\" id=\"label_$this->iId\" size=\"$iFieldSize\" value=\"$sDisplayValue\"/>&nbsp;";
$sHTMLValue .= "<img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif\" onClick=\"oACWidget_{$this->iId}.Search();\"/>&nbsp;";
$sHTMLValue = "<input count=\"".count($this->aAllowedValues)."\" type=\"text\" id=\"label_$this->iId\" size=\"30\" maxlength=\"$iFieldSize\" value=\"$sDisplayValue\"/>&nbsp;";
$sHTMLValue .= "<a class=\"no-arrow\" href=\"javascript:oACWidget_{$this->iId}.Search();\"><img style=\"border:0;vertical-align:middle;\" src=\"../images/mini_search.gif\" /></a>&nbsp;";
// another hidden input to store & pass the object's Id
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"$value\" />\n";
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"attr_{$this->sFieldPrefix}{$this->sAttCode}{$this->sNameSuffix}\" value=\"$this->value\" />\n";
// Scripts to start the autocomplete and bind some events to it
$oPage->add_ready_script(
$oPage->add_ready_script(
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sClass}', '{$this->sAttCode}', '{$this->sNameSuffix}', $sSelectMode, oWizardHelper{$this->sFormPrefix});
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter',bSearchMode:$JSSearchMode, json: function() { return $sWizHelperJSON; } }});
$('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly !
$('#label_$this->iId').autocomplete('./ajax.render.php', { scroll:true, minChars:{$iMinChars}, formatItem:formatItem, autoFill:false, matchContains:true, keyHolder:'#{$this->iId}', extraParams:{operation:'autocomplete', sclass:'{$this->sClass}',attCode:'{$this->sAttCode}'}});
$('#label_$this->iId').blur(function() { $(this).search(); } );
$('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('{$this->iId}', event, data, formatted); } );
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
if ($('#ac_dlg_{$this->iId}').length == 0)
{
$('body').append('<div id="ac_dlg_{$this->iId}"></div>');
}
$('#ac_dlg_$this->iId').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '{$this->sTitle}', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });
EOF
);
$oPage->add_at_the_end($this->GetSearchDialog($oPage)); // To prevent adding forms inside the main form
}
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
if ($bCreate)
{
$sHTMLValue .= "<img id=\"mini_tree_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_tree.gif\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"/>&nbsp;";
$oPage->add_ready_script(
<<<EOF
if ($('#ac_tree_{$this->iId}').length == 0)
{
$('body').append('<div id="ac_tree_{$this->iId}"></div>');
}
EOF
);
}
if ($bCreate && $bExtensions)
{
$sHTMLValue .= "<img id=\"mini_add_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_add.gif\" onClick=\"oACWidget_{$this->iId}.CreateObject();\"/>&nbsp;";
$oPage->add_ready_script(
<<<EOF
if ($('#ajax_{$this->iId}').length == 0)
{
$('body').append('<div id="ajax_{$this->iId}"></div>');
}
EOF
);
}
if ($sDisplayStyle == 'select')
{
$sHTMLValue .= "<span id=\"v_{$this->iId}\"></span>";
$sHTMLValue .= "<a class=\"no-arrow\" href=\"javascript:oACWidget_{$this->iId}.CreateObject();\"><img style=\"border:0;vertical-align:middle;\" src=\"../images/mini_add.gif\" /></a>&nbsp;";
$oPage->add_at_the_end('<div id="ajax_'.$this->iId.'"></div>');
}
$sHTMLValue .= "<span id=\"v_{$this->iId}\"></span>";
$sHTMLValue .= "</span>"; // end of no wrap
return $sHTMLValue;
}
public function GetSearchDialog(WebPage $oPage, $sTitle, $oCurrObject = null)
protected function GetSearchDialog(WebPage $oPage)
{
$sHTML = '<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
$sHTML = '<div id="ac_dlg_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
$aParams = array('query_params' => array('this' => $oCurrObject));
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aParams);
$oFilter = $oSet->GetFilter();
}
else
{
$aParams = array();
$oFilter = new DBObjectSearch($this->sTargetClass);
}
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
$oFilter = new DBObjectSearch($this->sTargetClass);
$oSet = new CMDBObjectSet($oFilter);
$oBlock = new DisplayBlock($oFilter, 'search', false);
$sHTML .= $oBlock->GetDisplay($oPage, $this->iId, array('open' => true, 'currentId' => $this->iId));
$sHTML .= "<form id=\"fr_{$this->iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoOk();\">\n";
$sHTML .= "<div id=\"dr_{$this->iId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
@@ -305,19 +193,13 @@ EOF
$sHTML .= "</div>\n";
$sHTML .= "<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_dlg_{$this->iId}').dialog('close');\">&nbsp;&nbsp;";
$sHTML .= "<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoOk();\">";
$sHTML .= "<input type=\"hidden\" id=\"count_{$this->iId}\" value=\"0\">";
$sHTML .= "</form>\n";
$sHTML .= '</div></div>';
$sHTML .= '</div></div></div>';
$sDialogTitle = addslashes($sTitle);
$oPage->add_ready_script(
<<<EOF
$('#ac_dlg_{$this->iId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });
$('#fs_{$this->iId}').bind('submit.uiAutocomplete', oACWidget_{$this->iId}.DoSearchObjects);
$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);
EOF
);
$oPage->add($sHTML);
$oPage->add_ready_script("$('#fs_{$this->iId}').bind('submit.uiAutocomplete', oACWidget_{$this->iId}.DoSearchObjects);");
$oPage->add_ready_script("$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);");
return $sHTML;
}
/**
@@ -326,51 +208,22 @@ EOF
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
* @param Array $aAlreadyLinkedIds List of IDs of objects of "remote" class already linked, to be filtered out of the search
*/
public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null)
public function SearchObjectsToSelect(WebPage $oP, $sTargetClass = '')
{
if (is_null($sFilter))
if ($sTargetClass != '')
{
throw new Exception('Implementation: null value for allowed values definition');
// assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
$oFilter = new DBObjectSearch($sTargetClass);
}
try
else
{
$oFilter = DBObjectSearch::FromOQL($sFilter);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'list', false, array('query_params' => array('this' => $oObj)));
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'table_id' => 'select_'.$this->sAttCode)); // Don't display the 'Actions' menu on the results
}
catch(MissingQueryArgument $e)
{
// When used in a search form the $this parameter may be missing, in this case return all possible values...
// TODO check if we can improve this behavior...
$sOQL = 'SELECT '.$sRemoteClass;
$oFilter = DBObjectSearch::FromOQL($sOQL);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
//$oBlock = new DisplayBlock($oFilter, 'list', false);
//$oBlock->Display($oP, $this->iId.'_results', array('cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single')); // Don't display the 'Actions' menu on the results
}
}
/**
* Search for objects to be selected
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param string $sFilter The OQL expression used to define/limit limit the scope of possible values
* @param DBObject $oObj The current object for the OQL context
* @param string $sContains The text of the autocomplete to filter the results
*/
public function AutoComplete(WebPage $oP, $sFilter, $oObj = null, $sContains)
{
if (is_null($sFilter))
{
throw new Exception('Implementation: null value for allowed values definition');
}
$oValuesSet = new ValueSetObjects($sFilter, 'friendlyname'); // Bypass GetName() to avoid the encoding by htmlentities
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$aValues = $oValuesSet->GetValues(array('this' => $oObj), $sContains);
foreach($aValues as $sKey => $sFriendlyName)
{
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
// No remote class specified use the one defined in the linkedset
$oFilter = new DBObjectSearch($this->sTargetClass);
}
$oFilter->AddCondition('id', array_keys($this->aAllowedValues), 'IN');
$oSet = new CMDBObjectSet($oFilter);
$oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, $this->iId, array('menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'display_limit' => false)); // Don't display the 'Actions' menu on the results
}
/**
@@ -378,188 +231,41 @@ EOF
*/
public function GetObjectName($iObjId)
{
$aModifierProps = array();
$aModifierProps['UserRightsGetSelectFilter']['bSearchMode'] = $this->bSearchMode;
$oObj = MetaModel::GetObject($this->sTargetClass, $iObjId, false, false, $aModifierProps);
if ($oObj)
{
return $oObj->GetName();
}
else
{
return '';
}
$oObj = MetaModel::GetObject($this->sTargetClass, $iObjId);
return $oObj->GetName();
}
/**
* Get the form to create a new object of the 'target' class
*/
public function GetObjectCreationForm(WebPage $oPage, $oCurrObject)
public function GetObjectCreationForm(WebPage $oPage)
{
// Set all the default values in an object and clone this "default" object
$oNewObj = MetaModel::NewObject($this->sTargetClass);
// 1st - set context values
$oAppContext = new ApplicationContext();
$oAppContext->InitObjectFromContext($oNewObj);
// 2nd set the default values from the constraint on the external key... if any
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
$aParams = array('this' => $oCurrObject);
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aParams);
$aConsts = $oSet->ListConstantFields();
$sClassAlias = $oSet->GetFilter()->GetClassAlias();
if (isset($aConsts[$sClassAlias]))
{
foreach($aConsts[$sClassAlias] as $sAttCode => $value)
{
$oNewObj->Set($sAttCode, $value);
}
}
}
// 3rd - set values from the page argument 'default'
$oNewObj->UpdateObjectFromArg('default');
$sDialogTitle = addslashes($this->sTitle);
$oPage->add('<div id="ac_create_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dcr_'.$this->iId.'">');
$oPage->add("<h1>".MetaModel::GetClassIcon($this->sTargetClass)."&nbsp;".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sTargetClass))."</h1>\n");
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true));
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, null, array(), array('formPrefix' => $this->iId, 'noRelations' => true));
$oPage->add('</div></div></div>');
// $oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: 'auto', autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
$oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
$oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: 'auto', autoOpen: false, modal: true, title: '$this->sTitle'});\n");
$oPage->add_ready_script("$('#dcr_{$this->iId} form').removeAttr('onsubmit');");
$oPage->add_ready_script("$('#dcr_{$this->iId} form').bind('submit.uilinksWizard', oACWidget_{$this->iId}.DoCreateObject);");
}
/**
* Display the hierarchy of the 'target' class
*/
public function DisplayHierarchy(WebPage $oPage, $sFilter, $currValue, $oObj)
{
$sDialogTitle = addslashes(Dict::Format('UI:HierarchyOf_Class', MetaModel::GetName($this->sTargetClass)));
$oPage->add('<div id="dlg_tree_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div style="overflow:auto;background:#fff;margin-bottom:5px;" id="tree_'.$this->iId.'">');
$oPage->add('<table style="width:100%"><tr><td>');
if (is_null($sFilter))
{
throw new Exception('Implementation: null value for allowed values definition');
}
try
{
$oFilter = DBObjectSearch::FromOQL($sFilter);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj));
}
catch(MissingQueryArgument $e)
{
// When used in a search form the $this parameter may be missing, in this case return all possible values...
// TODO check if we can improve this behavior...
$sOQL = 'SELECT '.$this->m_sTargetClass;
$oFilter = DBObjectSearch::FromOQL($sOQL);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter);
}
$sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass);
$this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue);
$oPage->add('</td></tr></table>');
$oPage->add('</div>');
$oPage->add("<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_tree_{$this->iId}').dialog('close');\">&nbsp;&nbsp;");
$oPage->add("<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoHKOk();\">");
$oPage->add('</div></div>');
$oPage->add_ready_script("\$('#tree_$this->iId ul').treeview();\n");
$oPage->add_ready_script("\$('#dlg_tree_$this->iId').dialog({ width: 'auto', height: 'auto', autoOpen: true, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.OnHKResize, close: oACWidget_{$this->iId}.OnHKClose });\n");
}
/**
* Get the form to create a new object of the 'target' class
*/
public function DoCreateObject($oPage)
{
$oObj = MetaModel::NewObject($this->sTargetClass);
$aErrors = $oObj->UpdateObjectFromPostedForm($this->iId);
if (count($aErrors) == 0)
{
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$sUserString = CMDBChange::GetCurrentUserName();
$oMyChange->Set("userinfo", $sUserString);
$iChangeId = $oMyChange->DBInsert();
$oObj->DBInsertTracked($oMyChange);
return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey());
}
else
{
return array('name' => implode(' ', $aErrors), 'id' => 0);
}
}
function DumpTree($oP, $oSet, $sParentAttCode, $currValue)
{
$aTree = array();
$aNodes = array();
while($oObj = $oSet->Fetch())
{
$iParentId = $oObj->Get($sParentAttCode);
if (!isset($aTree[$iParentId]))
{
$aTree[$iParentId] = array();
}
$aTree[$iParentId][$oObj->GetKey()] = $oObj->GetName();
$aNodes[$oObj->GetKey()] = $oObj;
}
$aParents = array_keys($aTree);
$aRoots = array();
foreach($aParents as $id)
{
if (!array_key_exists($id, $aNodes))
{
$aRoots[] = $id;
}
}
foreach($aRoots as $iRootId)
{
$this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue);
}
}
$oObj->UpdateObject($this->sFormPrefix.$this->iId);
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$sUserString = CMDBChange::GetCurrentUserName();
$oMyChange->Set("userinfo", $sUserString);
$iChangeId = $oMyChange->DBInsert();
$oObj->DBInsertTracked($oMyChange);
function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue)
{
$bSelect = true;
$bMultiple = false;
$sSelect = '';
if (array_key_exists($iRootId, $aTree))
{
$aSortedRoots = $aTree[$iRootId];
asort($aSortedRoots);
$oP->add("<ul>\n");
foreach($aSortedRoots as $id => $sName)
{
if ($bSelect)
{
$sChecked = ($aNodes[$id]->GetKey() == $currValue) ? 'checked' : '';
if ($bMultiple)
{
$sSelect = '<input type="checkbox" value="'.$aNodes[$id]->GetKey().'" name="selectObject[]" '.$sChecked.'>&nbsp;';
}
else
{
$sSelect = '<input type="radio" value="'.$aNodes[$id]->GetKey().'" name="selectObject" '.$sChecked.'>&nbsp;';
}
}
$oP->add('<li>'.$sSelect.$aNodes[$id]->GetHyperlink());
$this->DumpNodes($oP, $id, $aTree, $aNodes, $currValue);
$oP->add("</li>\n");
}
$oP->add("</ul>\n");
}
return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey());
//return array('name' => 'test', 'id' => '42');
}
}
?>

View File

@@ -61,14 +61,14 @@ class UIHTMLEditorWidget
$sHelpText = $this->m_sHelpText;
$sValidationField = $this->m_sValidationField;
$sHtmlValue = "<table><tr><td><textarea class=\"htmlEditor\" title=\"$sHelpText\" name=\"attr_{$this->m_sFieldPrefix}{$sCode}\" rows=\"10\" cols=\"10\" id=\"$iId\">$sValue</textarea></td><td>$sValidationField</td></tr></table>";
$sHtmlValue = "<table><tr><td><textarea class=\"htmlEditor\" title=\"$sHelpText\" name=\"attr_{$this->m_sFieldPrefix}{$sCode}\" rows=\"14\" cols=\"110\" id=\"$iId\">$sValue</textarea></td><td>$sValidationField</td></tr></table>";
// Replace the text area with CKEditor
// To change the default settings of the editor,
// a) edit the file /js/ckeditor/config.js
// b) or override some of the configuration settings, using the second parameter of ckeditor()
$sLanguage = strtolower(trim(UserRights::GetUserLanguage()));
$oPage->add_ready_script("$('#$iId').ckeditor(function() { /* callback code */ }, { language : '$sLanguage' , contentsLanguage : '$sLanguage', extraPlugins: 'disabler' });"); // Transform $iId into a CKEdit
$oPage->add_ready_script("$('#$iId').ckeditor(function() { /* callback code */ }, { language : '$sLanguage' , contentsLanguage : '$sLanguage' });"); // Transform $iId into a CKEdit
// Please read...
// ValidateCKEditField triggers a timer... calling itself indefinitely
@@ -78,8 +78,7 @@ class UIHTMLEditorWidget
// The most relevant solution would be to implement a plugin to CKEdit, and handle the internal events like: setData, insertHtml, insertElement, loadSnapshot, key, afterUndo, afterRedo
// Could also be bound to 'instanceReady.ckeditor'
$oPage->add_ready_script("$('#$iId').bind('validate', function(evt, sFormId) { return ValidateCKEditField('$iId', '', {$this->m_sMandatory}, sFormId, '') } );\n");
$oPage->add_ready_script("$('#$iId').bind('update', function() { BlockField('cke_$iId', $('#$iId').attr('disabled')); } );\n");
$oPage->add_ready_script("$('#$iId').bind('validate', function(evt, sFormId) { return ValidateCKEditField('$iId', '', {$this->m_sMandatory}, sFormId, '') } );");
return $sHtmlValue;
}

View File

@@ -34,7 +34,6 @@ class UILinksWidget
protected $m_iInputId;
protected $m_aAttributes;
protected $m_sExtKeyToRemote;
protected $m_sExtKeyToMe;
protected $m_sLinkedClass;
protected $m_sRemoteClass;
protected $m_bDuplicatesAllowed;
@@ -51,7 +50,6 @@ class UILinksWidget
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sAttCode);
$this->m_sLinkedClass = $oAttDef->GetLinkedClass();
$this->m_sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
$this->m_sExtKeyToMe = $oAttDef->GetExtKeyToMe();
$oLinkingAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $this->m_sExtKeyToRemote);
$this->m_sRemoteClass = $oLinkingAttDef->GetTargetClass();
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
@@ -62,14 +60,13 @@ class UILinksWidget
$this->m_aTableConfig = array();
$this->m_aTableConfig['form::checkbox'] = array( 'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+'));
foreach(MetaModel::FlattenZList(MetaModel::GetZListItems($this->m_sLinkedClass, 'list')) as $sAttCode)
foreach(MetaModel::ListAttributeDefs($this->m_sLinkedClass) as $sAttCode=>$oAttDef)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sAttCode);
if ($sStateAttCode == $sAttCode)
{
// State attribute is always hidden from the UI
}
else if ($oAttDef->IsWritable() && ($sAttCode != $sExtKeyToMe) && ($sAttCode != $this->m_sExtKeyToRemote) && ($sAttCode != 'finalclass'))
else if (!$oAttDef->IsExternalField() && ($sAttCode != $sExtKeyToMe) && ($sAttCode != $this->m_sExtKeyToRemote) && ($sAttCode != 'finalclass'))
{
$iFlags = MetaModel::GetAttributeFlags($this->m_sLinkedClass, $sDefaultState, $sAttCode);
if ( !($iFlags & OPT_ATT_HIDDEN) && !($iFlags & OPT_ATT_READONLY) )
@@ -100,98 +97,43 @@ class UILinksWidget
* @param Hash $aArgs Extra context arguments
* @return string The HTML fragment of the one-row form
*/
protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId = null, $aArgs = array(), $oCurrentObj )
protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId = null, $aArgs = array() )
{
$sPrefix = "$this->m_sAttCode{$this->m_sNameSuffix}";
$aRow = array();
$aFieldsMap = array();
if(is_object($linkObjOrId))
{
$key = $linkObjOrId->GetKey();
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
$sPrefix .= "[$key][";
$sNameSuffix = "]"; // To make a tabular form
$aArgs['prefix'] = $sPrefix;
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$key}";
$aArgs['this'] = $linkObjOrId;
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$key\">";
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"attr_{$sPrefix}id{$sNameSuffix}\" value=\"$key\">";
foreach($this->m_aEditableFields as $sFieldCode)
{
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId->GetKey().']';
$sSafeId = self::MakeID($sFieldId);
$sSafeId = str_replace(array('[',']','-'), '_', $sFieldId);
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $linkObjOrId->Get($sFieldCode), '' /* DisplayValue */, $sSafeId, $sNameSuffix, 0, $aArgs);
$aFieldsMap[$sFieldCode] = $sSafeId;
}
$sState = $linkObjOrId->GetState();
}
else
{
// form for creating a new record
$sPrefix .= "[$linkObjOrId][";
$iRemoteObjKey = -$linkObjOrId;
$oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass);
$oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, -$linkObjOrId);
$oNewLinkObj->Set($this->m_sExtKeyToRemote, $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields
$sNameSuffix = "]"; // To make a tabular form
$aArgs['prefix'] = $sPrefix;
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}_".(-$linkObjOrId);
$aArgs['this'] = $oNewLinkObj;
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$linkObjOrId\">";
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"attr_{$sPrefix}id{$sNameSuffix}\" value=\"\">";
foreach($this->m_aEditableFields as $sFieldCode)
{
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId.']';
$sSafeId = self::MakeID($sFieldId);
$sSafeId = str_replace(array('[',']','-'), '_', $sFieldId);
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $oNewLinkObj->Get($sFieldCode) /* TO DO/ call GetDefaultValue($oObject->ToArgs()) */, '' /* DisplayValue */, $sSafeId /* id */, $sNameSuffix, 0, $aArgs);
$aFieldsMap[$sFieldCode] = $sSafeId;
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, '' /* TO DO/ call GetDefaultValue($oObject->ToArgs()) */, '' /* DisplayValue */, $sSafeId /* id */, $sNameSuffix, 0, $aArgs);
}
$sState = '';
$oP->add_script(
<<<EOF
$(".date-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd',
constrainInput: false,
changeMonth: true,
changeYear: true
});
$(".datetime-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd 00:00:00',
constrainInput: false,
changeMonth: true,
changeYear: true
});
EOF
);
}
$sExtKeyToMeId = self::MakeID($sPrefix.$this->m_sExtKeyToMe);
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
$sExtKeyToRemoteId = self::MakeID($sPrefix.$this->m_sExtKeyToRemote);
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
$iFieldsCount = count($aFieldsMap);
$sJsonFieldsMap = json_encode($aFieldsMap);
$oP->add_script(
<<<EOF
var {$aArgs['wizHelper']} = new WizardHelper('{$this->m_sLinkedClass}', '', '$sState');
{$aArgs['wizHelper']}.SetFieldsMap($sJsonFieldsMap);
{$aArgs['wizHelper']}.SetFieldsCount($iFieldsCount);
EOF
);
$aRow['static::key'] = $oLinkedObj->GetHyperLink();
foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
{
@@ -199,11 +141,6 @@ EOF
}
return $aRow;
}
protected function MakeID($sName)
{
return str_replace(array('[', ']', '-'), '_', $sName);
}
/**
* Display one row of the whole form
@@ -245,17 +182,17 @@ EOF
// Content
$sHtml .= "</tbody>\n";
$sEmptyRowStyle = '';
if (count($aData) != 0)
if (count($aData) == 0)
{
$sEmptyRowStyle = 'style="display:none;"';
$sHtml .= "<tr id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\"></td></td>";
}
$sHtml .= "<tr $sEmptyRowStyle id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\"></td></td>";
foreach($aData as $iRowId => $aRow)
else
{
$sHtml .= $this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
}
foreach($aData as $iRowId => $aRow)
{
$sHtml .= $this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
}
}
$sHtml .= "</tbody>\n";
// Footer
@@ -270,11 +207,9 @@ EOF
* @param WebPage $oP The web page used for all the output
* @param DBObjectSet The initial value of the linked set
* @param Hash $aArgs Extra context arguments
* @param string $sFormPrefix prefix of the fields in the current form
* @param DBObject $oCurrentObj the current object to which the linkset is related
* @return string The HTML fragment to be inserted into the page
*/
public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array())
{
$sHtmlValue = '';
$sTargetClass = self::GetTargetClass($this->m_sClass, $this->m_sAttCode);
@@ -284,35 +219,113 @@ EOF
while($oCurrentLink = $oValue->Fetch())
{
$aRow = array();
$key = $oCurrentLink->GetKey();
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote));
if ($oCurrentLink->IsNew())
{
$key = -$oLinkedObj->GetKey();
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $key, $aArgs, $oCurrentObj);
}
else
{
$key = $oCurrentLink->GetKey();
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj);
}
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs);
}
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
$sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
$oPage->add_ready_script(<<<EOF
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper);
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates);
oWidget{$this->m_iInputId}.Init();
EOF
);
$sHtmlValue .= "<span style=\"float:left;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >";
$sHtmlValue .= "&nbsp;&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"><span id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_indicatorAdd\"></span></span>\n";
$sHtmlValue .= "&nbsp;&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"></span>\n";
$sHtmlValue .= "<span style=\"clear:both;\"><p>&nbsp;</p></span>\n";
$sHtmlValue .= "</div>\n";
$oPage->add_at_the_end("<div id=\"dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}\"></div>"); // To prevent adding forms inside the main form
$oPage->add_at_the_end($this->GetObjectPickerDialog($oPage)); // To prevent adding forms inside the main form
return $sHtmlValue;
}
/**
* This static function is called by the Ajax Page when there is a need to fill an autocomplete combo
* @param $oPage WebPage The ajax page used for the output (sent back to the browser)
* @param $sClass string The name of the class of the current object being edited
* @param $sAttCode string The name of the attribute being edited
* @param $sName string The partial name that was typed by the user
* @param $iMaxCount integer The maximum number of items to return
* @return void
*/
static public function Autocomplete(WebPage $oPage, $sClass, $sAttCode, $sName, $iMaxCount)
{
// #@# todo - add context information, otherwise any value will be authorized for external keys
$aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, array() /* $aArgs */, $sName);
if ($aAllowedValues != null)
{
$iCount = $iMaxCount;
foreach($aAllowedValues as $key => $value)
{
$oPage->add($value."|".$key."\n");
$iCount--;
if ($iCount == 0) break;
}
}
else // No limitation to the allowed values
{
// Search for all the object of the linked class
$oAttDef = $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$sLinkedClass = $oAttDef->GetLinkedClass();
$sSearchClass = self::GetTargetClass($sClass, $sAttCode);
$oFilter = new DBObjectSearch($sSearchClass);
$sSearchAttCode = MetaModel::GetNameAttributeCode($sSearchClass);
$oFilter->AddCondition($sSearchAttCode, $sName, 'Begins with');
$oSet = new CMDBObjectSet($oFilter, array($sSearchAttCode => true));
$iCount = 0;
while( ($iCount < $iMaxCount) && ($oObj = $oSet->fetch()) )
{
$oPage->add($oObj->GetName()."|".$oObj->GetKey()."\n");
$iCount++;
}
}
}
/**
* This static function is called by the Ajax Page display a set of objects being linked
* to the object being created
* @param $oPage WebPage The ajax page used for the put^put (sent back to the browser
* @param $sClass string The name of the 'linking class' which is the class of the objects to display
* @param $sSet JSON serialized set of objects
* @param $sExtKeyToMe Name of the attribute in sClass that is pointing to a given object
* @param $iObjectId The id of the object $sExtKeyToMe is pointing to
* @return void
*/
static public function RenderSet($oPage, $sClass, $sJSONSet, $sExtKeyToMe, $sExtKeyToRemote, $iObjectId)
{
$aSet = json_decode($sJSONSet, true); // true means hash array instead of object
$oSet = CMDBObjectSet::FromScratch($sClass);
foreach($aSet as $aObject)
{
$oObj = MetaModel::NewObject($sClass);
foreach($aObject as $sAttCode => $value)
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsExternalKey() && ($value != 0))
{
$oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value); // @@ optimization, don't do & query per object in the set !
$oObj->Set($sAttCode, $oTargetObj);
}
else
{
$oObj->Set($sAttCode, $value);
}
}
$oSet->AddObject($oObj);
}
$aExtraParams = array();
$aExtraParams['link_attr'] = $sExtKeyToMe;
$aExtraParams['object_id'] = $iObjectId;
$aExtraParams['target_attr'] = $sExtKeyToRemote;
$aExtraParams['menu'] = false;
$aExtraParams['select'] = false;
$aExtraParams['view_link'] = false;
cmdbAbstractObject::DisplaySet($oPage, $oSet, $aExtraParams);
}
protected static function GetTargetClass($sClass, $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
@@ -332,26 +345,27 @@ EOF
return $sTargetClass;
}
public function GetObjectPickerDialog($oPage, $oCurrentObj)
protected function GetObjectPickerDialog($oPage)
{
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$sHtml = "<div id=\"dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}\">";
$sHtml .= "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$oSet = new CMDBObjectSet($oFilter);
$oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}", array('open' => true));
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_sAttCode}{$this->m_sNameSuffix}\" OnSubmit=\"return oWidget{$this->m_iInputId}.DoAddObjects(this.id);\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHtml .= "</div>\n";
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"0\"/>";
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');\">&nbsp;&nbsp;<input id=\"btn_ok_{$this->m_sAttCode}{$this->m_sNameSuffix}\" disabled=\"disabled\" type=\"submit\" value=\"".Dict::S('UI:Button:Add')."\">";
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');\">&nbsp;&nbsp;<input type=\"submit\" value=\"".Dict::S('UI:Button:Add')."\">";
$sHtml .= "</div>\n";
$sHtml .= "</form>\n";
$oPage->add($sHtml);
$sHtml .= "</div>\n";
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('option', {title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."'});");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->m_iInputId}.SearchObjectsToAdd);");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}').resize(oWidget{$this->m_iInputId}.UpdateSizes);");
return $sHtml;
}
/**
@@ -405,19 +419,18 @@ EOF
}
$oSet = new CMDBObjectSet($oFilter);
$oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", array('menu' => false, 'cssCount'=> '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true, 'table_id' => 'add_'.$this->m_sAttCode)); // Don't display the 'Actions' menu on the results
$oBlock->Display($oP, 'ResultsToAdd', array('menu' => false, 'selection_mode' => true, 'display_limit' => false)); // Don't display the 'Actions' menu on the results
}
public function DoAddObjects(WebPage $oP, $oFullSetFilter, $oCurrentObj)
public function DoAddObjects(WebPage $oP, $aLinkedObjectIds = array())
{
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
$aTable = array();
foreach($aLinkedObjectIds as $iObjectId)
{
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId);
if (is_object($oLinkedObj))
{
$aRow = $this->GetFormRow($oP, $oLinkedObj, -$iObjectId, array(), $oCurrentObj ); // Not yet created link get negative Ids
$aRow = $this->GetFormRow($oP, $oLinkedObj, -$iObjectId ); // Not yet created link get negative Ids
$oP->add($this->DisplayFormRow($oP, $this->m_aTableConfig, $aRow, -$iObjectId));
}
else
@@ -426,47 +439,5 @@ EOF
}
}
}
/**
* Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context
* @param DBObject $oSourceObj
* @param DBObjectSearch $oSearch
*/
protected function SetSearchDefaultFromContext($oSourceObj, &$oSearch)
{
$oAppContext = new ApplicationContext();
$sSrcClass = get_class($oSourceObj);
$sDestClass = $oSearch->GetClass();
foreach($oAppContext->GetNames() as $key)
{
// Find the value of the object corresponding to each 'context' parameter
$aCallSpec = array($sSrcClass, 'MapContextParam');
$sAttCode = '';
if (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
}
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode))
{
$oAttDef = MetaModel::GetAttributeDef($sSrcClass, $sAttCode);
$defaultValue = $oSourceObj->Get($sAttCode);
// Find the attcode for the same 'context' parameter in the destination class
// and sets its value as the default value for the search condition
$aCallSpec = array($sDestClass, 'MapContextParam');
$sAttCode = '';
if (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
}
if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue))
{
$oSearch->AddCondition($sAttCode, $defaultValue);
}
}
}
}
}
?>

View File

@@ -52,33 +52,18 @@ class UIPasswordWidget
{
$sCode = $this->sAttCode.$this->sNameSuffix;
$iWidgetIndex = self::$iWidgetIndex;
$sPasswordValue = utils::ReadPostedParam("attr_{$sCode}[value]", '*****', 'raw_data');
$sConfirmPasswordValue = utils::ReadPostedParam("attr_{$sCode}[confirm]", '*****', 'raw_data');
$sPasswordValue = utils::ReadPostedParam("attr_$sCode", '*****');
$sConfirmPasswordValue = utils::ReadPostedParam("attr_{$sCode}_confirmed", '*****');
$sChangedValue = (($sPasswordValue != '*****') || ($sConfirmPasswordValue != '*****')) ? 1 : 0;
$sHtmlValue = '';
$sHtmlValue = '<input type="password" maxlength="255" name="attr_'.$sCode.'[value]" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/>&nbsp;<span class="form_validation" id="v_'.$this->iId.'"></span><br/>';
$sHtmlValue .= '<input type="password" maxlength="255" id="'.$this->iId.'_confirm" value="'.htmlentities($sConfirmPasswordValue, ENT_QUOTES, 'UTF-8').'" name="attr_'.$sCode.'[confirm]"/> '.Dict::S('UI:PasswordConfirm').' <input id="'.$this->iId.'_reset" type="button" value="'.Dict::S('UI:Button:ResetPassword').'" onClick="ResetPwd(\''.$this->iId.'\');">';
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'[changed]" value="'.$sChangedValue.'"/>';
$sHtmlValue = '<input type="password" maxlength="255" name="attr_'.$sCode.'" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/>&nbsp;<span class="form_validation" id="v_'.$this->iId.'"></span><br/>';
$sHtmlValue .= '<input type="password" maxlength="255" id="'.$this->iId.'_confirm" value="'.htmlentities($sConfirmPasswordValue, ENT_QUOTES, 'UTF-8').'" name="attr_'.$sCode.'_confirmed"/> '.Dict::S('UI:PasswordConfirm').' <input type="button" value="'.Dict::S('UI:Button:ResetPassword').'" onClick="ResetPwd(\''.$this->iId.'\');">';
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'_changed" value="'.$sChangedValue.'"/>';
$oPage->add_ready_script("$('#$this->iId').bind('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$this->iId').bind('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}_confirm').bind('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}').bind('update', function(evt, sFormId)
{
if ($(this).attr('disabled'))
{
$('#{$this->iId}_confirm').attr('disabled', 'disabled');
$('#{$this->iId}_changed').attr('disabled', 'disabled');
$('#{$this->iId}_reset').attr('disabled', 'disabled');
}
else
{
$('#{$this->iId}_confirm').removeAttr('disabled');
$('#{$this->iId}_changed').removeAttr('disabled');
$('#{$this->iId}_reset').removeAttr('disabled');
}
}
);"); // Bind to a custom event: update to handle enabling/disabling
return $sHtmlValue;
}
}

View File

@@ -85,7 +85,7 @@ class UILinksWizard
$sTargetClass = $oAttDef->GetTargetClass();
$oTargetObj = MetaModel::GetObject($sTargetClass, $this->m_iObjectId);
$oP->set_title("iTop - ".MetaModel::GetName($this->m_sLinkedClass)." objects linked with ".MetaModel::GetName(get_class($oTargetObj)).": ".$oTargetObj->GetRawName());
$oP->set_title("iTop - ".MetaModel::GetName($this->m_sLinkedClass)." objects linked with ".MetaModel::GetName(get_class($oTargetObj)).": ".$oTargetObj->GetName());
$oP->add("<div class=\"wizContainer\">\n");
$oP->add("<form method=\"post\">\n");
$oP->add("<div class=\"page_header\">\n");
@@ -97,14 +97,15 @@ class UILinksWizard
$oP->add("<input type=\"hidden\" name=\"linking_attcode\" value=\"{$this->m_sLinkingAttCode}\">\n");
$oP->add("<h1>".Dict::Format('UI:ManageObjectsOf_Class_LinkedWith_Class_Instance', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName(get_class($oTargetObj)), "<span class=\"hilite\">".$oTargetObj->GetHyperlink()."</span>")."</h1>\n");
$oP->add("</div>\n");
$oP->add_script(
$oP->add("<script type=\"text/javascript\">\n");
$oP->add(
<<<EOF
function OnSelectChange()
{
var nbChecked = $('.selection:checked').length;
if (nbChecked > 0)
{
$('#btnRemove').removeAttr('disabled');
$('#btnRemove').attr('disabled','');
}
else
{
@@ -131,7 +132,7 @@ class UILinksWizard
function AddObjects()
{
// TO DO: compute the list of objects already linked with the current Object
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { 'operation': 'addObjects',
$.post( 'ajax.render.php', { 'operation': 'addObjects',
'class': '{$this->m_sClass}',
'linkageAttr': '{$this->m_sLinkageAttr}',
'linkedClass': '{$this->m_sLinkedClass}',
@@ -174,7 +175,7 @@ class UILinksWizard
theMap['operation'] = 'searchObjectsToAdd';
// Run the query and display the results
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
$.post( 'ajax.render.php', theMap,
function(data)
{
$('#SearchResultsToAdd').html(data);
@@ -222,7 +223,7 @@ class UILinksWizard
theMap['operation'] = 'doAddObjects';
// Run the query and display the results
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
$.post( 'ajax.render.php', theMap,
function(data)
{
//console.log('Data: ' + data);
@@ -256,6 +257,7 @@ class UILinksWizard
}
EOF
);
$oP->Add("</script>\n");
$oP->add_ready_script("InitForm();");
$oFilter = new DBObjectSearch($this->m_sClass);
$oFilter->AddCondition($this->m_sLinkageAttr, $this->m_iObjectId, '=');
@@ -393,7 +395,7 @@ EOF
$oFilter = new DBObjectSearch($this->m_sLinkedClass);
$oSet = new CMDBObjectSet($oFilter);
$oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, 'ResultsToAdd', array('menu' => false, 'selection_mode' => true)); // Don't display the 'Actions' menu on the results
$oBlock->Display($oP, 'ResultsToAdd', array('menu' => false, 'selection_mode' => true, 'display_limit' => false)); // Don't display the 'Actions' menu on the results
}
public function DoAddObjects(WebPage $oP, $aLinkedObjectIds = array())

View File

@@ -53,7 +53,7 @@ class UIWizard
{
if ($iStepIndex == 1) // one big form that contains everything, to make sure that the uploaded files are posted too
{
$this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php\">\n");
$this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"../pages/UI.php\">\n");
}
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
@@ -112,7 +112,8 @@ class UIWizard
<input type=\"button\" value=\"".Dict::S('UI:Button:Next')."\" onClick=\"GoToStep($iStepIndex, 1+$iStepIndex)\" />
<input type=\"button\" value=\"".Dict::S('UI:Button:Finish')."\" $sDisabled onClick=\"GoToStep($iStepIndex, 1+$nbSteps)\" />
</div>\n");
$this->m_oPage->add_script("
$this->m_oPage->add("
<script type=\"text/javascript\">
function OnEnterStep{$iStepIndex}()
{
oWizardHelper.ResetQuery();
@@ -122,7 +123,7 @@ $sJSHandlerCode
oWizardHelper.AjaxQueryServer();
}
");
</script>\n");
$this->m_oPage->add("</div>\n\n");
}
@@ -138,15 +139,16 @@ $sJSHandlerCode
$this->m_oPage->add("<input type=\"hidden\" name=\"operation\" value=\"wizard_apply_new\" />\n");
$this->m_oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\" />\n");
$this->m_oPage->add("<input type=\"hidden\" id=\"wizard_json_obj\" name=\"json_obj\" value=\"\" />\n");
$sScript = "function OnEnterStep$iStepIndex() {\n";
$this->m_oPage->add("<script type=\"text/javascript\">\n");
$this->m_oPage->add("function OnEnterStep$iStepIndex() {\n");
foreach($aFieldsMap as $iInputId => $sAttCode)
{
$sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n";
$this->m_oPage->add("\toWizardHelper.UpdateCurrentValue('$sAttCode');\n");
}
$sScript .= "\toWizardHelper.Preview('object_preview');\n";
$sScript .= "\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n";
$sScript .= "}\n";
$this->m_oPage->add_script($sScript);
$this->m_oPage->add("\toWizardHelper.Preview('object_preview');\n");
$this->m_oPage->add("\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n");
$this->m_oPage->add("}\n");
$this->m_oPage->add("</script>\n");
$this->m_oPage->add("<div id=\"object_preview\">\n");
$this->m_oPage->add("</div>\n");
$this->m_oPage->add($oAppContext->GetForForm());
@@ -225,7 +227,7 @@ $sJSHandlerCode
// Now use the dependencies between the fields to order them
// Start from the order of the 'details'
$aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details'));
$aList = MetaModel::GetZListItems($this->m_sClass, 'details');
$index = 0;
$aOrder = array();
foreach($aFields as $sAttCode => $void)

View File

@@ -1,61 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Store and retrieve user custom dashboards
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once(APPROOT.'/core/dbobject.class.php');
/**
* This class is used to store, in a persistent manner, a dashboard edited by a user
*/
class UserDashboard extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "gui",
"key_type" => "autoincrement",
"name_attcode" => "user_id",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_app_dashboards",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("menu_code", array("allowed_values"=>null, "sql"=>"menu_code", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("contents", array("allowed_values"=>null, "sql"=>"contents", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
}
/**
* Overloading this function here to secure a fix done right before the release
* The real fix should be to implement this verb in DBObject
*/
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{
$this->DBDelete($oDeletionPlan);
}
}
?>

View File

@@ -77,42 +77,6 @@ class appUserPreferences extends DBObject
self::Save();
}
/**
* Clears the value for a given preference (or list of preferences that matches a pattern), and updates the database
* @param string $sPattern Code/Pattern of the properties/preferences to reset
* @param boolean $bPattern Whether or not the supplied code is a PCRE pattern
*/
static function UnsetPref($sCodeOrPattern, $bPattern = false)
{
if (self::$oUserPrefs == null)
{
self::Load();
}
$aPrefs = self::$oUserPrefs->Get('preferences');
if ($bPattern)
{
// the supplied code is a pattern, clear all preferences that match
foreach($aPrefs as $sKey => $void)
{
if (preg_match($sCodeOrPattern, $sKey))
{
unset($aPrefs[$sKey]);
}
}
self::$oUserPrefs->Set('preferences', $aPrefs);
}
else
{
unset($aPrefs[$sCode]);
self::$oUserPrefs->Set('preferences', $aPrefs);
}
// Save only if needed
if (self::$oUserPrefs->IsModified())
{
self::Save();
}
}
/**
* Call this function to get all the preferences for the user, packed as a JSON object
* @return string JSON representation of the preferences
@@ -205,9 +169,9 @@ class appUserPreferences extends DBObject
* Overloading this function here to secure a fix done right before the release
* The real fix should be to implement this verb in DBObject
*/
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null)
{
$this->DBDelete($oDeletionPlan);
$this->DBDelete();
}
}
?>

View File

@@ -26,10 +26,7 @@
require_once(APPROOT.'/core/config.class.inc.php');
require_once(APPROOT.'/application/transaction.class.inc.php');
define('ITOP_CONFIG_FILE', 'config-itop.php');
define('ITOP_DEFAULT_CONFIG_FILE', APPCONF.ITOP_DEFAULT_ENV.'/'.ITOP_CONFIG_FILE);
define('SERVER_NAME_PLACEHOLDER', '$SERVER_NAME$');
define('ITOP_CONFIG_FILE', APPROOT.'/config-itop.php');
class FileUploadException extends Exception
{
@@ -42,84 +39,9 @@ class FileUploadException extends Exception
*/
class utils
{
private static $oConfig = null;
private static $m_bCASClient = false;
private static $m_sConfigFile = ITOP_CONFIG_FILE;
private static $m_oConfig = null;
// Parameters loaded from a file, parameters of the page/command line still have precedence
private static $m_aParamsFromFile = null;
private static $m_aParamSource = array();
protected static function LoadParamFile($sParamFile)
{
if (!file_exists($sParamFile))
{
throw new Exception("Could not find the parameter file: '$sParamFile'");
}
if (!is_readable($sParamFile))
{
throw new Exception("Could not load parameter file: '$sParamFile'");
}
$sParams = file_get_contents($sParamFile);
if (is_null(self::$m_aParamsFromFile))
{
self::$m_aParamsFromFile = array();
}
$aParamLines = explode("\n", $sParams);
foreach ($aParamLines as $sLine)
{
$sLine = trim($sLine);
// Ignore the line after a '#'
if (($iCommentPos = strpos($sLine, '#')) !== false)
{
$sLine = substr($sLine, 0, $iCommentPos);
$sLine = trim($sLine);
}
// Note: the line is supposed to be already trimmed
if (preg_match('/^(\S*)\s*=(.*)$/', $sLine, $aMatches))
{
$sParam = $aMatches[1];
$value = trim($aMatches[2]);
self::$m_aParamsFromFile[$sParam] = $value;
self::$m_aParamSource[$sParam] = $sParamFile;
}
}
}
public static function UseParamFile($sParamFileArgName = 'param_file', $bAllowCLI = true)
{
$sFileSpec = self::ReadParam($sParamFileArgName, '', $bAllowCLI, 'raw_data');
foreach(explode(',', $sFileSpec) as $sFile)
{
$sFile = trim($sFile);
if (!empty($sFile))
{
self::LoadParamFile($sFile);
}
}
}
/**
* Return the source file from which the parameter has been found,
* usefull when it comes to pass user credential to a process executed
* in the background
* @param $sName Parameter name
* @return The file name if any, or null
*/
public static function GetParamSourceFile($sName)
{
if (array_key_exists($sName, self::$m_aParamSource))
{
return self::$m_aParamSource[$sName];
}
else
{
return null;
}
}
public static function IsModeCLI()
{
@@ -136,19 +58,10 @@ class utils
}
public static function ReadParam($sName, $defaultValue = "", $bAllowCLI = false, $sSanitizationFilter = 'parameter')
public static function ReadParam($sName, $defaultValue = "", $bAllowCLI = false)
{
global $argv;
$retValue = $defaultValue;
if (!is_null(self::$m_aParamsFromFile))
{
if (isset(self::$m_aParamsFromFile[$sName]))
{
$retValue = self::$m_aParamsFromFile[$sName];
}
}
if (isset($_REQUEST[$sName]))
{
$retValue = $_REQUEST[$sName];
@@ -163,119 +76,29 @@ class utils
}
}
}
return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter);
return $retValue;
}
public static function ReadPostedParam($sName, $defaultValue = '', $sSanitizationFilter = 'parameter')
public static function ReadPostedParam($sName, $defaultValue = "")
{
$retValue = isset($_POST[$sName]) ? $_POST[$sName] : $defaultValue;
return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter);
}
public static function Sanitize($value, $defaultValue, $sSanitizationFilter)
{
if ($value === $defaultValue)
{
// Preserve the real default value (can be used to detect missing mandatory parameters)
$retValue = $value;
}
else
{
$retValue = self::Sanitize_Internal($value, $sSanitizationFilter);
if ($retValue === false)
{
$retValue = $defaultValue;
}
}
return $retValue;
}
protected static function Sanitize_Internal($value, $sSanitizationFilter)
{
switch($sSanitizationFilter)
{
case 'integer':
$retValue = filter_var($value, FILTER_SANITIZE_NUMBER_INT);
break;
case 'class':
$retValue = $value;
if (!MetaModel::IsValidClass($value))
{
$retValue = false;
}
break;
case 'string':
$retValue = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
break;
case 'context_param':
case 'parameter':
case 'field_name':
if (is_array($value))
{
$retValue = array();
foreach($value as $key => $val)
{
$retValue[$key] = self::Sanitize_Internal($val, $sSanitizationFilter); // recursively check arrays
if ($retValue[$key] === false)
{
$retValue = false;
break;
}
}
}
else
{
switch($sSanitizationFilter)
{
case 'parameter':
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[ A-Za-z0-9_=-]*$/'))); // the '=' equal character is used in serialized filters
break;
case 'field_name':
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name
break;
case 'context_param':
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[ A-Za-z0-9_=%:+-]*$/')));
break;
}
}
break;
default:
case 'raw_data':
$retValue = $value;
// Do nothing
}
return $retValue;
return isset($_POST[$sName]) ? $_POST[$sName] : $defaultValue;
}
/**
* Reads an uploaded file and turns it into an ormDocument object - Triggers an exception in case of error
* @param string $sName Name of the input used from uploading the file
* @param string $sIndex If Name is an array of posted files, then the index must be used to point out the file
* @return ormDocument The uploaded file (can be 'empty' if nothing was uploaded)
*/
public static function ReadPostedDocument($sName, $sIndex = null)
public static function ReadPostedDocument($sName)
{
$oDocument = new ormDocument(); // an empty document
if(isset($_FILES[$sName]))
{
$aFileInfo = $_FILES[$sName];
$sError = is_null($sIndex) ? $aFileInfo['error'] : $aFileInfo['error'][$sIndex];
switch($sError)
switch($_FILES[$sName]['error'])
{
case UPLOAD_ERR_OK:
$sTmpName = is_null($sIndex) ? $aFileInfo['tmp_name'] : $aFileInfo['tmp_name'][$sIndex];
$sMimeType = is_null($sIndex) ? $aFileInfo['type'] : $aFileInfo['type'][$sIndex];
$sName = is_null($sIndex) ? $aFileInfo['name'] : $aFileInfo['name'][$sIndex];
$doc_content = file_get_contents($sTmpName);
$doc_content = file_get_contents($_FILES[$sName]['tmp_name']);
$sMimeType = $_FILES[$sName]['type'];
if (function_exists('finfo_file'))
{
// as of PHP 5.3 the fileinfo extension is bundled within PHP
@@ -293,7 +116,7 @@ class utils
}
@finfo_close($rInfo);
}
$oDocument = new ormDocument($doc_content, $sMimeType, $sName);
$oDocument = new ormDocument($doc_content, $sMimeType, $_FILES[$sName]['name']);
break;
case UPLOAD_ERR_NO_FILE:
@@ -318,12 +141,11 @@ class utils
break;
case UPLOAD_ERR_EXTENSION:
$sName = is_null($sIndex) ? $aFileInfo['name'] : $aFileInfo['name'][$sIndex];
throw new FileUploadException(Dict::Format('UI:Error:UploadStoppedByExtension_FileName', $sName));
throw new FileUploadException(Dict::Format('UI:Error:UploadStoppedByExtension_FileName', $_FILES[$sName]['name']));
break;
default:
throw new FileUploadException(Dict::Format('UI:Error:UploadFailedUnknownCause_Code', $sError));
throw new FileUploadException(Dict::Format('UI:Error:UploadFailedUnknownCause_Code', $_FILES[$sName]['error']));
break;
}
@@ -331,43 +153,6 @@ class utils
return $oDocument;
}
/**
* Interprets the results posted by a normal or paginated list (in multiple selection mode)
* @param $oFullSetFilter DBObjectSearch The criteria defining the whole sets of objects being selected
* @return Array An arry of object IDs corresponding to the objects selected in the set
*/
public static function ReadMultipleSelection($oFullSetFilter)
{
$aSelectedObj = utils::ReadParam('selectObject', array());
$sSelectionMode = utils::ReadParam('selectionMode', '');
if ($sSelectionMode != '')
{
// Paginated selection
$aExceptions = utils::ReadParam('storedSelection', array());
if ($sSelectionMode == 'positive')
{
// Only the explicitely listed items are selected
$aSelectedObj = $aExceptions;
}
else
{
// All items of the set are selected, except the one explicitely listed
$aSelectedObj = array();
$oFullSet = new DBObjectSet($oFullSetFilter);
$sClassAlias = $oFullSetFilter->GetClassAlias();
$oFullSet->OptimizeColumnLoad(array($sClassAlias => array('friendlyname'))); // We really need only the IDs but it does not work since id is not a real field
while($oObj = $oFullSet->Fetch())
{
if (!in_array($oObj->GetKey(), $aExceptions))
{
$aSelectedObj[] = $oObj->GetKey();
}
}
}
}
return $aSelectedObj;
}
public static function GetNewTransactionId()
{
return privUITransaction::GetNewTransactionId();
@@ -416,106 +201,39 @@ class utils
return $iReturn;
}
/**
* Helper function to convert a string to a date, given a format specification. It replaces strtotime which does not allow for specifying a date in a french format (for instance)
* Example: StringToTime('01/05/11 12:03:45', '%d/%m/%y %H:%i:%s')
* @param string $sDate
* @param string $sFormat
* @return timestamp or false if the input format is not correct
*/
public static function StringToTime($sDate, $sFormat)
{
// Source: http://php.net/manual/fr/function.strftime.php
// (alternative: http://www.php.net/manual/fr/datetime.formats.date.php)
static $aDateTokens = null;
static $aDateRegexps = null;
if (is_null($aDateTokens))
{
$aSpec = array(
'%d' =>'(?<day>[0-9]{2})',
'%m' => '(?<month>[0-9]{2})',
'%y' => '(?<year>[0-9]{2})',
'%Y' => '(?<year>[0-9]{4})',
'%H' => '(?<hour>[0-2][0-9])',
'%i' => '(?<minute>[0-5][0-9])',
'%s' => '(?<second>[0-5][0-9])',
);
$aDateTokens = array_keys($aSpec);
$aDateRegexps = array_values($aSpec);
}
$sDateRegexp = str_replace($aDateTokens, $aDateRegexps, $sFormat);
if (preg_match('!^(?<head>)'.$sDateRegexp.'(?<tail>)$!', $sDate, $aMatches))
{
$sYear = isset($aMatches['year']) ? $aMatches['year'] : 0;
$sMonth = isset($aMatches['month']) ? $aMatches['month'] : 1;
$sDay = isset($aMatches['day']) ? $aMatches['day'] : 1;
$sHour = isset($aMatches['hour']) ? $aMatches['hour'] : 0;
$sMinute = isset($aMatches['minute']) ? $aMatches['minute'] : 0;
$sSecond = isset($aMatches['second']) ? $aMatches['second'] : 0;
return strtotime("$sYear-$sMonth-$sDay $sHour:$sMinute:$sSecond");
}
else
{
return false;
}
// http://www.spaweditor.com/scripts/regex/index.php
}
static public function GetConfig()
{
if (self::$oConfig == null)
{
$sConfigFile = self::GetConfigFilePath();
if (file_exists($sConfigFile))
{
self::$oConfig = new Config($sConfigFile);
}
else
{
// When executing the setup, the config file may be still missing
self::$oConfig = new Config();
}
}
return self::$oConfig;
}
/**
* Returns the absolute URL to the application root path
* @return string The absolute URL to the application root, without the first slash
* Returns an absolute URL to the current page
* @param $bQueryString bool True to also get the query string, false otherwise
* @param $bForceHTTPS bool True to force HTTPS, false otherwise
* @return string The absolute URL to the current page
*/
static public function GetAbsoluteUrlAppRoot()
{
$sUrl = self::GetConfig()->Get('app_root_url');
if (strpos($sUrl, SERVER_NAME_PLACEHOLDER) > -1)
{
if (isset($_SERVER['SERVER_NAME']))
{
$sServerName = $_SERVER['SERVER_NAME'];
}
else
{
// CLI mode ?
$sServerName = php_uname('n');
}
$sUrl = str_replace(SERVER_NAME_PLACEHOLDER, $sServerName, $sUrl);
}
return $sUrl;
}
static public function GetDefaultUrlAppRoot()
static public function GetAbsoluteUrl($bQueryString = true, $bForceHTTPS = false)
{
// Build an absolute URL to this page on this server/port
$sServerName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
$sProtocol = (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS']!="off")) ? 'https' : 'http';
$iPort = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80;
if ($sProtocol == 'http')
if (MetaModel::GetConfig()->GetSecureConnectionRequired() || MetaModel::GetConfig()->GetHttpsHyperlinks())
{
$sPort = ($iPort == 80) ? '' : ':'.$iPort;
// If a secure connection is required, or if the URL is requested to start with HTTPS
// then any URL must start with https !
$bForceHTTPS = true;
}
if ($bForceHTTPS)
{
$sProtocol = 'https';
$sPort = '';
}
else
{
$sPort = ($iPort == 443) ? '' : ':'.$iPort;
$sProtocol = (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS']!="off")) ? 'https' : 'http';
$iPort = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80;
if ($sProtocol == 'http')
{
$sPort = ($iPort == 80) ? '' : ':'.$iPort;
}
else
{
$sPort = ($iPort == 443) ? '' : ':'.$iPort;
}
}
// $_SERVER['REQUEST_URI'] is empty when running on IIS
// Let's use Ivan Tcholakov's fix (found on www.dokeos.com)
@@ -532,42 +250,48 @@ class utils
}
$_SERVER['REQUEST_URI'] = $sPath;
}
$sPath = $_SERVER['REQUEST_URI'];
// remove all the parameters from the query string
$iQuestionMarkPos = strpos($sPath, '?');
if ($iQuestionMarkPos !== false)
{
$sPath = substr($sPath, 0, $iQuestionMarkPos);
}
$sAbsoluteUrl = "$sProtocol://{$sServerName}{$sPort}{$sPath}";
$sCurrentScript = realpath($_SERVER['SCRIPT_FILENAME']);
$sCurrentScript = str_replace('\\', '/', $sCurrentScript); // canonical path
$sAppRoot = str_replace('\\', '/', APPROOT); // canonical path
$sCurrentRelativePath = str_replace($sAppRoot, '', $sCurrentScript);
$sPath = $_SERVER['REQUEST_URI'];
if (!$bQueryString)
{
// remove all the parameters from the query string
$iQuestionMarkPos = strpos($sPath, '?');
if ($iQuestionMarkPos !== false)
{
$sPath = substr($sPath, 0, $iQuestionMarkPos);
}
}
$sUrl = "$sProtocol://{$sServerName}{$sPort}{$sPath}";
return $sUrl;
}
$sAppRootPos = strpos($sAbsoluteUrl, $sCurrentRelativePath);
if ($sAppRootPos !== false)
/**
* Returns the absolute URL PATH of the current page
* @param $bForceHTTPS bool True to force HTTPS, false otherwise
* @return string The absolute URL to the current page
*/
static public function GetAbsoluteUrlPath($bForceHTTPS = false)
{
$sAbsoluteUrl = self::GetAbsoluteUrl(false, $bForceHTTPS); // False => Don't get the query string
$sAbsoluteUrl = substr($sAbsoluteUrl, 0, 1+strrpos($sAbsoluteUrl, '/')); // remove the current page, keep just the path, up to the last /
return $sAbsoluteUrl;
}
/**
* Returns the absolute URL to the server's root path
* @param $bForceHTTPS bool True to force HTTPS, false otherwise
* @return string The absolute URL to the server's root, without the first slash
*/
static public function GetAbsoluteUrlRoot($bForceHTTPS = false)
{
$sAbsoluteUrl = self::GetAbsoluteUrl(false, $bForceHTTPS); // False => Don't get the query string
$sServerPos = 3 + strpos($sAbsoluteUrl, '://');
$iFirstSlashPos = strpos($sAbsoluteUrl, '/', $sServerPos);
if ($iFirstSlashPos !== false)
{
$sAppRootUrl = substr($sAbsoluteUrl, 0, $sAppRootPos); // remove the current page and path
$sAbsoluteUrl = substr($sAbsoluteUrl, 0, $iFirstSlashPos); // remove the current page, keep just the path, without the first /
}
else
{
// Second attempt without index.php at the end...
$sCurrentRelativePath = str_replace('index.php', '', $sCurrentRelativePath);
$sAppRootPos = strpos($sAbsoluteUrl, $sCurrentRelativePath);
if ($sAppRootPos !== false)
{
$sAppRootUrl = substr($sAbsoluteUrl, 0, $sAppRootPos); // remove the current page and path
}
else
{
// No luck...
throw new Exception("Failed to determine application root path $sAbsoluteUrl ($sCurrentRelativePath) APPROOT:'$sAppRoot'");
}
}
return $sAppRootUrl;
return $sAbsoluteUrl;
}
/**
@@ -579,236 +303,7 @@ class utils
*/
static function CanLogOff()
{
$bResult = false;
if(isset($_SESSION['login_mode']))
{
$sLoginMode = $_SESSION['login_mode'];
switch($sLoginMode)
{
case 'external':
$bResult = false;
break;
case 'form':
case 'basic':
case 'url':
case 'cas':
default:
$bResult = true;
}
}
return $bResult;
}
/**
* Initializes the CAS client
*/
static function InitCASClient()
{
$sCASIncludePath = self::GetConfig()->Get('cas_include_path');
include_once($sCASIncludePath.'/CAS.php');
$bCASDebug = self::GetConfig()->Get('cas_debug');
if ($bCASDebug)
{
phpCAS::setDebug(APPROOT.'/error.log');
}
if (!self::$m_bCASClient)
{
// Initialize phpCAS
$sCASVersion = self::GetConfig()->Get('cas_version');
$sCASHost = self::GetConfig()->Get('cas_host');
$iCASPort = self::GetConfig()->Get('cas_port');
$sCASContext = self::GetConfig()->Get('cas_context');
phpCAS::client($sCASVersion, $sCASHost, $iCASPort, $sCASContext, false /* session already started */);
self::$m_bCASClient = true;
$sCASCACertPath = self::GetConfig()->Get('cas_server_ca_cert_path');
if (empty($sCASCACertPath))
{
// If no certificate authority is provided, do not attempt to validate
// the server's certificate
// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
phpCAS::setNoCasServerValidation();
}
else
{
phpCAS::setCasServerCACert($sCASCACertPath);
}
}
}
static function DebugBacktrace($iLimit = 5)
{
$aFullTrace = debug_backtrace();
$aLightTrace = array();
for($i=1; ($i<=$iLimit && $i < count($aFullTrace)); $i++) // Skip the last function call... which is the call to this function !
{
$aLightTrace[$i] = $aFullTrace[$i]['function'].'(), called from line '.$aFullTrace[$i]['line'].' in '.$aFullTrace[$i]['file'];
}
echo "<p><pre>".print_r($aLightTrace, true)."</pre></p>\n";
}
/**
* Execute the given iTop PHP script, passing it the current credentials
* Only CLI mode is supported, because of the need to hand the credentials over to the next process
* Throws an exception if the execution fails or could not be attempted (config issue)
* @param string $sScript Name and relative path to the file (relative to the iTop root dir)
* @param hash $aArguments Associative array of 'arg' => 'value'
* @return array(iCode, array(output lines))
*/
/**
*/
static function ExecITopScript($sScriptName, $aArguments)
{
$aDisabled = explode(', ', ini_get('disable_functions'));
if (in_array('exec', $aDisabled))
{
throw new Exception("The PHP exec() function has been disabled on this server");
}
$sPHPExec = trim(self::GetConfig()->Get('php_path'));
if (strlen($sPHPExec) == 0)
{
throw new Exception("The path to php must not be empty. Please set a value for 'php_path' in your configuration file.");
}
$sAuthUser = self::ReadParam('auth_user', '', 'raw_data');
$sAuthPwd = self::ReadParam('auth_pwd', '', 'raw_data');
$sParamFile = self::GetParamSourceFile('auth_user');
if (is_null($sParamFile))
{
$aArguments['auth_user'] = $sAuthUser;
$aArguments['auth_pwd'] = $sAuthPwd;
}
else
{
$aArguments['param_file'] = $sParamFile;
}
$aArgs = array();
foreach($aArguments as $sName => $value)
{
// Note: See comment from the 23-Apr-2004 03:30 in the PHP documentation
// It suggests to rely on pctnl_* function instead of using escapeshellargs
$aArgs[] = "--$sName=".escapeshellarg($value);
}
$sArgs = implode(' ', $aArgs);
$sScript = realpath(APPROOT.$sScriptName);
if (!file_exists($sScript))
{
throw new Exception("Could not find the script file '$sScriptName' from the directory '".APPROOT."'");
}
$sCommand = '"'.$sPHPExec.'" '.escapeshellarg($sScript).' -- '.$sArgs;
if (version_compare(phpversion(), '5.3.0', '<'))
{
if (substr(PHP_OS,0,3) == 'WIN')
{
// Under Windows, and for PHP 5.2.x, the whole command has to be quoted
// Cf PHP doc: http://php.net/manual/fr/function.exec.php, comment from the 27-Dec-2010
$sCommand = '"'.$sCommand.'"';
}
}
$sLastLine = exec($sCommand, $aOutput, $iRes);
if ($iRes == 1)
{
throw new Exception(Dict::S('Core:ExecProcess:Code1')." - ".$sCommand);
}
elseif ($iRes == 255)
{
$sErrors = implode("\n", $aOutput);
throw new Exception(Dict::S('Core:ExecProcess:Code255')." - ".$sCommand.":\n".$sErrors);
}
//$aOutput[] = $sCommand;
return array($iRes, $aOutput);
}
/**
* Get the current environment
*/
public static function GetCurrentEnvironment()
{
if (isset($_SESSION['itop_env']))
{
return $_SESSION['itop_env'];
}
else
{
return ITOP_DEFAULT_ENV;
}
}
/**
* Get the "Back" button to go out of the current environment
*/
public static function GetEnvironmentBackButton()
{
if (isset($_SESSION['itop_return_env']))
{
if (isset($_SESSION['itop_return_url']))
{
$sReturnUrl = $_SESSION['itop_return_url'];
}
else
{
$sReturnUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?switch_env='.$_SESSION['itop_return_env'];
}
return '&nbsp;<button onclick="window;location.href=\''.addslashes($sReturnUrl).'\'">'.Dict::S('UI:Button:Back').'</button>';
}
else
{
return '';
}
}
/**
* Get the "Back" button to go out of the current environment
*/
public static function GetPopupMenuItems($oPage, $iMenuId, $param, &$aActions)
{
foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance)
{
foreach($oExtensionInstance->EnumItems($iMenuId, $param) as $oMenuItem)
{
if (is_object($oMenuItem))
{
$aActions[$oMenuItem->GetUID()] = $oMenuItem->GetMenuItem();
foreach($oMenuItem->GetLinkedScripts() as $sLinkedScript)
{
$oPage->add_linked_script($sLinkedScript);
}
}
}
}
}
/**
* Get target configuration file name (including full path)
*/
public static function GetConfigFilePath($sEnvironment = null)
{
if (is_null($sEnvironment))
{
$sEnvironment = self::GetCurrentEnvironment();
}
return APPCONF.$sEnvironment.'/'.ITOP_CONFIG_FILE;
}
/**
* Returns the absolute URL to the modules root path
* @return string ...
*/
static public function GetAbsoluteUrlModulesRoot()
{
$sUrl = self::GetAbsoluteUrlAppRoot().'env-'.self::GetCurrentEnvironment().'/';
return $sUrl;
return (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'form');
}
}
?>
?>

View File

@@ -23,22 +23,6 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
/**
* Generic interface common to CLI and Web pages
*/
Interface Page
{
public function output();
public function add($sText);
public function p($sText);
public function pre($sText);
public function add_comment($sText);
public function table($aConfig, $aData, $aParams = array());
}
/**
* Simple helper class to ease the production of HTML pages
*
@@ -50,7 +34,7 @@ Interface Page
* $oPage->p("Hello World !");
* $oPage->output();
*/
class WebPage implements Page
class WebPage
{
protected $s_title;
protected $s_content;
@@ -62,13 +46,7 @@ class WebPage implements Page
protected $a_headers;
protected $a_base;
protected $iNextId;
protected $iTransactionId;
protected $sContentType;
protected $sContentDisposition;
protected $sContentFileName;
protected $s_sOutputFormat;
protected $a_OutputOptions;
public function __construct($s_title)
{
$this->s_title = $s_title;
@@ -81,12 +59,6 @@ class WebPage implements Page
$this->a_headers = array();
$this->a_base = array( 'href' => '', 'target' => '');
$this->iNextId = 0;
$this->iTransactionId = 0;
$this->sContentType = '';
$this->sContentDisposition = '';
$this->sContentFileName = '';
$this->s_OutputFormat = utils::ReadParam('output_format', 'html');
$this->a_OutputOptions = array();
ob_start(); // Start capturing the output
}
@@ -116,11 +88,11 @@ class WebPage implements Page
}
/**
* Add any text or HTML fragment (identified by an ID) at the end of the body of the page
* Add any text or HTML fragment at the end of the body of the page
* This is useful to add hidden content, DIVs or FORMs that should not
* be embedded into each other.
*/
public function add_at_the_end($s_html, $sId = '')
public function add_at_the_end($s_html)
{
$this->s_deferred_content .= $s_html;
}
@@ -141,13 +113,6 @@ class WebPage implements Page
$this->add('<pre>'.$s_html.'</pre>');
}
/**
* Add a comment
*/
public function add_comment($sText)
{
$this->add('<!--'.$sText.'-->');
}
/**
* Add a paragraph to the body of the page
*/
@@ -187,33 +152,27 @@ class WebPage implements Page
$sHtml .= "<tbody>\n";
foreach($aData as $aRow)
{
$sHtml .= $this->GetTableRow($aRow, $aConfig);
if (isset($aRow['@class'])) // Row specific class, for hilighting certain rows
{
$sHtml .= "<tr class=\"{$aRow['@class']}\">\n";
}
else
{
$sHtml .= "<tr>\n";
}
foreach($aConfig as $sName=>$aAttribs)
{
$aMatches = array();
$sClass = isset($aAttribs['class']) ? 'class="'.$aAttribs['class'].'"' : '';
$sValue = ($aRow[$sName] === '') ? '&nbsp;' : $aRow[$sName];
$sHtml .= "<td $sClass>$sValue</td>\n";
}
$sHtml .= "</tr>\n";
}
$sHtml .= "</tbody>\n";
$sHtml .= "</table>\n";
return $sHtml;
}
public function GetTableRow($aRow, $aConfig)
{
$sHtml = '';
if (isset($aRow['@class'])) // Row specific class, for hilighting certain rows
{
$sHtml .= "<tr class=\"{$aRow['@class']}\">";
}
else
{
$sHtml .= "<tr>";
}
foreach($aConfig as $sName=>$aAttribs)
{
$sClass = isset($aAttribs['class']) ? 'class="'.$aAttribs['class'].'"' : '';
$sValue = ($aRow[$sName] === '') ? '&nbsp;' : $aRow[$sName];
$sHtml .= "<td $sClass>$sValue</td>";
}
$sHtml .= "</tr>";
return $sHtml;
}
/**
* Add some Javascript to the header of the page
@@ -243,7 +202,7 @@ class WebPage implements Page
*/
public function add_linked_script($s_linked_script)
{
$this->a_linked_scripts[$s_linked_script] = $s_linked_script;
$this->a_linked_scripts[] = $s_linked_script;
}
/**
@@ -279,35 +238,13 @@ class WebPage implements Page
$this->add($this->GetDetails($aFields));
}
/**
* Records the current state of the 'html' part of the page output
* @return mixed The current state of the 'html' output
*/
public function start_capture()
{
return strlen($this->s_content);
}
/**
* Returns the part of the html output that occurred since the call to start_capture
* and removes this part from the current html output
* @param $offset mixed The value returned by start_capture
* @return string The part of the html output that was added since the call to start_capture
*/
public function end_capture($offset)
{
$sCaptured = substr($this->s_content, $offset);
$this->s_content = substr($this->s_content, 0, $offset);
return $sCaptured;
}
/**
* Build a special kind of TABLE useful for displaying the details of an object from a hash array of data
*/
public function GetDetails($aFields)
{
$sHtml = "<table class=\"details\">\n";
$sHtml = "<table>\n";
$sHtml .= "<tbody>\n";
foreach($aFields as $aAttrib)
{
@@ -321,62 +258,12 @@ class WebPage implements Page
{
$sHtml .= "<td class=\"label\">".$aAttrib['label']."</td><td>".$aAttrib['value']."</td>\n";
}
$sComment = (isset($aAttrib['comments'])) ? $aAttrib['comments'] : '&nbsp;';
$sInfo = (isset($aAttrib['infos'])) ? $aAttrib['infos'] : '&nbsp;';
$sHtml .= "<td>$sComment</td><td>$sInfo</td>\n";
$sHtml .= "</tr>\n";
}
$sHtml .= "</tbody>\n";
$sHtml .= "</table>\n";
return $sHtml;
}
/**
* Build a set of radio buttons suitable for editing a field/attribute of an object (including its validation)
* @param $aAllowedValues hash Array of value => display_value
* @param $value mixed Current value for the field/attribute
* @param $iId mixed Unique Id for the input control in the page
* @param $sFieldName string The name of the field, attr_<$sFieldName> will hold the value for the field
* @param $bMandatory bool Whether or not the field is mandatory
* @param $bVertical bool Disposition of the radio buttons vertical or horizontal
* @param $sValidationField string HTML fragment holding the validation field (exclamation icon...)
* @return string The HTML fragment corresponding to the radio buttons
*/
public function GetRadioButtons($aAllowedValues, $value, $iId, $sFieldName, $bMandatory, $bVertical, $sValidationField)
{
$idx = 0;
$sHTMLValue = '';
foreach($aAllowedValues as $key => $display_value)
{
if ((count($aAllowedValues) == 1) && ($bMandatory == 'true') )
{
// When there is only once choice, select it by default
$sSelected = ' checked';
}
else
{
$sSelected = ($value == $key) ? ' checked' : '';
}
$sHTMLValue .= "<input type=\"radio\" id=\"{$iId}_{$key}\" name=\"radio_$sFieldName\" onChange=\"$('#{$iId}').val(this.value).trigger('change');\" value=\"$key\"$sSelected><label class=\"radio\" for=\"{$iId}_{$key}\">&nbsp;$display_value</label>&nbsp;";
if ($bVertical)
{
if ($idx == 0)
{
// Validation icon at the end of the first line
$sHTMLValue .= "&nbsp;{$sValidationField}\n";
}
$sHTMLValue .= "<br>\n";
}
$idx++;
}
$sHTMLValue .= "<input type=\"hidden\" id=\"$iId\" name=\"$sFieldName\" value=\"$value\"/>";
if (!$bVertical)
{
// Validation icon at the end of the line
$sHTMLValue .= "&nbsp;{$sValidationField}\n";
}
return $sHTMLValue;
}
/**
* Outputs (via some echo) the complete HTML page by assembling all its elements
@@ -392,21 +279,11 @@ class WebPage implements Page
echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
echo "<html>\n";
echo "<head>\n";
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
echo "<title>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</title>\n";
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
echo "<title>{$this->s_title}</title>\n";
echo $this->get_base_tag();
foreach($this->a_linked_scripts as $s_script)
{
// Make sure that the URL to the script contains the application's version number
// so that the new script do NOT get reloaded from the cache when the application is upgraded
if (strpos($s_script, '?') === false)
{
$s_script .= "?itopversion=".ITOP_VERSION;
}
else
{
$s_script .= "&itopversion=".ITOP_VERSION;
}
echo "<script type=\"text/javascript\" src=\"$s_script\"></script>\n";
}
if (count($this->a_scripts)>0)
@@ -440,18 +317,14 @@ class WebPage implements Page
}
echo "</style>\n";
}
if (class_exists('MetaModel') && MetaModel::GetConfig())
{
echo "<link rel=\"shortcut icon\" href=\"".utils::GetAbsoluteUrlAppRoot()."images/favicon.ico\" />\n";
}
echo "</head>\n";
echo "<body>\n";
echo self::FilterXSS($this->s_content);
echo $this->s_content;
if (trim($s_captured_output) != "")
{
echo "<div class=\"raw_output\">".self::FilterXSS($s_captured_output)."</div>\n";
echo "<div class=\"raw_output\">$s_captured_output</div>\n";
}
echo '<div id="at_the_end">'.self::FilterXSS($this->s_deferred_content).'</div>';
echo $this->s_deferred_content;
echo "</body>\n";
echo "</html>\n";
}
@@ -496,144 +369,5 @@ class WebPage implements Page
{
return $this->iNextId++;
}
/**
* Set the content-type (mime type) for the page's content
* @param $sContentType string
* @return void
*/
public function SetContentType($sContentType)
{
$this->sContentType = $sContentType;
}
/**
* Set the content-disposition (mime type) for the page's content
* @param $sDisposition string The disposition: 'inline' or 'attachment'
* @param $sFileName string The original name of the file
* @return void
*/
public function SetContentDisposition($sDisposition, $sFileName)
{
$this->sContentDisposition = $sDisposition;
$this->sContentFileName = $sFileName;
}
/**
* Set the transactionId of the current form
* @param $iTransactionId integer
* @return void
*/
public function SetTransactionId($iTransactionId)
{
$this->iTransactionId = $iTransactionId;
}
/**
* Returns the transactionId of the current form
* @return integer The current transactionID
*/
public function GetTransactionId()
{
return $this->iTransactionId;
}
public static function FilterXSS($sHTML)
{
return str_ireplace('<script', '&lt;script', $sHTML);
}
/**
* What is the currently selected output format
* @return string The selected output format: html, pdf...
*/
public function GetOutputFormat()
{
return $this->s_OutputFormat;
}
/**
* Check whether the desired output format is possible or not
* @param string $sOutputFormat The desired output format: html, pdf...
* @return bool True if the format is Ok, false otherwise
*/
function IsOutputFormatAvailable($sOutputFormat)
{
$bResult = false;
switch($sOutputFormat)
{
case 'html':
$bResult = true; // Always supported
break;
case 'pdf':
$bResult = @is_readable(APPROOT.'lib/MPDF/mpdf.php');
break;
}
return $bResult;
}
/**
* Retrieves the value of a named output option for the given format
* @param string $sFormat The format: html or pdf
* @param string $sOptionName The name of the option
* @return mixed false if the option was never set or the options's value
*/
public function GetOutputOption($sFormat, $sOptionName)
{
if (isset($this->a_OutputOptions[$sFormat][$sOptionName]))
{
return $this->a_OutputOptions[$sFormat][$sOptionName];
}
return false;
}
/**
* Sets a named output option for the given format
* @param string $sFormat The format for which to set the option: html or pdf
* @param string $sOptionName the name of the option
* @param mixed $sValue The value of the option
*/
public function SetOutputOption($sFormat, $sOptionName, $sValue)
{
if (!isset($this->a_OutputOptions[$sFormat]))
{
$this->a_OutputOptions[$sFormat] = array($sOptionName => $sValue);
}
else
{
$this->a_OutputOptions[$sFormat][$sOptionName] = $sValue;
}
}
public function RenderPopupMenuItems($aActions, $aFavoriteActions = array())
{
$sPrevUrl = '';
$sHtml = '';
foreach ($aActions as $aAction)
{
$sClass = isset($aAction['class']) ? " class=\"{$aAction['class']}\"" : "";
$sOnClick = isset($aAction['onclick']) ? " onclick=\"{$aAction['onclick']}\"" : "";
if (empty($aAction['url']))
{
if ($sPrevUrl != '') // Don't output consecutively two separators...
{
$sHtml .= "<li>{$aAction['label']}</li>";
}
$sPrevUrl = '';
}
else
{
$sHtml .= "<li><a href=\"{$aAction['url']}\"$sClass $sOnClick>{$aAction['label']}</a></li>";
$sPrevUrl = $aAction['url'];
}
}
$sHtml .= "</ul></li></ul></div>";
foreach(array_reverse($aFavoriteActions) as $aAction)
{
$sHtml .= "<div class=\"actions_button\"><a href='{$aAction['url']}'>{$aAction['label']}</a></div>";
}
return $sHtml;
}
}
?>

View File

@@ -76,7 +76,7 @@ class WizardHelper
if ( isset($aLinkedObject[$sLinkedAttCode]) && ($aLinkedObject[$sLinkedAttCode] !== null) )
{
$sLinkedAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sLinkedAttCode);
if (($sLinkedAttDef->IsExternalKey()) && ($aLinkedObject[$sLinkedAttCode] != '') && ($aLinkedObject[$sLinkedAttCode] > 0) )
if (($sLinkedAttDef->IsExternalKey()) && ($aLinkedObject[$sLinkedAttCode] != '') && ($aLinkedObject[$sLinkedAttCode] != 0) )
{
// For external keys: load the target object so that external fields
// get filled too
@@ -98,7 +98,7 @@ class WizardHelper
{
if ($bReadUploadedFiles)
{
$oDocument = utils::ReadPostedDocument('attr_'.$sAttCode, 'fcontents');
$oDocument = utils::ReadPostedDocument('file_'.$sAttCode);
$oObj->Set($sAttCode, $oDocument);
}
else
@@ -108,7 +108,7 @@ class WizardHelper
$oObj->Set($sAttCode, $oDocument);
}
}
else if (($oAttDef->IsExternalKey()) && (!empty($value)) && ($value > 0) )
else if (($oAttDef->IsExternalKey()) && (!empty($value)) )
{
// For external keys: load the target object so that external fields
// get filled too
@@ -121,11 +121,6 @@ class WizardHelper
}
}
}
if (isset($this->m_aData['m_sState']) && !empty($this->m_aData['m_sState']))
{
$oObj->Set(MetaModel::GetStateAttributeCode($this->m_aData['m_sClass']), $this->m_aData['m_sState']);
}
$oObj->DoComputeValues();
return $oObj;
}
@@ -260,7 +255,7 @@ class WizardHelper
foreach($aLinkObj as $sAttCode => $value)
{
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
if (($oAttDef->IsExternalKey()) && ($value != '') )
{
// For external keys: load the target object so that external fields
// get filled too

View File

@@ -1,15 +1,3 @@
<?php
define('APPROOT', dirname(__FILE__).'/');
define('APPCONF', APPROOT.'conf/');
define('ITOP_DEFAULT_ENV', 'production');
if (function_exists('microtime'))
{
$fItopStarted = microtime(true);
}
else
{
$fItopStarted = 1000 * time();
}
?>

View File

@@ -443,9 +443,9 @@ class Str
public static function pure2html($pure, $maxLength = false)
{
// Check for HTML entities, but be careful the DB is in UTF-8
return $maxLength
? htmlentities(substr($pure, 0, $maxLength), ENT_QUOTES, 'UTF-8')
: htmlentities($pure, ENT_QUOTES, 'UTF-8');
return $maxLength
? htmlentities(substr($pure, 0, $maxLength), ENT_COMPAT, 'UTF-8')
: htmlentities($pure, ENT_COMPAT, 'UTF-8');
}
public static function pure2sql($pure, $maxLength = false)
{

View File

@@ -24,7 +24,6 @@
*/
require_once(APPROOT.'/core/asynctask.class.inc.php');
require_once(APPROOT.'/core/email.class.inc.php');
/**
@@ -42,7 +41,7 @@ abstract class Action extends cmdbAbstractObject
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"reconc_keys" => array(),
"db_table" => "priv_action",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
@@ -106,7 +105,7 @@ abstract class ActionNotification extends Action
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"reconc_keys" => array(),
"db_table" => "priv_action_notification",
"db_key_field" => "id",
"db_finalclass_field" => "",
@@ -135,11 +134,11 @@ class ActionEmail extends ActionNotification
{
$aParams = array
(
"category" => "core/cmdb,bizmodel",
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"reconc_keys" => array(),
"db_table" => "priv_action_email",
"db_key_field" => "id",
"db_finalclass_field" => "",
@@ -163,7 +162,7 @@ class ActionEmail extends ActionNotification
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name','description', 'status', 'subject')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
@@ -183,7 +182,6 @@ class ActionEmail extends ActionNotification
try
{
$oSearch = DBObjectSearch::FromOQL($sOQL);
$oSearch->AllowAllData();
}
catch (OQLException $e)
{
@@ -221,73 +219,17 @@ class ActionEmail extends ActionNotification
public function DoExecute($oTrigger, $aContextArgs)
{
if (MetaModel::IsLogEnabledNotification())
{
$oLog = new EventNotificationEmail();
if ($this->IsBeingTested())
{
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
}
else
{
$oLog->Set('message', 'Notification pending');
}
$oLog->Set('userinfo', UserRights::GetUser());
$oLog->Set('trigger_id', $oTrigger->GetKey());
$oLog->Set('action_id', $this->GetKey());
$oLog->Set('object_id', $aContextArgs['this->object()']->GetKey());
// Must be inserted now so that it gets a valid id that will make the link
// between an eventual asynchronous task (queued) and the log
$oLog->DBInsertNoReload();
}
else
{
$oLog = null;
}
$this->m_iRecipients = 0;
$this->m_aMailErrors = array();
$bRes = false; // until we do succeed in sending the email
try
{
$sRes = $this->_DoExecute($oTrigger, $aContextArgs, $oLog);
if ($this->IsBeingTested())
{
$sPrefix = 'TEST ('.$this->Get('test_recipient').') - ';
}
else
{
$sPrefix = '';
}
$oLog->Set('message', $sPrefix.$sRes);
}
catch (Exception $e)
{
if ($oLog)
{
$oLog->Set('message', 'Error: '.$e->getMessage());
}
}
if ($oLog)
{
$oLog->DBUpdate();
}
}
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
{
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
try
{
$this->m_iRecipients = 0;
$this->m_aMailErrors = array();
$bRes = false; // until we do succeed in sending the email
// Determine recicipients
//
$sTo = $this->FindRecipients('to', $aContextArgs);
$sCC = $this->FindRecipients('cc', $aContextArgs);
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
$sFrom = $this->Get('from');
$sReplyTo = $this->Get('reply_to');
@@ -295,18 +237,102 @@ class ActionEmail extends ActionNotification
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
$oObj = $aContextArgs['this->object()'];
$sMessageId = sprintf('iTop_%s_%d_%f@%s.openitop.org', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/), MetaModel::GetEnvironmentId());
$sReference = '<'.$sMessageId.'>';
$sServerIP = $_SERVER['SERVER_ADDR']; //gethostbyname(gethostname());
$sReference = '<iTop/'.get_class($oObj).'/'.$oObj->GetKey().'@'.$sServerIP.'>';
$oEmail = new EMail();
if ($this->IsBeingTested())
{
$oEmail->SetSubject('TEST['.$sSubject.']');
$sTestBody = $sBody;
$sTestBody .= "<div style=\"border: dashed;\">\n";
$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
$sTestBody .= "<p>The email should be sent with the following properties\n";
$sTestBody .= "<ul>\n";
$sTestBody .= "<li>TO: $sTo</li>\n";
$sTestBody .= "<li>CC: $sCC</li>\n";
$sTestBody .= "<li>BCC: $sBCC</li>\n";
$sTestBody .= "<li>From: $sFrom</li>\n";
$sTestBody .= "<li>Reply-To: $sReplyTo</li>\n";
$sTestBody .= "<li>References: $sReference</li>\n";
$sTestBody .= "</ul>\n";
$sTestBody .= "</p>\n";
$sTestBody .= "</div>\n";
$oEmail->SetBody($sTestBody);
$oEmail->SetRecipientTO($this->Get('test_recipient'));
$oEmail->SetRecipientFrom($this->Get('test_recipient'));
$oEmail->SetReferences($sReference);
}
else
{
$oEmail->SetSubject($sSubject);
$oEmail->SetBody($sBody);
$oEmail->SetRecipientTO($sTo);
$oEmail->SetRecipientCC($sCC);
$oEmail->SetRecipientBCC($sBCC);
$oEmail->SetRecipientFrom($sFrom);
$oEmail->SetRecipientReplyTo($sReplyTo);
$oEmail->SetReferences($sReference);
}
if (empty($this->m_aMailErrors))
{
if ($this->m_iRecipients == 0)
{
$this->m_aMailErrors[] = 'No recipient';
}
else
{
$oKPI = new ExecutionKPI();
$this->m_aMailErrors = array_merge($this->m_aMailErrors, $oEmail->Send());
$oKPI->ComputeStats('Send mail', $sTo);
}
}
}
catch(Exception $e)
catch (Exception $e)
{
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
throw $e;
}
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
if (!is_null($oLog))
$this->m_aMailErrors[] = $e->getMessage();
}
if (MetaModel::IsLogEnabledNotification())
{
$oLog = new EventNotificationEmail();
if (empty($this->m_aMailErrors))
{
if ($this->IsBeingTested())
{
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
}
else
{
$oLog->Set('message', 'Notification sent');
}
}
else
{
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
{
$sError = implode(', ', $this->m_aMailErrors);
}
else
{
$sError = 'Unknown reason';
}
if ($this->IsBeingTested())
{
$oLog->Set('message', 'TEST - Notification was not sent: '.$sError);
}
else
{
$oLog->Set('message', 'Notification was not sent: '.$sError);
}
}
$oLog->Set('userinfo', UserRights::GetUser());
$oLog->Set('trigger_id', $oTrigger->GetKey());
$oLog->Set('action_id', $this->GetKey());
$oLog->Set('object_id', $aContextArgs['this->object()']->GetKey());
// Note: we have to secure this because those values are calculated
// inside the try statement, and we would like to keep track of as
// many data as we could while some variables may still be undefined
@@ -316,79 +342,7 @@ class ActionEmail extends ActionNotification
if (isset($sFrom)) $oLog->Set('from', $sFrom);
if (isset($sSubject)) $oLog->Set('subject', $sSubject);
if (isset($sBody)) $oLog->Set('body', $sBody);
}
$oEmail = new EMail();
if ($this->IsBeingTested())
{
$oEmail->SetSubject('TEST['.$sSubject.']');
$sTestBody = $sBody;
$sTestBody .= "<div style=\"border: dashed;\">\n";
$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
$sTestBody .= "<p>The email should be sent with the following properties\n";
$sTestBody .= "<ul>\n";
$sTestBody .= "<li>TO: $sTo</li>\n";
$sTestBody .= "<li>CC: $sCC</li>\n";
$sTestBody .= "<li>BCC: $sBCC</li>\n";
$sTestBody .= "<li>From: $sFrom</li>\n";
$sTestBody .= "<li>Reply-To: $sReplyTo</li>\n";
$sTestBody .= "<li>References: $sReference</li>\n";
$sTestBody .= "</ul>\n";
$sTestBody .= "</p>\n";
$sTestBody .= "</div>\n";
$oEmail->SetBody($sTestBody);
$oEmail->SetRecipientTO($this->Get('test_recipient'));
$oEmail->SetRecipientFrom($this->Get('test_recipient'));
$oEmail->SetReferences($sReference);
$oEmail->SetMessageId($sMessageId);
}
else
{
$oEmail->SetSubject($sSubject);
$oEmail->SetBody($sBody);
$oEmail->SetRecipientTO($sTo);
$oEmail->SetRecipientCC($sCC);
$oEmail->SetRecipientBCC($sBCC);
$oEmail->SetRecipientFrom($sFrom);
$oEmail->SetRecipientReplyTo($sReplyTo);
$oEmail->SetReferences($sReference);
$oEmail->SetMessageId($sMessageId);
}
if (empty($this->m_aMailErrors))
{
if ($this->m_iRecipients == 0)
{
return 'No recipient';
}
else
{
$iRes = $oEmail->Send($aErrors, false, $oLog); // allow asynchronous mode
switch ($iRes)
{
case EMAIL_SEND_OK:
return "Sent";
case EMAIL_SEND_PENDING:
return "Pending";
case EMAIL_SEND_ERROR:
return "Errors: ".implode(', ', $aErrors);
}
}
}
else
{
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
{
$sError = implode(', ', $this->m_aMailErrors);
}
else
{
$sError = 'Unknown reason';
}
return 'Notification was not sent: '.$sError;
$oLog->DBInsertNoReload();
}
}
}

View File

@@ -1,186 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Persistent classes (internal): user defined actions
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
class ExecAsyncTask implements iBackgroundProcess
{
public function GetPeriodicity()
{
return 2; // seconds
}
public function Process($iTimeLimit)
{
$sOQL = "SELECT AsyncTask WHERE ISNULL(started) AND (ISNULL(planned) OR (planned < NOW()))";
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array());
$iProcessed = 0;
while ((time() < $iTimeLimit) && ($oTask = $oSet->Fetch()))
{
$oTask->Set('started', time());
$oTask->DBUpdate();
$oTask->Process();
$iProcessed++;
$oTask->DBDelete();
}
if ($iProcessed == $oSet->Count())
{
return "processed $iProcessed tasks";
}
else
{
return "processed $iProcessed tasks (remaining: ".($oSet->Count() - $iProcessed).")";
}
}
}
/**
* A
*
* @package iTopORM
*/
abstract class AsyncTask extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => array('created'),
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_async_task",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
// MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("started", array("allowed_values"=>null, "sql"=>"started", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
// planned... still not used - reserved for timer management
MetaModel::Init_AddAttribute(new AttributeDateTime("planned", array("allowed_values"=>null, "sql"=>"planned", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("event_id", array("targetclass"=>"Event", "jointype"=> "", "allowed_values"=>null, "sql"=>"event_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_SILENT, "depends_on"=>array())));
// Display lists
// MetaModel::Init_SetZListItems('details', array()); // Attributes to be displayed for the complete details
// MetaModel::Init_SetZListItems('list', array()); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
protected function OnInsert()
{
$this->Set('created', time());
}
public function Process()
{
$sStatus = $this->DoProcess();
if ($this->Get('event_id') != 0)
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', $sStatus);
$oEventLog->DBUpdate();
}
}
abstract public function DoProcess();
}
/**
* An email notification
*
* @package iTopORM
*/
class AsyncSendEmail extends AsyncTask
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "created",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_async_send_email",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLongText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
// MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
// MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
static public function AddToQueue(EMail $oEMail, $oLog)
{
$oNew = MetaModel::NewObject(__class__);
if ($oLog)
{
$oNew->Set('event_id', $oLog->GetKey());
}
$oNew->Set('to', $oEMail->GetRecipientTO(true /* string */));
$oNew->Set('subject', $oEMail->GetSubject());
$sMessage = serialize($oEMail);
$oNew->Set('message', $sMessage);
$oNew->DBInsert();
}
public function DoProcess()
{
$sMessage = $this->Get('message');
$oEMail = unserialize($sMessage);
$iRes = $oEMail->Send($aIssues, true /* force synchro !!!!! */);
switch ($iRes)
{
case EMAIL_SEND_OK:
return "Sent";
case EMAIL_SEND_PENDING:
return "Bug - the email should be sent in synchronous mode";
case EMAIL_SEND_ERROR:
return "Failed: ".implode(', ', $aIssues);
}
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -1,33 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Class BackgroundProcess
* Any extension that must be called regularly to be executed in the background
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
interface iBackgroundProcess
{
public function GetPeriodicity();
public function Process($iUnixTimeLimit);
}
?>

View File

@@ -52,13 +52,19 @@ abstract class CellChangeSpec
$this->m_sOql = $sOql;
}
public function GetPureValue()
static protected function ValueAsHtml($value)
{
// Todo - distinguish both values
return $this->m_proposedValue;
if (MetaModel::IsValidObject($value))
{
return $value->GetHyperLink();
}
else
{
return htmlentities($value, ENT_QUOTES, 'UTF-8');
}
}
public function GetDisplayableValue()
public function GetValue()
{
return $this->m_proposedValue;
}
@@ -95,10 +101,10 @@ class CellStatus_Modify extends CellChangeSpec
return 'Modified';
}
//public function GetPreviousValue()
//{
// return $this->m_previousValue;
//}
public function GetPreviousValue()
{
return $this->m_previousValue;
}
}
class CellStatus_Issue extends CellStatus_Modify
@@ -252,9 +258,8 @@ class BulkChange
protected $m_aReconcilKeys; // attcode (attcode = 'id' for the pkey)
protected $m_sSynchroScope; // OQL - if specified, then the missing items will be reported
protected $m_aOnDisappear; // array of attcode => value, values to be set when an object gets out of scope (ignored if no scope has been defined)
protected $m_sDateFormat; // Date format specification, see utils::StringToTime()
public function __construct($sClass, $aData, $aAttList, $aExtKeys, $aReconcilKeys, $sSynchroScope = null, $aOnDisappear = null, $sDateFormat = null)
public function __construct($sClass, $aData, $aAttList, $aExtKeys, $aReconcilKeys, $sSynchroScope = null, $aOnDisappear = null)
{
$this->m_sClass = $sClass;
$this->m_aData = $aData;
@@ -263,25 +268,8 @@ class BulkChange
$this->m_aExtKeys = $aExtKeys;
$this->m_sSynchroScope = $sSynchroScope;
$this->m_aOnDisappear = $aOnDisappear;
$this->m_sDateFormat = $sDateFormat;
}
protected $m_bReportHtml = false;
protected $m_sReportCsvSep = ',';
protected $m_sReportCsvDelimiter = '"';
public function SetReportHtml()
{
$this->m_bReportHtml = true;
}
public function SetReportCsv($sSeparator = ',', $sDelimiter = '"')
{
$this->m_bReportHtml = false;
$this->m_sReportCsvSep = $sSeparator;
$this->m_sReportCsvDelimiter = $sDelimiter;
}
protected function ResolveExternalKey($aRowData, $sAttCode, &$aResults)
{
$oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
@@ -400,37 +388,15 @@ class BulkChange
// skip the private key, if any
if ($sAttCode == 'id') continue;
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
$aReasons = array();
$iFlags = $oTargetObj->GetAttributeFlags($sAttCode, $aReasons);
if ( (($iFlags & OPT_ATT_READONLY) == OPT_ATT_READONLY) && ( $oTargetObj->Get($sAttCode) != $aRowData[$iCol]) )
$res = $oTargetObj->CheckValue($sAttCode, $aRowData[$iCol]);
if ($res === true)
{
$aErrors[$sAttCode] = "the attribute '$sAttCode' is read-only and cannot be modified (current value: ".$oTargetObj->Get($sAttCode).", proposed value: {$aRowData[$iCol]}).";
}
else if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect())
{
try
{
$oSet = $oAttDef->MakeValueFromString($aRowData[$iCol]);
$oTargetObj->Set($sAttCode, $oSet);
}
catch(CoreException $e)
{
$aErrors[$sAttCode] = "Failed to process input: ".$e->getMessage();
}
$oTargetObj->Set($sAttCode, $aRowData[$iCol]);
}
else
{
$res = $oTargetObj->CheckValue($sAttCode, $aRowData[$iCol]);
if ($res === true)
{
$oTargetObj->Set($sAttCode, $aRowData[$iCol]);
}
else
{
// $res is a string with the error description
$aErrors[$sAttCode] = "Unexpected value for attribute '$sAttCode': $res";
}
// $res is a string with the error description
$aErrors[$sAttCode] = "Unexpected value for attribute '$sAttCode': $res";
}
}
@@ -443,38 +409,25 @@ class BulkChange
{
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]);
}
if (isset($aErrors[$sAttCode]))
{
$aResults[$iCol]= new CellStatus_Issue($oTargetObj->Get($sAttCode), $oTargetObj->GetOriginal($sAttCode), $aErrors[$sAttCode]);
}
elseif (array_key_exists($sAttCode, $aChangedFields))
{
if ($oTargetObj->IsNew())
{
$aResults[$iCol]= new CellStatus_Void($oTargetObj->Get($sAttCode));
}
else
{
$aResults[$iCol]= new CellStatus_Modify($oTargetObj->Get($sAttCode), $oTargetObj->GetOriginal($sAttCode));
}
}
else
{
if ($this->m_bReportHtml)
{
$sCurValue = $oTargetObj->GetAsHTML($sAttCode);
$sOrigValue = $oTargetObj->GetOriginalAsHTML($sAttCode);
}
else
{
$sCurValue = $oTargetObj->GetAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter);
$sOrigValue = $oTargetObj->GetOriginalAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter);
}
if (isset($aErrors[$sAttCode]))
{
$aResults[$iCol]= new CellStatus_Issue($sCurValue, $sOrigValue, $aErrors[$sAttCode]);
}
elseif (array_key_exists($sAttCode, $aChangedFields))
{
if ($oTargetObj->IsNew())
{
$aResults[$iCol]= new CellStatus_Void($sCurValue);
}
else
{
$aResults[$iCol]= new CellStatus_Modify($sCurValue, $sOrigValue);
}
}
else
{
// By default... nothing happens
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]);
}
// By default... nothing happens
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]);
}
}
@@ -628,14 +581,7 @@ class BulkChange
//
if ($oChange)
{
try
{
$oTargetObj->DBUpdateTracked($oChange);
}
catch(CoreException $e)
{
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue($e->getMessage());
}
$oTargetObj->DBUpdateTracked($oChange);
}
}
else
@@ -664,19 +610,12 @@ class BulkChange
if (count($aChangedFields) > 0)
{
$aResult[$iRow]["__STATUS__"] = new RowStatus_Disappeared(count($aChangedFields));
// Optionaly record the results
//
if ($oChange)
{
try
{
$oTargetObj->DBUpdateTracked($oChange);
}
catch(CoreException $e)
{
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue($e->getMessage());
}
$oTargetObj->DBUpdateTracked($oChange);
}
}
else
@@ -710,35 +649,6 @@ class BulkChange
exit;
}
$aResult = array();
if (!is_null($this->m_sDateFormat) && (strlen($this->m_sDateFormat) > 0))
{
// Translate dates from the source data
//
foreach ($this->m_aAttList as $sAttCode => $iCol)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if ($oAttDef instanceof AttributeDateTime)
{
foreach($this->m_aData as $iRow => $aRowData)
{
$sNewDate = utils::StringToTime($this->m_aData[$iRow][$iCol], $this->m_sDateFormat);
if ($sNewDate !== false)
{
// Todo - improve the reporting
$this->m_aData[$iRow][$iCol] = $sNewDate;
}
else
{
// Leave the cell unchanged
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue("wrong date format");
$aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], 'Wrong date format');
}
}
}
}
}
// Compute the results
//
@@ -746,13 +656,9 @@ class BulkChange
{
$aVisited = array();
}
$aResult = array();
foreach($this->m_aData as $iRow => $aRowData)
{
if (isset($aResult[$iRow]["__STATUS__"]))
{
// An issue at the earlier steps - skip the rest
continue;
}
$oReconciliationFilter = new CMDBSearchFilter($this->m_sClass);
$bSkipQuery = false;
foreach($this->m_aReconcilKeys as $sAttCode)
@@ -839,28 +745,8 @@ class BulkChange
$aResult[$iRow]["finalclass"]= 'n/a';
}
}
}
if (!is_null($this->m_sSynchroScope))
{
// Compute the delta between the scope and visited objects
$oScopeSearch = DBObjectSearch::FromOQL($this->m_sSynchroScope);
$oScopeSet = new DBObjectSet($oScopeSearch);
while ($oObj = $oScopeSet->Fetch())
{
$iObj = $oObj->GetKey();
if (!in_array($iObj, $aVisited))
{
$iRow++;
$this->UpdateMissingObject($aResult, $iRow, $oObj, $oChange);
}
}
}
// Fill in the blanks - the result matrix is expected to be 100% complete
//
foreach($this->m_aData as $iRow => $aRowData)
{
// Whatever happened, do report the reconciliation values
foreach($this->m_aAttList as $iCol)
{
if (!array_key_exists($iCol, $aResult[$iRow]))
@@ -885,6 +771,22 @@ class BulkChange
}
}
if (!is_null($this->m_sSynchroScope))
{
// Compute the delta between the scope and visited objects
$oScopeSearch = DBObjectSearch::FromOQL($this->m_sSynchroScope);
$oScopeSet = new DBObjectSet($oScopeSearch);
while ($oObj = $oScopeSet->Fetch())
{
$iObj = $oObj->GetKey();
if (!in_array($iObj, $aVisited))
{
$iRow++;
$this->UpdateMissingObject($aResult, $iRow, $oObj, $oChange);
}
}
}
return $aResult;
}
@@ -904,7 +806,7 @@ class BulkChange
$oBulkChangeSearch = DBObjectSearch::FromOQL("SELECT CMDBChange WHERE userinfo LIKE '%(CSV)'");
$iQueryLimit = $bShowAll ? 0 : MetaModel::GetConfig()->GetMaxDisplayLimit() + 1;
$oBulkChanges = new DBObjectSet($oBulkChangeSearch, array('date' => false), array(), null, $iQueryLimit);
$oBulkChanges = new DBObjectSet($oBulkChangeSearch, array('date' => false), array(), $iQueryLimit);
$oAppContext = new ApplicationContext();
@@ -914,7 +816,7 @@ class BulkChange
$bLimitExceeded = true;
if (!$bShowAll)
{
$iMaxObjects = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
$iMaxObjects = MetaModel::GetConfig()->GetMinDisplayLimit();
$oBulkChanges->SetLimit($iMaxObjects);
}
}
@@ -923,7 +825,7 @@ class BulkChange
$aDetails = array();
while ($oChange = $oBulkChanges->Fetch())
{
$sDate = '<a href="csvimport.php?step=10&changeid='.$oChange->GetKey().'&'.$oAppContext->GetForLink().'">'.$oChange->Get('date').'</a>';
$sDate = '<a href="?step=10&changeid='.$oChange->GetKey().'&'.$oAppContext->GetForLink().'">'.$oChange->Get('date').'</a>';
$sUser = $oChange->GetUserName();
if (preg_match('/^(.*)\\(CSV\\)$/i', $oChange->Get('userinfo'), $aMatches))
{
@@ -963,10 +865,8 @@ class BulkChange
// Assumption: there is only one class of objects being loaded
// Then the last class found gives us the class for every object
if ( ($iModified > 0) || ($iCreated > 0))
{
$aDetails[] = array('date' => $sDate, 'user' => $sUser, 'class' => $sClass, 'created' => $iCreated, 'modified' => $iModified);
}
$aDetails[] = array('date' => $sDate, 'user' => $sUser, 'class' => $sClass, 'created' => $iCreated, 'modified' => $iModified);
}
@@ -1005,7 +905,7 @@ EOF
<<<EOF
function OnTruncatedHistoryToggle(bShowAll)
{
$.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
$.get('../pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
{
$('#$sAjaxDivId').html(data);
var table = $('#$sAjaxDivId .listResults');
@@ -1068,7 +968,7 @@ EOF
{
$aObjects[$iObjId]['__created__'] = true;
}
elseif ($oOperation instanceof CMDBChangeOpSetAttribute)
elseif (is_subclass_of($oOperation, 'CMDBChangeOpSetAttribute'))
{
$sAttCode = $oOperation->Get('attcode');
@@ -1077,19 +977,10 @@ EOF
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsExternalKey())
{
$sOldValue = Dict::S('UI:UndefinedObject');
if ($oOperation->Get('oldvalue') != 0)
{
$oOldTarget = MetaModel::GetObject($oAttDef->GetTargetClass(), $oOperation->Get('oldvalue'));
$sOldValue = $oOldTarget->GetHyperlink();
}
$sNewValue = Dict::S('UI:UndefinedObject');
if ($oOperation->Get('newvalue') != 0)
{
$oNewTarget = MetaModel::GetObject($oAttDef->GetTargetClass(), $oOperation->Get('newvalue'));
$sNewValue = $oNewTarget->GetHyperlink();
}
$oOldTarget = MetaModel::GetObject($oAttDef->GetTargetClass(), $oOperation->Get('oldvalue'));
$oNewTarget = MetaModel::GetObject($oAttDef->GetTargetClass(), $oOperation->Get('newvalue'));
$sOldValue = $oOldTarget->GetHyperlink();
$sNewValue = $oNewTarget->GetHyperlink();
}
else
{
@@ -1166,49 +1057,6 @@ EOF
}
$oPage->table($aConfig, $aDetails);
}
/**
* Get the user friendly name for an 'extended' attribute code i.e 'name', becomes 'Name' and 'org_id->name' becomes 'Organization->Name'
* @param string $sClassName The name of the class
* @param string $sAttCodeEx Either an attribute code or ext_key_name->att_code
* @return string A user friendly format of the string: AttributeName or AttributeName->ExtAttributeName
*/
public static function GetFriendlyAttCodeName($sClassName, $sAttCodeEx)
{
$sFriendlyName = '';
if (preg_match('/(.+)->(.+)/', $sAttCodeEx, $aMatches) > 0)
{
$sAttribute = $aMatches[1];
$sField = $aMatches[2];
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttribute);
if ($oAttDef->IsExternalKey())
{
$sTargetClass = $oAttDef->GetTargetClass();
$oTargetAttDef = MetaModel::GetAttributeDef($sTargetClass, $sField);
$sFriendlyName = $oAttDef->GetLabel().'->'.$oTargetAttDef->GetLabel();
}
else
{
// hum, hum... should never happen, we'd better raise an exception
throw(new Exception(Dict::Format('UI:CSVImport:ErrorExtendedAttCode', $sAttCodeEx, $sAttribute, $sClassName)));
}
}
else
{
if ($sAttCodeEx == 'id')
{
$sFriendlyName = Dict::S('UI:CSVImport:idField');
}
else
{
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCodeEx);
$sFriendlyName = $oAttDef->GetLabel();
}
}
return $sFriendlyName;
}
}

View File

@@ -200,6 +200,9 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
*/
public function GetDescription()
{
// Temporary, until we change the options of GetDescription() -needs a more global revision
$bIsHtml = true;
$sResult = '';
$oTargetObjectClass = $this->Get('objclass');
$oTargetObjectKey = $this->Get('objkey');
@@ -209,13 +212,44 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
$oMonoObjectSet = new DBObjectSet($oTargetSearch);
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
{
if (!MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) return ''; // Protects against renamed attributes...
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
$sNewValue = $this->Get('newvalue');
$sOldValue = $this->Get('oldvalue');
$sResult = $oAttDef->GetAsHTMLForHistory($sOldValue, $sNewValue);
if ( (($oAttDef->GetType() == 'String') || ($oAttDef->GetType() == 'Text')) &&
(strlen($sNewValue) > strlen($sOldValue)) )
{
// Check if some text was not appended to the field
if (substr($sNewValue,0, strlen($sOldValue)) == $sOldValue) // Text added at the end
{
$sDelta = substr($sNewValue, strlen($sOldValue));
$sResult = Dict::Format('Change:Text_AppendedTo_AttName', $sDelta, $sAttName);
}
else if (substr($sNewValue, -strlen($sOldValue)) == $sOldValue) // Text added at the beginning
{
$sDelta = substr($sNewValue, 0, strlen($sNewValue) - strlen($sOldValue));
$sResult = Dict::Format('Change:Text_AppendedTo_AttName', $sDelta, $sAttName);
}
else
{
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
}
}
elseif($bIsHtml && $oAttDef->IsExternalKey())
{
$sTargetClass = $oAttDef->GetTargetClass();
$sFrom = MetaModel::GetHyperLink($sTargetClass, $sOldValue);
$sTo = MetaModel::GetHyperLink($sTargetClass, $sNewValue);
$sResult = "$sAttName set to $sTo (previous: $sFrom)";
}
elseif ($oAttDef instanceOf AttributeBlob)
{
$sResult = "#@# Issue... found an attribute for which other type of tracking should be made";
}
else
{
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
}
}
return $sResult;
}
@@ -441,98 +475,4 @@ class CMDBChangeOpSetAttributeText extends CMDBChangeOpSetAttribute
}
}
/**
* Record the modification of a caselog (text)
* since the caselog itself stores the history
* of its entries, there is no need to duplicate
* the text here
*
* @package iTopORM
*/
class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "",
"name_attcode" => "change",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_changeop_setatt_log",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeInteger("lastentry", array("allowed_values"=>null, "sql"=>"lastentry", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
public function GetDescription()
{
// Temporary, until we change the options of GetDescription() -needs a more global revision
$bIsHtml = true;
$sResult = '';
$oTargetObjectClass = $this->Get('objclass');
$oTargetObjectKey = $this->Get('objkey');
$oTargetSearch = new DBObjectSearch($oTargetObjectClass);
$oTargetSearch->AddCondition('id', $oTargetObjectKey, '=');
$oMonoObjectSet = new DBObjectSet($oTargetSearch);
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
{
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
$sResult = Dict::Format('Change:AttName_EntryAdded', $sAttName);
}
return $sResult;
}
}
/**
* Record an action made by a plug-in
*
* @package iTopORM
*/
class CMDBChangeOpPlugin extends CMDBChangeOp
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "",
"name_attcode" => "change",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_changeop_plugin",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
/* May be used later when implementing an extension mechanism that will allow the plug-ins to store some extra information and still degrades gracefully when the plug-in is desinstalled
MetaModel::Init_AddAttribute(new AttributeString("extension_class", array("allowed_values"=>null, "sql"=>"extension_class", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("extension_id", array("allowed_values"=>null, "sql"=>"extension_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
*/
MetaModel::Init_InheritAttributes();
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
public function GetDescription()
{
return $this->Get('description');
}
}
?>

View File

@@ -59,8 +59,6 @@ require_once('dbobject.class.php');
require_once('dbobjectsearch.class.php');
require_once('dbobjectset.class.php');
require_once('backgroundprocess.inc.php');
require_once('asynctask.class.inc.php');
require_once('dbproperty.class.inc.php');
// db change tracking data model
@@ -76,7 +74,6 @@ require_once('cmdbchangeop.class.inc.php');
// Romain: temporary moved into application.inc.php (see explanations there)
//require_once('event.class.inc.php');
require_once('templatestring.class.inc.php');
require_once('csvparser.class.inc.php');
require_once('bulkchange.class.inc.php');
@@ -93,23 +90,6 @@ abstract class CMDBObject extends DBObject
protected static $m_oCurrChange = null;
public static function SetCurrentChange(CMDBChange $oChange)
{
self::$m_oCurrChange = $oChange;
}
//
// Todo: simplify the APIs and do not pass the current change as an argument anymore
// SetCurrentChange to be invoked in very few cases (UI.php, CSV import, Data synchro)
// GetCurrentChange to be called ONCE (!) by CMDBChangeOp::OnInsert ($this->Set('change', ..GetCurrentChange())
// GetCurrentChange to create a default change if not already done in the current context
//
public static function GetCurrentChange()
{
return self::$m_oCurrChange;
}
private function RecordObjCreation(CMDBChange $oChange)
{
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpCreate");
@@ -133,18 +113,8 @@ abstract class CMDBObject extends DBObject
foreach ($aValues as $sAttCode=> $value)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
if ($oAttDef->IsExternalField()) continue; // #@# temporary
if ($oAttDef->IsLinkSet()) continue; // #@# temporary
if (array_key_exists($sAttCode, $aOrigValues))
{
$original = $aOrigValues[$sAttCode];
}
else
{
$original = null;
}
if ($oAttDef instanceOf AttributeOneWayPassword)
{
// One Way encrypted passwords' history is stored -one way- encrypted
@@ -154,7 +124,11 @@ abstract class CMDBObject extends DBObject
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
if (is_null($original))
if (array_key_exists($sAttCode, $aOrigValues))
{
$original = $aOrigValues[$sAttCode];
}
else
{
$original = '';
}
@@ -170,7 +144,11 @@ abstract class CMDBObject extends DBObject
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
if (is_null($original))
if (array_key_exists($sAttCode, $aOrigValues))
{
$original = $aOrigValues[$sAttCode];
}
else
{
$original = '';
}
@@ -186,51 +164,17 @@ abstract class CMDBObject extends DBObject
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
if (is_null($original))
if (array_key_exists($sAttCode, $aOrigValues))
{
$original = $aOrigValues[$sAttCode];
}
else
{
$original = new ormDocument();
}
$oMyChangeOp->Set("prevdata", $original);
$iId = $oMyChangeOp->DBInsertNoReload();
}
elseif ($oAttDef instanceOf AttributeStopWatch)
{
// Stop watches - record changes for sub items only (they are visible, the rest is not visible)
//
if (is_null($original))
{
$original = new OrmStopWatch();
}
foreach ($oAttDef->ListSubItems() as $sSubItemAttCode => $oSubItemAttDef)
{
$item_value = $oSubItemAttDef->GetValue($value);
$item_original = $oSubItemAttDef->GetValue($original);
if ($item_value != $item_original)
{
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeScalar");
$oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sSubItemAttCode);
$oMyChangeOp->Set("oldvalue", $item_original);
$oMyChangeOp->Set("newvalue", $item_value);
$iId = $oMyChangeOp->DBInsertNoReload();
}
}
}
elseif ($oAttDef instanceOf AttributeCaseLog)
{
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeCaseLog");
$oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
$oMyChangeOp->Set("lastentry", $value->GetLatestEntryIndex());
$iId = $oMyChangeOp->DBInsertNoReload();
}
elseif ($oAttDef instanceOf AttributeText)
{
// Data blobs
@@ -240,9 +184,13 @@ abstract class CMDBObject extends DBObject
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
if (!is_null($original) && ($original instanceof ormCaseLog))
if (array_key_exists($sAttCode, $aOrigValues))
{
$original = $original->GetText();
$original = $aOrigValues[$sAttCode];
}
else
{
$original = null;
}
$oMyChangeOp->Set("prevdata", $original);
$iId = $oMyChangeOp->DBInsertNoReload();
@@ -256,7 +204,16 @@ abstract class CMDBObject extends DBObject
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
$oMyChangeOp->Set("oldvalue", $original);
if (array_key_exists($sAttCode, $aOrigValues))
{
$sOriginalValue = $aOrigValues[$sAttCode];
}
else
{
$sOriginalValue = 'undefined';
}
$oMyChangeOp->Set("oldvalue", $sOriginalValue);
$oMyChangeOp->Set("newvalue", $value);
$iId = $oMyChangeOp->DBInsertNoReload();
}
@@ -305,10 +262,9 @@ abstract class CMDBObject extends DBObject
{
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$ret = $this->DBInsertTracked_Internal();
self::$m_oCurrChange = $oPreviousChange;
self::$m_oCurrChange = null;
return $ret;
}
@@ -316,10 +272,9 @@ abstract class CMDBObject extends DBObject
{
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$ret = $this->DBInsertTracked_Internal(true);
self::$m_oCurrChange = $oPreviousChange;
self::$m_oCurrChange = null;
return $ret;
}
@@ -348,10 +303,9 @@ abstract class CMDBObject extends DBObject
public function DBCloneTracked(CMDBChange $oChange, $newKey = null)
{
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$this->DBCloneTracked_Internal($newKey);
self::$m_oCurrChange = $oPreviousChange;
self::$m_oCurrChange = null;
}
protected function DBCloneTracked_Internal($newKey = null)
@@ -376,10 +330,9 @@ abstract class CMDBObject extends DBObject
{
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$this->DBUpdateTracked_Internal();
self::$m_oCurrChange = $oPreviousChange;
self::$m_oCurrChange = null;
}
protected function DBUpdateTracked_Internal()
@@ -399,29 +352,28 @@ abstract class CMDBObject extends DBObject
return $ret;
}
public function DBDelete(&$oDeletionPlan = null)
public function DBDelete()
{
if(!self::$m_oCurrChange)
{
throw new CoreException("DBDelete() could not be used here, please use DBDeleteTracked() instead");
}
return $this->DBDeleteTracked_Internal($oDeletionPlan);
return $this->DBDeleteTracked_Internal();
}
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null)
{
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_DELETE);
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$this->DBDeleteTracked_Internal($oDeletionPlan);
self::$m_oCurrChange = $oPreviousChange;
$this->DBDeleteTracked_Internal();
self::$m_oCurrChange = null;
}
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
protected function DBDeleteTracked_Internal()
{
$prevkey = $this->GetKey();
$ret = parent::DBDelete($oDeletionPlan);
$ret = parent::DBDelete();
$this->RecordObjDeletion(self::$m_oCurrChange, $prevkey);
return $ret;
}
@@ -437,10 +389,9 @@ abstract class CMDBObject extends DBObject
public static function BulkDeleteTracked(CMDBChange $oChange, DBObjectSearch $oFilter)
{
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$this->BulkDeleteTracked_Internal($oFilter);
self::$m_oCurrChange = $oPreviousChange;
self::$m_oCurrChange = null;
}
protected static function BulkDeleteTracked_Internal(DBObjectSearch $oFilter)
@@ -477,10 +428,9 @@ abstract class CMDBObject extends DBObject
public static function BulkUpdateTracked(CMDBChange $oChange, DBObjectSearch $oFilter, array $aValues)
{
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$this->BulkUpdateTracked_Internal($oFilter, $aValues);
self::$m_oCurrChange = $oPreviousChange;
self::$m_oCurrChange = null;
}
protected static function BulkUpdateTracked_Internal(DBObjectSearch $oFilter, array $aValues)
@@ -531,22 +481,24 @@ class CMDBObjectSet extends DBObjectSet
static public function FromScratch($sClass)
{
$oFilter = new CMDBSearchFilter($sClass);
$oFilter->AddConditionExpression(new FalseExpression());
$oRetSet = new self($oFilter);
// NOTE: THIS DOES NOT WORK IF m_bLoaded is private in the base class (and you will not get any error message)
$oRetSet = new CMDBObjectSet($oFilter); // THE ONLY DIFF IS HERE
// NOTE: THIS DOES NOT WORK IF m_bLoaded is private...
// BUT IT THAT CASE YOU DO NOT GET ANY ERROR !!!!!
$oRetSet->m_bLoaded = true; // no DB load
return $oRetSet;
}
// create an object set ex nihilo
// input = array of objects
static public function FromArray($sClass, $aObjects)
{
$oRetSet = self::FromScratch($sClass);
$oRetSet->AddObjectArray($aObjects, $sClass);
$oFilter = new CMDBSearchFilter($sClass);
$oRetSet = new CMDBObjectSet($oFilter); // THE ONLY DIFF IS HERE
// NOTE: THIS DOES NOT WORK IF m_bLoaded is private...
// BUT IT THAT CASE YOU DO NOT GET ANY ERROR !!!!!
$oRetSet->m_bLoaded = true; // no DB load
$oRetSet->AddObjectArray($aObjects);
return $oRetSet;
}
static public function FromArrayAssoc($aClasses, $aObjects)
{
// In a perfect world, we should create a complete tree of DBObjectSearch,

View File

@@ -24,14 +24,13 @@
*/
require_once('MyHelpers.class.inc.php');
require_once(APPROOT.'core/kpi.class.inc.php');
class MySQLException extends CoreException
{
public function __construct($sIssue, $aContext)
{
$aContext['mysql_error'] = CMDBSource::GetError();
$aContext['mysql_errno'] = CMDBSource::GetErrNo();;
$aContext['mysql_error'] = mysql_error();
$aContext['mysql_errno'] = mysql_errno();
parent::__construct($sIssue, $aContext);
}
}
@@ -57,13 +56,13 @@ class CMDBSource
self::$m_sDBUser = $sUser;
self::$m_sDBPwd = $sPwd;
self::$m_sDBName = $sSource;
if (!self::$m_resDBLink = @mysqli_connect($sServer, $sUser, $sPwd))
if (!self::$m_resDBLink = @mysql_pconnect($sServer, $sUser, $sPwd))
{
throw new MySQLException('Could not connect to the DB server', array('host'=>$sServer, 'user'=>$sUser));
}
if (!empty($sSource))
{
if (!((bool)mysqli_query(self::$m_resDBLink, "USE $sSource")))
if (!mysql_select_db($sSource, self::$m_resDBLink))
{
throw new MySQLException('Could not select DB', array('host'=>$sServer, 'user'=>$sUser, 'db_name'=>$sSource));
}
@@ -85,17 +84,6 @@ class CMDBSource
}
}
public static function SetTimezone($sTimezone = null)
{
// Note: requires the installation of MySQL special tables,
// otherwise, only 'SYSTEM' or "+10:00' may be specified which is NOT sufficient because of day light saving times
if (!is_null($sTimezone))
{
$sQuotedTimezone = self::Quote($sTimezone);
self::Query("SET time_zone = $sQuotedTimezone");
}
}
public static function ListDB()
{
$aDBs = self::QueryToCol('SHOW DATABASES', 'Database');
@@ -119,7 +107,7 @@ class CMDBSource
{
// In case we don't have rights to enumerate the databases
// Let's try to connect directly
return @((bool)mysqli_query(self::$m_resDBLink, "USE $sSource"));
return @mysql_select_db($sSource, self::$m_resDBLink);
}
}
@@ -132,7 +120,7 @@ class CMDBSource
public static function SelectDB($sSource)
{
if (!((bool)mysqli_query(self::$m_resDBLink, "USE $sSource")))
if (!mysql_select_db($sSource, self::$m_resDBLink))
{
throw new MySQLException('Could not select DB', array('db_name'=>$sSource));
}
@@ -172,30 +160,6 @@ class CMDBSource
return $res;
}
public static function GetErrNo()
{
if (self::$m_resDBLink)
{
return mysqli_errno(self::$m_resDBLink);
}
else
{
return mysqli_connect_errno();
}
}
public static function GetError()
{
if (self::$m_resDBLink)
{
return mysqli_error(self::$m_resDBLink);
}
else
{
return mysqli_connect_error();
}
}
public static function DBHost() {return self::$m_sDBHost;}
public static function DBUser() {return self::$m_sDBUser;}
public static function DBPwd() {return self::$m_sDBPwd;}
@@ -233,7 +197,7 @@ class CMDBSource
// Quote if not a number or a numeric string
if ($bAlways || is_string($value))
{
$value = $cQuoteStyle . mysqli_real_escape_string(self::$m_resDBLink, $value) . $cQuoteStyle;
$value = $cQuoteStyle . mysql_real_escape_string($value, self::$m_resDBLink) . $cQuoteStyle;
}
return $value;
}
@@ -247,7 +211,7 @@ class CMDBSource
// $sSQLQuery .= MyHelpers::MakeSQLComment($aTraceInf);
$oKPI = new ExecutionKPI();
$result = mysqli_query(self::$m_resDBLink, $sSQLQuery);
$result = mysql_query($sSQLQuery, self::$m_resDBLink);
if (!$result)
{
throw new MySQLException('Failed to issue SQL query', array('query' => $sSQLQuery));
@@ -261,21 +225,15 @@ class CMDBSource
{
$sSQL = "SHOW TABLE STATUS LIKE '$sTable'";
$result = self::Query($sSQL);
$aRow = mysqli_fetch_assoc($result);
$aRow = mysql_fetch_assoc($result);
$iNextInsertId = $aRow['Auto_increment'];
return $iNextInsertId;
}
public static function GetInsertId()
{
$iRes = mysqli_insert_id(self::$m_resDBLink);
if (is_null($iRes))
{
return 0;
}
return $iRes;
return mysql_insert_id(self::$m_resDBLink);
}
public static function InsertInto($sSQLQuery)
{
if (self::Query($sSQLQuery))
@@ -285,44 +243,19 @@ class CMDBSource
return false;
}
public static function DeleteFrom($sSQLQuery)
{
self::Query($sSQLQuery);
}
public static function QueryToScalar($sSql)
{
$result = mysqli_query(self::$m_resDBLink, $sSql);
if (!$result)
{
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
}
if ($aRow = mysqli_fetch_array($result, MYSQLI_BOTH))
{
$res = $aRow[0];
}
else
{
mysqli_free_result($result);
throw new MySQLException('Found no result for query', array('query' => $sSql));
}
mysqli_free_result($result);
return $res;
}
public static function QueryToArray($sSql)
{
$aData = array();
$result = mysqli_query(self::$m_resDBLink, $sSql);
$result = mysql_query($sSql, self::$m_resDBLink);
if (!$result)
{
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
}
while ($aRow = mysqli_fetch_array($result, MYSQLI_BOTH))
while ($aRow = mysql_fetch_array($result, MYSQL_BOTH))
{
$aData[] = $aRow;
}
mysqli_free_result($result);
mysql_free_result($result);
return $aData;
}
@@ -340,7 +273,7 @@ class CMDBSource
public static function ExplainQuery($sSql)
{
$aData = array();
$result = mysqli_query(self::$m_resDBLink, "EXPLAIN $sSql");
$result = mysql_query("EXPLAIN $sSql", self::$m_resDBLink);
if (!$result)
{
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
@@ -349,62 +282,62 @@ class CMDBSource
$aNames = self::GetColumns($result);
$aData[] = $aNames;
while ($aRow = mysqli_fetch_array($result, MYSQLI_ASSOC))
while ($aRow = mysql_fetch_array($result, MYSQL_ASSOC))
{
$aData[] = $aRow;
}
mysqli_free_result($result);
mysql_free_result($result);
return $aData;
}
public static function TestQuery($sSql)
{
$result = mysqli_query(self::$m_resDBLink, "EXPLAIN $sSql");
$result = mysql_query("EXPLAIN $sSql", self::$m_resDBLink);
if (!$result)
{
return self::GetError();
return mysql_error();
}
mysqli_free_result($result);
mysql_free_result($result);
return '';
}
public static function NbRows($result)
{
return mysqli_num_rows($result);
return mysql_num_rows($result);
}
public static function FetchArray($result)
{
return mysqli_fetch_array($result, MYSQLI_ASSOC);
return mysql_fetch_array($result, MYSQL_ASSOC);
}
public static function GetColumns($result)
{
$aNames = array();
for ($i = 0; $i < (($___mysqli_tmp = mysqli_num_fields($result)) ? $___mysqli_tmp : 0) ; $i++)
for ($i = 0; $i < mysql_num_fields($result) ; $i++)
{
$meta = mysqli_fetch_field_direct($result, $i);
if (!$meta)
{
$meta = mysql_fetch_field($result, $i);
if (!$meta)
{
throw new MySQLException('mysql_fetch_field: No information available', array('query'=>$sSql, 'i'=>$i));
}
else
{
$aNames[] = $meta->name;
}
}
else
{
$aNames[] = $meta->name;
}
}
return $aNames;
}
public static function Seek($result, $iRow)
{
return mysqli_data_seek($result, $iRow);
return mysql_data_seek($result, $iRow);
}
public static function FreeResult($result)
{
return ((mysqli_free_result($result) || (is_object($result) && (get_class($result) == "mysqli_result"))) ? true : false);
return mysql_free_result($result);
}
public static function IsTable($sTable)
@@ -542,18 +475,18 @@ class CMDBSource
public static function DumpTable($sTable)
{
$sSql = "SELECT * FROM `$sTable`";
$result = mysqli_query(self::$m_resDBLink, $sSql);
$result = mysql_query($sSql, self::$m_resDBLink);
if (!$result)
{
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
}
$aRows = array();
while ($aRow = mysqli_fetch_array($result, MYSQLI_ASSOC))
while ($aRow = mysql_fetch_array($result, MYSQL_ASSOC))
{
$aRows[] = $aRow;
}
mysqli_free_result($result);
mysql_free_result($result);
return $aRows;
}
@@ -591,12 +524,12 @@ class CMDBSource
}
$aRes = array();
while ($aRow = mysqli_fetch_array($result, MYSQLI_NUM))
while ($aRow = mysql_fetch_array($result, MYSQL_NUM))
{
// so far, only one column...
$aRes[] = implode('/', $aRow);
}
mysqli_free_result($result);
mysql_free_result($result);
// so far, only one line...
return implode(', ', $aRes);
}
@@ -616,14 +549,14 @@ class CMDBSource
throw new CoreException("Current user not allowed to check the status", array('mysql_error' => $e->getMessage()));
}
if (mysqli_num_rows($result) == 0)
if (mysql_num_rows($result) == 0)
{
return false;
}
// Returns one single row anytime
$aRow = mysqli_fetch_array($result, MYSQLI_ASSOC);
mysqli_free_result($result);
$aRow = mysql_fetch_array($result, MYSQL_ASSOC);
mysql_free_result($result);
if (!isset($aRow['Slave_IO_Running']))
{

View File

@@ -1,121 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Any extension to compute things like a stop watch deadline or working hours
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
/**
* Metric computing for stop watches
*/
interface iMetricComputer
{
public static function GetDescription();
public function ComputeMetric($oObject);
}
/**
* Working time computing for stop watches
*/
interface iWorkingTimeComputer
{
public static function GetDescription();
/**
* Get the date/time corresponding to a given delay in the future from the present
* considering only the valid (open) hours for a specified object
* @param $oObject DBObject The object for which to compute the deadline
* @param $iDuration integer The duration (in seconds) in the future
* @param $oStartDate DateTime The starting point for the computation
* @return DateTime The date/time for the deadline
*/
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate);
/**
* Get duration (considering only open hours) elapsed bewteen two given DateTimes
* @param $oObject DBObject The object for which to compute the duration
* @param $oStartDate DateTime The starting point for the computation (default = now)
* @param $oEndDate DateTime The ending point for the computation (default = now)
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
*/
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate);
}
/**
* Default implementation oof deadline computing: NO deadline
*/
class DefaultMetricComputer implements iMetricComputer
{
public static function GetDescription()
{
return "Null";
}
public function ComputeMetric($oObject)
{
return null;
}
}
/**
* Default implementation of working time computing
*/
class DefaultWorkingTimeComputer implements iWorkingTimeComputer
{
public static function GetDescription()
{
return "24x7, no holidays";
}
/**
* Get the date/time corresponding to a given delay in the future from the present
* considering only the valid (open) hours for a specified object
* @param $oObject DBObject The object for which to compute the deadline
* @param $iDuration integer The duration (in seconds) in the future
* @param $oStartDate DateTime The starting point for the computation
* @return DateTime The date/time for the deadline
*/
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate)
{
//echo "GetDeadline - default: ".$oStartDate->format('Y-m-d H:i:s')." + $iDuration<br/>\n";
// Default implementation: 24x7, no holidays: to compute the deadline, just add
// the specified duration to the given date/time
$oResult = clone $oStartDate;
$oResult->modify('+'.$iDuration.' seconds');
return $oResult;
}
/**
* Get duration (considering only open hours) elapsed bewteen two given DateTimes
* @param $oObject DBObject The object for which to compute the duration
* @param $oStartDate DateTime The starting point for the computation (default = now)
* @param $oEndDate DateTime The ending point for the computation (default = now)
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
*/
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate)
{
//echo "GetOpenDuration - default: ".$oStartDate->format('Y-m-d H:i:s')." to ".$oEndDate->format('Y-m-d H:i:s')."<br/>\n";
return abs($oEndDate->format('U') - $oStartDate->format('U'));
}
}
?>

View File

@@ -14,7 +14,6 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
define('ITOP_APPLICATION', 'iTop');
define('ITOP_VERSION', '$ITOP_VERSION$');
define('ITOP_REVISION', '$WCREV$');
define('ITOP_BUILD_DATE', '$WCNOW$');
@@ -40,7 +39,7 @@ class ConfigException extends CoreException
}
define ('DEFAULT_CHARACTER_SET', 'utf8');
define ('DEFAULT_COLLATION', 'utf8_unicode_ci');
define ('DEFAULT_COLLATION', 'utf8_general_ci');
define ('DEFAULT_LOG_GLOBAL', true);
define ('DEFAULT_LOG_NOTIFICATION', true);
@@ -58,6 +57,7 @@ define ('DEFAULT_MAX_DISPLAY_LIMIT', 15);
define ('DEFAULT_STANDARD_RELOAD_INTERVAL', 5*60);
define ('DEFAULT_FAST_RELOAD_INTERVAL', 1*60);
define ('DEFAULT_SECURE_CONNECTION_REQUIRED', false);
define ('DEFAULT_HTTPS_HYPERLINKS', false);
define ('DEFAULT_ALLOWED_LOGIN_TYPES', 'form|basic|external');
define ('DEFAULT_EXT_AUTH_VARIABLE', '$_SERVER[\'REMOTE_USER\']');
define ('DEFAULT_ENCRYPTION_KEY', '@iT0pEncr1pti0n!'); // We'll use a random value, later...
@@ -84,22 +84,6 @@ class Config
// New way to store the settings !
//
protected $m_aSettings = array(
'app_env_label' => array(
'type' => 'string',
'description' => 'Label displayed to describe the current application environnment, defaults to the environment name (e.g. "production")',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'app_root_url' => array(
'type' => 'string',
'description' => 'Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server\'s name)',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'skip_check_to_write' => array(
'type' => 'bool',
'description' => 'Disable data format and integrity checks to boost up data load (insert or update)',
@@ -110,7 +94,7 @@ class Config
),
'skip_check_ext_keys' => array(
'type' => 'bool',
'description' => 'Disable external key check when checking the value of attributes',
'description' => 'Disable external key check when checking the value of attribtutes',
'default' => false,
'value' => false,
'source_of_value' => '',
@@ -132,14 +116,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'php_path' => array(
'type' => 'string',
'description' => 'Path to the php executable in CLI mode',
'default' => 'php',
'value' => 'php',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'session_name' => array(
'type' => 'string',
'description' => 'The name of the cookie used to store the PHP session id',
@@ -149,7 +125,7 @@ class Config
'show_in_conf_sample' => true,
),
'max_combo_length' => array(
'type' => 'integer',
'type' => 'int',
'description' => 'The maximum number of elements in a drop-down list. If more then an autocomplete will be used',
'default' => 50,
'value' => 50,
@@ -157,7 +133,7 @@ class Config
'show_in_conf_sample' => false,
),
'min_autocomplete_chars' => array(
'type' => 'integer',
'type' => 'int',
'description' => 'The minimum number of characters to type in order to trigger the "autocomplete" behavior',
'default' => 3,
'value' => 3,
@@ -229,324 +205,12 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'log_usage' => array(
'type' => 'bool',
'description' => 'Log the usage of the application (i.e. the date/time and the user name of each login)',
'default' => false,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'synchro_trace' => array(
'type' => 'string',
'description' => 'Synchronization details: none, display, save (includes \'display\')',
'default' => 'none',
'value' => 'none',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'link_set_item_separator' => array(
'type' => 'string',
'description' => 'Link set from string: line separator',
'default' => '|',
'value' => '|',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'link_set_attribute_separator' => array(
'type' => 'string',
'description' => 'Link set from string: attribute separator',
'default' => ';',
'value' => ';',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'link_set_value_separator' => array(
'type' => 'string',
'description' => 'Link set from string: value separator (between the attcode and the value itself',
'default' => ':',
'value' => ':',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'link_set_attribute_qualifier' => array(
'type' => 'string',
'description' => 'Link set from string: attribute qualifier (encloses both the attcode and the value)',
'default' => "'",
'value' => "'",
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cron_max_execution_time' => array(
'type' => 'integer',
'description' => 'Duration (seconds) of the page cron.php, must be shorter than php setting max_execution_time and shorter than the web server response timeout',
'default' => 600,
'value' => 600,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cron_sleep' => array(
'type' => 'integer',
'description' => 'Duration (seconds) before cron.php checks again if something must be done',
'default' => 2,
'value' => 2,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'email_asynchronous' => array(
'type' => 'bool',
'description' => 'If set, the emails are sent off line, which requires cron.php to be activated. Exception: some features like the email test utility will force the serialized mode',
'default' => false,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'email_transport' => array(
'type' => 'string',
'description' => 'Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocole)',
'default' => "PHPMail",
'value' => "PHPMail",
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'email_transport_smtp.host' => array(
'type' => 'string',
'description' => 'host name or IP address (optional)',
'default' => "localhost",
'value' => "localhost",
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'email_transport_smtp.port' => array(
'type' => 'integer',
'description' => 'port number (optional)',
'default' => 25,
'value' => 25,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'email_transport_smtp.encryption' => array(
'type' => 'string',
'description' => 'tls or ssl (optional)',
'default' => "",
'value' => "",
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'email_transport_smtp.username' => array(
'type' => 'string',
'description' => 'Authentication user (optional)',
'default' => "",
'value' => "",
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'email_transport_smtp.password' => array(
'type' => 'string',
'description' => 'Authentication password (optional)',
'default' => "",
'value' => "",
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'apc_cache.enabled' => array(
'type' => 'bool',
'description' => 'If set, the APC cache is allowed (the PHP extension must also be active)',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'apc_cache.query_ttl' => array(
'type' => 'integer',
'description' => 'Time to live set in APC for the prepared queries (seconds - 0 means no timeout)',
'default' => 3600,
'value' => 3600,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'timezone' => array(
'type' => 'string',
'description' => 'Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitely configured in PHP',
// examples... not used (nor 'description')
'examples' => array('America/Sao_Paulo', 'America/New_York (standing for EDT)', 'America/Los_Angeles (standing for PDT)', 'Asia/Istanbul', 'Asia/Singapore', 'Africa/Casablanca', 'Australia/Sydney'),
'default' => 'Europe/Paris',
'value' => 'Europe/Paris',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_include_path' => array(
'type' => 'string',
'description' => 'The path where to find the phpCAS library',
// examples... not used (nor 'description')
'default' => '/usr/share/php',
'value' => '/usr/share/php',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_version' => array(
'type' => 'string',
'description' => 'The CAS protocol version to use: "1.0" (CAS v1), "2.0" (CAS v2) or "S1" (SAML V1) )',
// examples... not used (nor 'description')
'default' => '2.0',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_host' => array(
'type' => 'string',
'description' => 'The name of the CAS host',
// examples... not used (nor 'description')
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_port' => array(
'type' => 'integer',
'description' => 'The port used by the CAS server',
// examples... not used (nor 'description')
'default' => 443,
'value' => 443,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_context' => array(
'type' => 'string',
'description' => 'The CAS context',
// examples... not used (nor 'description')
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_server_ca_cert_path' => array(
'type' => 'string',
'description' => 'The path where to find the certificate of the CA for validating the certificate of the CAS server',
// examples... not used (nor 'description')
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_logout_redirect_service' => array(
'type' => 'string',
'description' => 'The redirect service (URL) to use when logging-out with CAS',
// examples... not used (nor 'description')
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_memberof' => array(
'type' => 'string',
'description' => 'A semicolon separated list of group names that the user must be member of (works only with SAML - e.g. cas_version=> "S1")',
// examples... not used (nor 'description')
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_user_synchro' => array(
'type' => 'bool',
'description' => 'Whether or not to synchronize users with CAS/LDAP',
// examples... not used (nor 'description')
'default' => 0,
'value' => 0,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_update_profiles' => array(
'type' => 'bool',
'description' => 'Whether or not to update the profiles of an existing user from the CAS information',
// examples... not used (nor 'description')
'default' => 0,
'value' => 0,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_profile_pattern' => array(
'type' => 'string',
'description' => 'A regular expression pattern to extract the name of the iTop profile from the name of an LDAP/CAS group',
// examples... not used (nor 'description')
'default' => '/^cn=([^,]+),/',
'value' => '/^cn=([^,]+),/',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_default_profiles' => array(
'type' => 'string',
'description' => 'A semi-colon separated list of iTop Profiles to use when creating a new user if no profile is retrieved from CAS',
// examples... not used (nor 'description')
'default' => 'Portal user',
'value' => 'Portal user',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cas_debug' => array(
'type' => 'bool',
'description' => 'Activate the CAS debug',
// examples... not used (nor 'description')
'default' => false,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'deadline_format' => array(
'type' => 'string',
'description' => 'The format used for displaying "deadline" attributes: any string with the following placeholders: $date$, $difference$',
// examples... $date$ ($deadline$)
'default' => '$difference$',
'value' => '$difference$',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'buttons_position' => array(
'type' => 'string',
'description' => 'Position of the forms buttons: bottom | top | both',
// examples... not used
'default' => 'both',
'value' => 'both',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'shortcut_actions' => array(
'type' => 'string',
'description' => 'Actions that are available as direct buttons next to the "Actions" menu',
// examples... not used
'default' => 'UI:Menu:Modify,UI:Menu:New',
'value' => 'UI:Menu:Modify',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'synchro_prevent_delete_all' => array(
'type' => 'bool',
'description' => 'Stop the synchro if all the replicas of a data source become obsolete at the same time.',
// examples... not used
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'source_dir' => array(
'type' => 'string',
'description' => 'Source directory for the datamodel files. (which gets compiled to env-production).',
// examples... not used
'default' => 'datamodels/latest',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
);
public function IsProperty($sPropCode)
{
return (array_key_exists($sPropCode, $this->m_aSettings));
}
public function GetDescription($sPropCode)
{
return $this->m_aSettings[$sPropCode];
}
public function Set($sPropCode, $value, $sSourceDesc = 'unknown')
{
@@ -595,8 +259,8 @@ class Config
protected $m_bLogNotification;
protected $m_bLogIssue;
protected $m_bLogWebService;
protected $m_bLogKPIDuration; // private setting
protected $m_bLogKPIMemory; // private setting
protected $m_bLogKpiDuration; // private setting
protected $m_bLogKpiMemory; // private setting
protected $m_bDebugQueries; // private setting
protected $m_bQueryCacheEnabled; // private setting
@@ -625,6 +289,13 @@ class Config
*/
protected $m_bSecureConnectionRequired;
/**
* @var boolean Forces iTop to output hyperlinks starting with https:// even
* if the current page is not using https. This can be useful when
* the application runs behind a SSL gateway
*/
protected $m_bHttpsHyperlinks;
/**
* @var string Langage code, default if the user language is undefined
*/
@@ -653,23 +324,16 @@ class Config
*/
protected $m_aCharsets;
public function __construct($sConfigFile = null, $bLoadConfig = true)
public function __construct($sConfigFile, $bLoadConfig = true)
{
$this->m_sFile = $sConfigFile;
if (is_null($sConfigFile))
{
$bLoadConfig = false;
}
$this->m_aAppModules = array(
// Some default modules, always present can be move to an official iTop Module later if needed
'application/transaction.class.inc.php',
'application/menunode.class.inc.php',
'application/user.preferences.class.inc.php',
'application/user.dashboard.class.inc.php',
'application/audit.rule.class.inc.php',
'application/query.class.inc.php',
// Romain - That's dirty, because those classes are in fact part of the core
// Romain - That's dirty, because those 3 classes are in fact part of the core
// but I needed those classes to be derived from cmdbAbstractObject
// (to be managed via the GUI) and this class in not really known from
// the core, PLUS I needed the includes to be there also for the setup
@@ -677,7 +341,6 @@ class Config
'core/event.class.inc.php',
'core/action.class.inc.php',
'core/trigger.class.inc.php',
'synchro/synchrodatasource.class.inc.php',
);
$this->m_aDataModels = array();
$this->m_aWebServiceCategories = array(
@@ -687,8 +350,25 @@ class Config
// Default AddOn, always present can be moved to an official iTop Module later if needed
'user rights' => 'addons/userrights/userrightsprofile.class.inc.php',
);
$this->m_aDictionaries = self::ScanDictionariesDir();
$this->m_aDictionaries = array(
// Default dictionaries, always present can be moved to an official iTop Module later if needed
'dictionaries/dictionary.itop.core.php',
'dictionaries/dictionary.itop.ui.php', // Support for English
'dictionaries/fr.dictionary.itop.ui.php', // Support for French
'dictionaries/fr.dictionary.itop.core.php', // Support for French
'dictionaries/es_cr.dictionary.itop.ui.php', // Support for Spanish (from Costa Rica)
'dictionaries/es_cr.dictionary.itop.core.php', // Support for Spanish (from Costa Rica)
'dictionaries/de.dictionary.itop.ui.php', // Support for German
'dictionaries/de.dictionary.itop.core.php', // Support for German
'dictionaries/pt_br.dictionary.itop.ui.php', // Support for Brazilian Portuguese
'dictionaries/pt_br.dictionary.itop.core.php', // Support for Brazilian Portuguese
'dictionaries/ru.dictionary.itop.ui.php', // Support for Russian
'dictionaries/ru.dictionary.itop.core.php', // Support for Russian
'dictionaries/tr.dictionary.itop.ui.php', // Support for Turkish
'dictionaries/tr.dictionary.itop.core.php', // Support for Turkish
'dictionaries/zh.dictionary.itop.ui.php', // Support for Chinese
'dictionaries/zh.dictionary.itop.core.php', // Support for Chinese
);
foreach($this->m_aSettings as $sPropCode => $aSettingInfo)
{
$this->m_aSettings[$sPropCode]['value'] = $aSettingInfo['default'];
@@ -712,6 +392,7 @@ class Config
$this->m_iStandardReloadInterval = DEFAULT_STANDARD_RELOAD_INTERVAL;
$this->m_iFastReloadInterval = DEFAULT_FAST_RELOAD_INTERVAL;
$this->m_bSecureConnectionRequired = DEFAULT_SECURE_CONNECTION_REQUIRED;
$this->m_bHttpsHyperlinks = DEFAULT_HTTPS_HYPERLINKS;
$this->m_sDefaultLanguage = 'EN US';
$this->m_sAllowedLoginTypes = DEFAULT_ALLOWED_LOGIN_TYPES;
$this->m_sExtAuthVariable = DEFAULT_EXT_AUTH_VARIABLE;
@@ -725,21 +406,6 @@ class Config
$this->Load($sConfigFile);
$this->Verify();
}
// Application root url: set a default value, then normalize it
/*
* Does not work in CLI/unattended mode
$sAppRootUrl = trim($this->Get('app_root_url'));
if (strlen($sAppRootUrl) == 0)
{
$sAppRootUrl = utils::GetDefaultUrlAppRoot();
}
if (substr($sAppRootUrl, -1, 1) != '/')
{
$sAppRootUrl .= '/';
}
$this->Set('app_root_url', $sAppRootUrl);
*/
}
protected function CheckFile($sPurpose, $sFileName)
@@ -748,10 +414,6 @@ class Config
{
throw new ConfigException("Could not find $sPurpose file", array('file' => $sFileName));
}
if (!is_readable($sFileName))
{
throw new ConfigException("Could not read $sPurpose file (the file exists but cannot be read). Do you have the rights to access this file?", array('file' => $sFileName));
}
}
protected function Load($sConfigFile)
@@ -779,7 +441,7 @@ class Config
if (strlen($sNoise) > 0)
{
// Note: sNoise is an html output, but so far it was ok for me (e.g. showing the entire call stack)
throw new ConfigException('Syntax error in configuration file', array('file' => $sConfigFile, 'error' => '<tt>'.htmlentities($sNoise, ENT_QUOTES, 'UTF-8').'</tt>'));
throw new ConfigException('Syntax error in configuration file', array('file' => $sConfigFile, 'error' => '<tt>'.htmlentities($sNoise).'</tt>'));
}
if (!isset($MySettings) || !is_array($MySettings))
@@ -852,6 +514,7 @@ class Config
$this->m_iStandardReloadInterval = isset($MySettings['standard_reload_interval']) ? trim($MySettings['standard_reload_interval']) : DEFAULT_STANDARD_RELOAD_INTERVAL;
$this->m_iFastReloadInterval = isset($MySettings['fast_reload_interval']) ? trim($MySettings['fast_reload_interval']) : DEFAULT_FAST_RELOAD_INTERVAL;
$this->m_bSecureConnectionRequired = isset($MySettings['secure_connection_required']) ? (bool) trim($MySettings['secure_connection_required']) : DEFAULT_SECURE_CONNECTION_REQUIRED;
$this->m_bHttpsHyperlinks = isset($MySettings['https_hyperlinks']) ? (bool) trim($MySettings['https_hyperlinks']) : DEFAULT_HTTPS_HYPERLINKS;
$this->m_aModuleSettings = isset($MyModuleSettings) ? $MyModuleSettings : array();
@@ -1027,6 +690,11 @@ class Config
return $this->m_bSecureConnectionRequired;
}
public function GetHttpsHyperlinks()
{
return $this->m_bHttpsHyperlinks;
}
public function GetDefaultLanguage()
{
return $this->m_sDefaultLanguage;
@@ -1132,6 +800,11 @@ class Config
$this->m_bSecureConnectionRequired = $bSecureConnectionRequired;
}
public function SetHttpsHyperlinks($bHttpsHyperlinks)
{
$this->m_bHttpsHyperlinks = $bHttpsHyperlinks;
}
public function SetDefaultLanguage($sLanguageCode)
{
$this->m_sDefaultLanguage = $sLanguageCode;
@@ -1161,17 +834,13 @@ class Config
{
$this->m_aCharsets[$sIconvCode] = $sDisplayName;
}
public function FileIsWritable()
{
return is_writable($this->m_sFile);
}
public function GetLoadedFile()
{
if (is_null($this->m_sFile))
{
return '';
}
else
{
return $this->m_sFile;
}
return $this->m_sFile;
}
/**
@@ -1201,6 +870,7 @@ class Config
$aSettings['standard_reload_interval'] = $this->m_iStandardReloadInterval;
$aSettings['fast_reload_interval'] = $this->m_iFastReloadInterval;
$aSettings['secure_connection_required'] = $this->m_bSecureConnectionRequired;
$aSettings['https_hyperlinks'] = $this->m_bHttpsHyperlinks;
$aSettings['default_language'] = $this->m_sDefaultLanguage;
$aSettings['allowed_login_types'] = $this->m_sAllowedLoginTypes;
$aSettings['encryption_key'] = $this->m_sEncryptionKey;
@@ -1254,98 +924,65 @@ class Config
fwrite($hFile, "<?php\n");
fwrite($hFile, "\n/**\n");
fwrite($hFile, " *\n");
fwrite($hFile, " * Configuration file, generated by the ".ITOP_APPLICATION." configuration wizard\n");
fwrite($hFile, " * phpMyORM configuration file, generated by the iTop configuration wizard\n");
fwrite($hFile, " *\n");
fwrite($hFile, " * The file is used in MetaModel::LoadConfig() which does all the necessary initialization job\n");
fwrite($hFile, " *\n");
fwrite($hFile, " */\n");
fwrite($hFile, "\n");
$aConfigSettings = $this->m_aSettings;
// Old fashioned boolean settings
$aBoolValues = array(
'log_global' => $this->m_bLogGlobal,
'log_notification' => $this->m_bLogNotification,
'log_issue' => $this->m_bLogIssue,
'log_web_service' => $this->m_bLogWebService,
'secure_connection_required' => $this->m_bSecureConnectionRequired,
);
foreach($aBoolValues as $sKey => $bValue)
{
$aConfigSettings[$sKey] = array(
'show_in_conf_sample' => true,
'type' => 'bool',
'value' => $bValue,
);
}
// Old fashioned non boolean values
$aOtherValues = array(
'db_host' => $this->m_sDBHost,
'db_user' => $this->m_sDBUser,
'db_pwd' => $this->m_sDBPwd,
'db_name' => $this->m_sDBName,
'db_subname' => $this->m_sDBSubname,
'db_character_set' => $this->m_sDBCharacterSet,
'db_collation' => $this->m_sDBCollation,
'default_language' => $this->m_sDefaultLanguage,
'allowed_login_types' => $this->m_sAllowedLoginTypes,
'encryption_key' => $this->m_sEncryptionKey,
'csv_import_charsets' => $this->m_aCharsets,
);
foreach($aOtherValues as $sKey => $value)
{
$aConfigSettings[$sKey] = array(
'show_in_conf_sample' => true,
'type' => is_string($value) ? 'string' : 'mixed',
'value' => $value,
);
}
ksort($aConfigSettings);
fwrite($hFile, "\$MySettings = array(\n");
foreach($aConfigSettings as $sPropCode => $aSettingInfo)
foreach($this->m_aSettings as $sPropCode => $aSettingInfo)
{
if ($aSettingInfo['show_in_conf_sample'])
{
$sType = $aSettingInfo['type'];
$sType = $this->m_aSettings[$sPropCode]['type'];
switch($sType)
{
case 'bool':
$sSeenAs = $aSettingInfo['value'] ? 'true' : 'false';
$sSeenAs = $aSettingInfo['value'] ? '1' : '0';
break;
default:
$sSeenAs = self::PrettyVarExport($aSettingInfo['value'], "\t");
}
fwrite($hFile, "\n");
if (isset($aSettingInfo['description']))
{
fwrite($hFile, "\t// $sPropCode: {$aSettingInfo['description']}\n");
}
if (isset($aSettingInfo['default']))
{
$default = $aSettingInfo['default'];
if ($aSettingInfo['type'] == 'bool')
{
$default = $default ? 'true' : 'false';
}
fwrite($hFile, "\t//\tdefault: ".self::PrettyVarExport($aSettingInfo['default'],"\t//\t\t", true)."\n");
$sSeenAs = "'".$aSettingInfo['value']."'";
}
fwrite($hFile, "\t'$sPropCode' => $sSeenAs,\n");
}
}
fwrite($hFile, ");\n");
fwrite($hFile, "\t'db_host' => '{$this->m_sDBHost}',\n");
fwrite($hFile, "\t'db_user' => '{$this->m_sDBUser}',\n");
fwrite($hFile, "\t'db_pwd' => '".addslashes($this->m_sDBPwd)."',\n");
fwrite($hFile, "\t'db_name' => '{$this->m_sDBName}',\n");
fwrite($hFile, "\t'db_subname' => '{$this->m_sDBSubname}',\n");
fwrite($hFile, "\t'db_character_set' => '{$this->m_sDBCharacterSet}',\n");
fwrite($hFile, "\t'db_collation' => '{$this->m_sDBCollation}',\n");
fwrite($hFile, "\n");
fwrite($hFile, "\t'log_global' => {$this->m_bLogGlobal},\n");
fwrite($hFile, "\t'log_notification' => {$this->m_bLogNotification},\n");
fwrite($hFile, "\t'log_issue' => {$this->m_bLogIssue},\n");
fwrite($hFile, "\t'log_web_service' => {$this->m_bLogWebService},\n");
fwrite($hFile, "\t'min_display_limit' => {$this->m_iMinDisplayLimit},\n");
fwrite($hFile, "\t'max_display_limit' => {$this->m_iMaxDisplayLimit},\n");
fwrite($hFile, "\t'standard_reload_interval' => {$this->m_iStandardReloadInterval},\n");
fwrite($hFile, "\t'fast_reload_interval' => {$this->m_iFastReloadInterval},\n");
fwrite($hFile, "\t'secure_connection_required' => ".($this->m_bSecureConnectionRequired ? 'true' : 'false').",\n");
fwrite($hFile, "\t'https_hyperlinks' => ".($this->m_bHttpsHyperlinks ? 'true' : 'false').",\n");
fwrite($hFile, "\t'default_language' => '{$this->m_sDefaultLanguage}',\n");
fwrite($hFile, "\t'allowed_login_types' => '{$this->m_sAllowedLoginTypes}',\n");
fwrite($hFile, "\t'encryption_key' => '{$this->m_sEncryptionKey}',\n");
$sExport = var_export($this->m_aCharsets, true);
fwrite($hFile, "\t'csv_import_charsets' => $sExport,\n");
fwrite($hFile, ");\n");
fwrite($hFile, "\n");
fwrite($hFile, "/**\n *\n * Modules specific settings\n *\n */\n");
fwrite($hFile, "\$MyModuleSettings = array(\n");
foreach ($this->m_aModuleSettings as $sModule => $aProperties)
{
fwrite($hFile, "\t'$sModule' => array (\n");
foreach ($aProperties as $sProperty => $value)
{
$sNiceExport = self::PrettyVarExport($value, "\t\t");
fwrite($hFile, "\t\t'$sProperty' => $sNiceExport,\n");
$sExport = var_export($value, true);
fwrite($hFile, "\t\t'$sProperty' => $sExport,\n");
}
fwrite($hFile, "\t),\n");
}
@@ -1353,7 +990,7 @@ class Config
fwrite($hFile, "\n/**\n");
fwrite($hFile, " *\n");
fwrite($hFile, " * Data model modules to be loaded. Names are specified as relative paths\n");
fwrite($hFile, " * Data model modules to be loaded. Names should be specified as absolute paths\n");
fwrite($hFile, " *\n");
fwrite($hFile, " */\n");
fwrite($hFile, "\$MyModules = array(\n");
@@ -1396,178 +1033,5 @@ class Config
throw new ConfigException("Could not write to configuration file", array('file' => $sFileName));
}
}
protected static function ScanDictionariesDir()
{
$aResult = array();
// Populate automatically the list of dictionary files
$sDir = APPROOT.'/dictionaries';
if ($hDir = @opendir($sDir))
{
while (($sFile = readdir($hDir)) !== false)
{
$aMatches = array();
if (preg_match("/^([^\.]+\.)?dictionary\.itop\.(ui|core)\.php$/i", $sFile, $aMatches)) // Dictionary files named like [<Lang>.]dictionary.[core|ui].php are loaded automatically
{
$aResult[] = 'dictionaries/'.$sFile;
}
}
closedir($hDir);
}
return $aResult;
}
/**
* Helper function to initialize a configuration from the page arguments
*/
public function UpdateFromParams($aParamValues, $sModulesDir = null)
{
if (isset($aParamValues['application_path']))
{
$this->Set('app_root_url', $aParamValues['application_path']);
}
if (isset($aParamValues['mode']) && isset($aParamValues['language']))
{
if (($aParamValues['mode'] == 'install') || $this->GetDefaultLanguage() == '')
{
$this->SetDefaultLanguage($aParamValues['language']);
}
}
if (isset($aParamValues['db_server']))
{
$this->SetDBHost($aParamValues['db_server']);
$this->SetDBUser($aParamValues['db_user']);
$this->SetDBPwd($aParamValues['db_pwd']);
$sDBName = $aParamValues['db_name'];
if ($sDBName == '')
{
// Todo - obsolete after the transition to the new setup (2.0) is complete (WARNING: used by the designer)
$sDBName = $aParamValues['new_db_name'];
}
$this->SetDBName($sDBName);
$this->SetDBSubname($aParamValues['db_prefix']);
}
if (!is_null($sModulesDir))
{
if (isset($aParamValues['selected_modules']))
{
$aSelectedModules = explode(',', $aParamValues['selected_modules']);
}
else
{
$aSelectedModules = null;
}
// Initialize the arrays below with default values for the application...
$oEmptyConfig = new Config('dummy_file', false); // Do NOT load any config file, just set the default values
$aAddOns = $oEmptyConfig->GetAddOns();
$aAppModules = $oEmptyConfig->GetAppModules();
$aDataModels = $oEmptyConfig->GetDataModels();
$aWebServiceCategories = $oEmptyConfig->GetWebServiceCategories();
$aDictionaries = $oEmptyConfig->GetDictionaries();
// Merge the values with the ones provided by the modules
// Make sure when don't load the same file twice...
$aModules = ModuleDiscovery::GetAvailableModules(APPROOT, $sModulesDir);
foreach($aModules as $sModuleId => $aModuleInfo)
{
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
if (is_null($aSelectedModules) || in_array($sModuleName, $aSelectedModules))
{
if (isset($aModuleInfo['datamodel']))
{
$aDataModels = array_unique(array_merge($aDataModels, $aModuleInfo['datamodel']));
}
if (isset($aModuleInfo['webservice']))
{
$aWebServiceCategories = array_unique(array_merge($aWebServiceCategories, $aModuleInfo['webservice']));
}
if (isset($aModuleInfo['dictionary']))
{
$aDictionaries = array_unique(array_merge($aDictionaries, $aModuleInfo['dictionary']));
}
if (isset($aModuleInfo['settings']))
{
foreach($aModuleInfo['settings'] as $sProperty => $value)
{
list($sName, $sVersion) = ModuleDiscovery::GetModuleName($sModuleId);
$this->SetModuleSetting($sName, $sProperty, $value);
}
}
if (isset($aModuleInfo['installer']))
{
$sModuleInstallerClass = $aModuleInfo['installer'];
if (!class_exists($sModuleInstallerClass))
{
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aModuleInfo['label']);
}
if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI'))
{
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aModuleInfo['label']);
}
$aCallSpec = array($sModuleInstallerClass, 'BeforeWritingConfig');
call_user_func_array($aCallSpec, array($this));
}
}
}
$this->SetAddOns($aAddOns);
$this->SetAppModules($aAppModules);
$this->SetDataModels($aDataModels);
$this->SetWebServiceCategories($aWebServiceCategories);
$this->SetDictionaries($aDictionaries);
}
}
/**
* Helper: for an array of string, change the prefix when found
*/
protected static function ChangePrefix(&$aStrings, $sSearchPrefix, $sNewPrefix)
{
foreach ($aStrings as &$sFile)
{
if (substr($sFile, 0, strlen($sSearchPrefix)) == $sSearchPrefix)
{
$sFile = $sNewPrefix.substr($sFile, strlen($sSearchPrefix));
}
}
}
/**
* Quick an dirty way to clone a config file into another environment
*/
public function ChangeModulesPath($sSourceEnv, $sTargetEnv)
{
$sSearchPrefix = 'env-'.$sSourceEnv.'/';
$sNewPrefix = 'env-'.$sTargetEnv.'/';
self::ChangePrefix($this->m_aDataModels, $sSearchPrefix, $sNewPrefix);
self::ChangePrefix($this->m_aWebServiceCategories, $sSearchPrefix, $sNewPrefix);
self::ChangePrefix($this->m_aDictionaries, $sSearchPrefix, $sNewPrefix);
}
/**
* Pretty format a var_export'ed value so that (if possible) the identation is preserved on every line
* @param mixed $value The value to export
* @param string $sIdentation The string to use to indent the text
* @param bool $bForceIndentation Forces the identation (enven if it breaks/changes an eval, for example to ouput a value inside a comment)
* @return string The indented export string
*/
protected static function PrettyVarExport($value, $sIdentation, $bForceIndentation = false)
{
$sExport = var_export($value, true);
$sNiceExport = trim(preg_replace("/^/m", "\t\t\t", $sExport));
if (!$bForceIndentation)
{
eval('$aImported='.$sNiceExport.';');
// Check if adding the identations at the beginning of each line
// did not modify the values (in case of a string containing a line break)
if($aImported != $value)
{
$sNiceExport = $sExport;
}
}
return $sNiceExport;
}
}
?>

View File

@@ -40,8 +40,6 @@ define('evTEXTQUAL', 3); // used for escaping as well
define('evOTHERCHAR', 4);
define('evEND', 5);
define('NULL_VALUE', '<NULL>');
/**
* CSVParser
@@ -84,10 +82,6 @@ class CSVParser
{
$sCell = $this->m_sCurrCell;
}
if ($sCell == NULL_VALUE)
{
$sCell = null;
}
if (!is_null($aFieldMap))
{
@@ -184,7 +178,6 @@ class CSVParser
{
if ($i == $iDataLength)
{
$c = null;
$iEvent = evEND;
}
else

File diff suppressed because it is too large Load Diff

View File

@@ -22,16 +22,6 @@
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
define('TREE_OPERATOR_EQUALS', 0);
define('TREE_OPERATOR_BELOW', 1);
define('TREE_OPERATOR_BELOW_STRICT', 2);
define('TREE_OPERATOR_NOT_BELOW', 3);
define('TREE_OPERATOR_NOT_BELOW_STRICT', 4);
define('TREE_OPERATOR_ABOVE', 5);
define('TREE_OPERATOR_ABOVE_STRICT', 6);
define('TREE_OPERATOR_NOT_ABOVE', 7);
define('TREE_OPERATOR_NOT_ABOVE_STRICT', 8);
class DBObjectSearch
{
@@ -43,7 +33,6 @@ class DBObjectSearch
private $m_aPointingTo;
private $m_aReferencedBy;
private $m_aRelatedTo;
private $m_bDataFiltered;
// By default, some information may be hidden to the current user
// But it may happen that we need to disable that feature
@@ -64,29 +53,12 @@ class DBObjectSearch
$this->m_aPointingTo = array();
$this->m_aReferencedBy = array();
$this->m_aRelatedTo = array();
$this->m_bDataFiltered = false;
$this->m_aParentConditions = array();
$this->m_aModifierProperties = array();
}
public function AllowAllData() {$this->m_bAllowAllData = true;}
public function IsAllDataAllowed() {return $this->m_bAllowAllData;}
public function IsDataFiltered() {return $this->m_bDataFiltered; }
public function SetDataFiltered() {$this->m_bDataFiltered = true;}
public function GetClassName($sAlias)
{
if (array_key_exists($sAlias, $this->m_aClasses))
{
return $this->m_aClasses[$sAlias];
}
else
{
throw new CoreException("Invalid class alias '$sAlias'");
}
}
public function GetClassName($sAlias) {return $this->m_aClasses[$sAlias];}
public function GetJoinedClasses() {return $this->m_aClasses;}
public function GetClass()
@@ -128,23 +100,6 @@ class DBObjectSearch
}
public function SetModifierProperty($sPluginClass, $sProperty, $value)
{
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
}
public function GetModifierProperties($sPluginClass)
{
if (array_key_exists($sPluginClass, $this->m_aModifierProperties))
{
return $this->m_aModifierProperties[$sPluginClass];
}
else
{
return array();
}
}
public function IsAny()
{
// #@# todo - if (!$this->m_oSearchCondition->IsTrue()) return false;
@@ -152,7 +107,6 @@ class DBObjectSearch
if (count($this->m_aPointingTo) > 0) return false;
if (count($this->m_aReferencedBy) > 0) return false;
if (count($this->m_aRelatedTo) > 0) return false;
if (count($this->m_aParentConditions) > 0) return false;
return true;
}
@@ -161,55 +115,13 @@ class DBObjectSearch
// To replace __Describe
}
public function DescribeConditionPointTo($sExtKeyAttCode, $aPointingTo)
public function DescribeConditionPointTo($sExtKeyAttCode)
{
if (empty($aPointingTo)) return "";
foreach($aPointingTo as $iOperatorCode => $oFilter)
{
if ($oFilter->IsAny()) break;
$oAtt = MetaModel::GetAttributeDef($this->GetClass(), $sExtKeyAttCode);
$sOperator = '';
switch($iOperatorCode)
{
case TREE_OPERATOR_EQUALS:
$sOperator = 'having';
break;
case TREE_OPERATOR_BELOW:
$sOperator = 'below';
break;
case TREE_OPERATOR_BELOW_STRICT:
$sOperator = 'strictly below';
break;
case TREE_OPERATOR_NOT_BELOW:
$sOperator = 'not below';
break;
case TREE_OPERATOR_NOT_BELOW_STRICT:
$sOperator = 'strictly not below';
break;
case TREE_OPERATOR_ABOVE:
$sOperator = 'above';
break;
case TREE_OPERATOR_ABOVE_STRICT:
$sOperator = 'strictly above';
break;
case TREE_OPERATOR_NOT_ABOVE:
$sOperator = 'not above';
break;
case TREE_OPERATOR_NOT_ABOVE_STRICT:
$sOperator = 'strictly not above';
break;
}
$aDescription[] = $oAtt->GetLabel()."$sOperator ({$oFilter->DescribeConditions()})";
}
return implode(' and ', $aDescription);
if (!isset($this->m_aPointingTo[$sExtKeyAttCode])) return "";
$oFilter = $this->m_aPointingTo[$sExtKeyAttCode];
if ($oFilter->IsAny()) return "";
$oAtt = MetaModel::GetAttributeDef($this->GetClass(), $sExtKeyAttCode);
return $oAtt->GetLabel()." having ({$oFilter->DescribeConditions()})";
}
public function DescribeConditionRefBy($sForeignClass, $sForeignExtKeyAttCode)
@@ -229,7 +141,6 @@ class DBObjectSearch
return "related ($sRelCode... peut mieux faire !, $iMaxDepth dig depth) to a {$oFilter->GetClass()} ({$oFilter->DescribeConditions()})";
}
public function DescribeConditions()
{
$aConditions = array();
@@ -248,9 +159,10 @@ class DBObjectSearch
$aConditions[] = $this->RenderCondition();
$aCondPoint = array();
foreach($this->m_aPointingTo as $sExtKeyAttCode => $aPointingTo)
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$oFilter)
{
$aCondPoint[] = $this->DescribeConditionPointTo($sExtKeyAttCode, $aPointingTo);
if ($oFilter->IsAny()) continue;
$aCondPoint[] = $this->DescribeConditionPointTo($sExtKeyAttCode);
}
if (count($aCondPoint) > 0)
{
@@ -275,11 +187,6 @@ class DBObjectSearch
$aConditions[] = implode(" and ", $aCondReferred);
}
foreach ($this->m_aParentConditions as $aRelInfo)
{
$aCondReferred[] = $this->DescribeConditionParent($aRelInfo);
}
return implode(" and ", $aConditions);
}
@@ -302,88 +209,23 @@ class DBObjectSearch
protected function TransferConditionExpression($oFilter, $aTranslation)
{
// Prevent collisions in the parameter names by renaming them if needed
foreach($this->m_aParams as $sParam => $value)
{
if (array_key_exists($sParam, $oFilter->m_aParams) && ($value != $oFilter->m_aParams[$sParam]))
{
// Generate a new and unique name for the collinding parameter
$index = 1;
while(array_key_exists($sParam.$index, $oFilter->m_aParams))
{
$index++;
}
$secondValue = $oFilter->m_aParams[$sParam];
$oFilter->RenameParam($sParam, $sParam.$index);
unset($oFilter->m_aParams[$sParam]);
$oFilter->m_aParams[$sParam.$index] = $secondValue;
}
}
//echo "<p>TransferConditionExpression:<br/>";
//echo "Adding Conditions:<br/><pre>oFilter:\n".print_r($oFilter, true)."\naTranslation:\n".print_r($aTranslation, true)."</pre>\n";
//echo "</p>";
$oTranslated = $oFilter->GetCriteria()->Translate($aTranslation, false, false /* leave unresolved fields */);
//echo "Adding Conditions (translated):<br/><pre>".print_r($oTranslated, true)."</pre>\n";
$oTranslated = $oFilter->GetCriteria()->Translate($aTranslation, false);
$this->AddConditionExpression($oTranslated);
// #@# what about collisions in parameter names ???
$this->m_aParams = array_merge($this->m_aParams, $oFilter->m_aParams);
}
protected function RenameParam($sOldName, $sNewName)
{
$this->m_oSearchCondition->RenameParam($sOldName, $sNewName);
foreach($this->m_aRelatedTo as $aRelatedTo)
{
$aRelatedTo['flt']->RenameParam($sOldName, $sNewName);
}
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
{
foreach($aPointingTo as $iOperatorCode => $aFilter)
{
foreach($aFilter as $sAlias => $oExtFilter)
{
$oExtFilter->RenameParam($sOldName, $sNewName);
}
}
}
foreach($this->m_aReferencedBy as $sForeignClass => $aReferences)
{
foreach($aReferences as $sForeignExtKeyAttCode => $oForeignFilter)
{
$oForeignFilter->RenameParam($sOldName, $sNewName);
}
}
foreach($this->m_aParentConditions as $aParent)
{
$aParent['expression']->RenameParam($sOldName, $sNewName);
}
}
public function ResetCondition()
{
$this->m_oSearchCondition = new TrueExpression();
$this->m_aParentConditions = array();
// ? is that usefull/enough, do I need to rebuild the list after the subqueries ?
}
public function MergeConditionExpression($oExpression)
{
$this->m_oSearchCondition = $this->m_oSearchCondition->LogOr($oExpression);
}
public function AddConditionExpression($oExpression)
{
$this->m_oSearchCondition = $this->m_oSearchCondition->LogAnd($oExpression);
}
public function AddNameCondition($sName)
{
$oValueExpr = new ScalarExpression($sName);
$oNameExpr = new FieldExpression('friendlyname', $this->GetClassAlias());
$oNewCondition = new BinaryExpression($oNameExpr, '=', $oValueExpr);
$this->AddConditionExpression($oNewCondition);
}
public function AddCondition($sFilterCode, $value, $sOpCode = null)
{
MyHelpers::CheckKeyInArray('filter code', $sFilterCode, MetaModel::GetClassFilterDefs($this->GetClass()));
@@ -470,127 +312,30 @@ class DBObjectSearch
$this->AddConditionExpression($oNewCondition);
}
/**
* Specify a condition on external keys or link sets
* @param sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively
* Example: infra_list->ci_id->location_id->country
* @param value The value to match
* @return void
*/
public function AddConditionAdvanced($sAttSpec, $value)
{
$sClass = $this->GetClass();
$iPos = strpos($sAttSpec, '->');
if ($iPos !== false)
{
$sAttCode = substr($sAttSpec, 0, $iPos);
$sSubSpec = substr($sAttSpec, $iPos + 2);
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
{
throw new Exception("Invalid attribute code '$sClass/$sAttCode' in condition specification '$sAttSpec'");
}
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsLinkSet())
{
$sTargetClass = $oAttDef->GetLinkedClass();
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
$oNewFilter = new DBObjectSearch($sTargetClass);
$oNewFilter->AddConditionAdvanced($sSubSpec, $value);
$this->AddCondition_ReferencedBy($oNewFilter, $sExtKeyToMe);
}
elseif ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
{
$sTargetClass = $oAttDef->GetTargetClass(EXTKEY_ABSOLUTE);
$oNewFilter = new DBObjectSearch($sTargetClass);
$oNewFilter->AddConditionAdvanced($sSubSpec, $value);
$this->AddCondition_PointingTo($oNewFilter, $sAttCode);
}
else
{
throw new Exception("Attribute specification '$sAttSpec', '$sAttCode' should be either a link set or an external key");
}
}
else
{
// $sAttSpec is an attribute code
//
$this->AddCondition($sAttSpec, $value);
}
}
public function AddCondition_FullText($sFullText)
{
$this->m_aFullText[] = $sFullText;
}
public function AddCondition_Parent($sAttCode, $iOperatorCode, $oExpression)
protected function AddToNameSpace(&$aClassAliases, &$aAliasTranslation)
{
$oAttDef = MetaModel::GetAttributeDef($this->GetClass(), $sAttCode);
if (!$oAttDef instanceof AttributeHierarchicalKey)
$sOrigAlias = $this->GetClassAlias();
if (array_key_exists($sOrigAlias, $aClassAliases))
{
throw new Exception("AddCondition_Parent can only be used on hierarchical keys. '$sAttCode' is not a hierarchical key.");
}
$this->m_aParentConditions[] = array(
'attCode' => $sAttCode,
'operator' => $iOperatorCode,
'expression' => $oExpression,
);
}
protected function AddToNameSpace(&$aClassAliases, &$aAliasTranslation, $bTranslateMainAlias = true)
{
if ($bTranslateMainAlias)
{
$sOrigAlias = $this->GetFirstJoinedClassAlias();
if (array_key_exists($sOrigAlias, $aClassAliases))
{
$sNewAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->GetFirstJoinedClass());
if (isset($this->m_aSelectedClasses[$sOrigAlias]))
{
$this->m_aSelectedClasses[$sNewAlias] = $this->GetFirstJoinedClass();
unset($this->m_aSelectedClasses[$sOrigAlias]);
}
$sNewAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->GetClass());
$this->m_aSelectedClasses[$sNewAlias] = $this->GetClass();
unset($this->m_aSelectedClasses[$sOrigAlias]);
// TEMPORARY ALGORITHM (m_aClasses is not correctly updated, it is not possible to add a subtree onto a subnode)
// Replace the element at the same position (unset + set is not enough because the hash array is ordered)
$aPrevList = $this->m_aClasses;
$this->m_aClasses = array();
foreach ($aPrevList as $sSomeAlias => $sSomeClass)
{
if ($sSomeAlias == $sOrigAlias)
{
$this->m_aClasses[$sNewAlias] = $sSomeClass; // note: GetFirstJoinedClass now returns '' !!!
}
else
{
$this->m_aClasses[$sSomeAlias] = $sSomeClass;
}
}
// Translate the condition expression with the new alias
$aAliasTranslation[$sOrigAlias]['*'] = $sNewAlias;
}
// add the alias into the filter aliases list
$aClassAliases[$this->GetFirstJoinedClassAlias()] = $this->GetFirstJoinedClass();
// Translate the condition expression with the new alias
$aAliasTranslation[$sOrigAlias]['*'] = $sNewAlias;
}
// add the alias into the filter aliases list
$aClassAliases[$this->GetClassAlias()] = $this->GetClass();
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$oFilter)
{
foreach($aPointingTo as $iOperatorCode => $aFilter)
{
foreach($aFilter as $sAlias => $oFilter)
{
$oFilter->AddToNameSpace($aClassAliases, $aAliasTranslation);
}
}
$oFilter->AddToNameSpace($aClassAliases, $aAliasTranslation);
}
foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences)
@@ -602,15 +347,15 @@ class DBObjectSearch
}
}
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS)
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode)
{
$aAliasTranslation = array();
$res = $this->AddCondition_PointingTo_InNameSpace($oFilter, $sExtKeyAttCode, $this->m_aClasses, $aAliasTranslation, $iOperatorCode);
$res = $this->AddCondition_PointingTo_InNameSpace($oFilter, $sExtKeyAttCode, $this->m_aClasses, $aAliasTranslation);
$this->TransferConditionExpression($oFilter, $aAliasTranslation);
return $res;
}
protected function AddCondition_PointingTo_InNameSpace(DBObjectSearch $oFilter, $sExtKeyAttCode, &$aClassAliases, &$aAliasTranslation, $iOperatorCode)
protected function AddCondition_PointingTo_InNameSpace(DBObjectSearch $oFilter, $sExtKeyAttCode, &$aClassAliases, &$aAliasTranslation)
{
if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
{
@@ -621,33 +366,20 @@ class DBObjectSearch
{
throw new CoreException("The specified filter (pointing to {$oFilter->GetClass()}) is not compatible with the key '{$this->GetClass()}::$sExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
}
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !($oAttExtKey instanceof AttributeHierarchicalKey))
{
throw new CoreException("The specified tree operator $iOperatorCode is not applicable to the key '{$this->GetClass()}::$sExtKeyAttCode', which is not a HierarchicalKey");
}
$bSamePointingTo = false;
if (array_key_exists($sExtKeyAttCode, $this->m_aPointingTo))
{
if (array_key_exists($iOperatorCode, $this->m_aPointingTo[$sExtKeyAttCode]))
{
if (array_key_exists($oFilter->GetClassAlias(), $this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode]))
{
$bSamePointingTo = true;
}
}
}
if ($bSamePointingTo)
{
// Same ext key, alias and same operator, merge the filters together
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation, true /* Don't translate the main alias */);
$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$oFilter->GetClassAlias()] = $oFilter;
$this->m_aPointingTo[$sExtKeyAttCode]->MergeWith_InNamespace($oFilter, $aClassAliases, $aAliasTranslation);
}
else
{
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation);
$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$oFilter->GetClassAlias()] = $oFilter;
// #@# The condition expression found in that filter should not be used - could be another kind of structure like a join spec tree !!!!
// $oNewFilter = clone $oFilter;
// $oNewFilter->ResetCondition();
$this->m_aPointingTo[$sExtKeyAttCode] = $oFilter;
}
}
@@ -691,7 +423,6 @@ class DBObjectSearch
public function AddCondition_LinkedTo(DBObjectSearch $oLinkFilter, $sExtKeyAttCodeToMe, $sExtKeyAttCodeTarget, DBObjectSearch $oFilterTarget)
{
$oLinkFilterFinal = clone $oLinkFilter;
// todo : new function prototype
$oLinkFilterFinal->AddCondition_PointingTo($sExtKeyAttCodeToMe);
$this->AddCondition_ReferencedBy($oLinkFilterFinal, $sExtKeyAttCodeToMe);
@@ -724,15 +455,9 @@ class DBObjectSearch
$this->m_aFullText = array_merge($this->m_aFullText, $oFilter->m_aFullText);
$this->m_aRelatedTo = array_merge($this->m_aRelatedTo, $oFilter->m_aRelatedTo);
foreach($oFilter->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
foreach($oFilter->m_aPointingTo as $sExtKeyAttCode=>$oExtFilter)
{
foreach($aPointingTo as $iOperatorCode => $aFilter)
{
foreach($aFilter as $sAlias => $oExtFilter)
{
$this->AddCondition_PointingTo_InNamespace($oExtFilter, $sExtKeyAttCode, $aClassAliases, $aAliasTranslation, $iOperatorCode);
}
}
$this->AddCondition_PointingTo_InNamespace($oExtFilter, $sExtKeyAttCode, $aClassAliases, $aAliasTranslation);
}
foreach($oFilter->m_aReferencedBy as $sForeignClass => $aReferences)
{
@@ -751,7 +476,7 @@ class DBObjectSearch
{
return $this->m_aPointingTo;
}
if (!array_key_exists($sKeyAttCode, $this->m_aPointingTo)) return array();
if (!array_key_exists($sKeyAttCode, $this->m_aPointingTo)) return null;
return $this->m_aPointingTo[$sKeyAttCode];
}
public function GetCriteria_ReferencedBy($sRemoteClass = "", $sForeignExtKeyAttCode = "")
@@ -772,47 +497,20 @@ class DBObjectSearch
{
return $this->m_aRelatedTo;
}
public function SetInternalParams($aParams)
{
return $this->m_aParams = $aParams;
}
public function GetInternalParams()
{
return $this->m_aParams;
}
public function GetQueryParams()
{
$aParams = array();
$this->m_oSearchCondition->Render($aParams, true);
return $aParams;
}
public function ListConstantFields()
{
return $this->m_oSearchCondition->ListConstantFields();
}
public function RenderCondition()
{
return $this->m_oSearchCondition->Render($this->m_aParams, false);
}
/**
* Turn the parameters (:xxx) into scalar values in order to easily
* serialize a search
*/
public function ApplyParameters($aArgs)
{
return $this->m_oSearchCondition->ApplyParameters(array_merge($this->m_aParams, $aArgs));
}
public function serialize($bDevelopParams = false, $aContextParams = null)
{
$sOql = $this->ToOql($bDevelopParams, $aContextParams);
return base64_encode(serialize(array($sOql, $this->m_aParams, $this->m_aModifierProperties)));
return base64_encode(serialize(array($sOql, $this->m_aParams)));
}
static public function unserialize($sValue)
@@ -823,9 +521,7 @@ class DBObjectSearch
// We've tried to use gzcompress/gzuncompress, but for some specific queries
// it was not working at all (See Trac #193)
// gzuncompress was issuing a warning "data error" and the return object was null
$oRetFilter = self::FromOQL($sOql, $aParams);
$oRetFilter->m_aModifierProperties = $aData[2];
return $oRetFilter;
return self::FromOQL($sOql, $aParams);
}
// SImple BUt Structured Query Languag - SubuSQL
@@ -921,7 +617,6 @@ class DBObjectSearch
{
$aParams = array_merge($aContextParams, $this->m_aParams);
}
$aParams = MetaModel::PrepareQueryArguments($aParams);
}
else
{
@@ -932,7 +627,7 @@ class DBObjectSearch
$sSelectedClasses = implode(', ', array_keys($this->m_aSelectedClasses));
$sRes = 'SELECT '.$sSelectedClasses.' FROM';
$sRes .= ' '.$this->GetFirstJoinedClass().' AS '.$this->GetFirstJoinedClassAlias();
$sRes .= ' '.$this->GetClass().' AS '.$this->GetClassAlias();
$sRes .= $this->ToOQL_Joins();
$sRes .= " WHERE ".$this->m_oSearchCondition->Render($aParams, $bRetrofitParams);
@@ -947,61 +642,16 @@ class DBObjectSearch
protected function ToOQL_Joins()
{
$sRes = '';
foreach($this->m_aPointingTo as $sExtKey => $aPointingTo)
foreach($this->m_aPointingTo as $sExtKey=>$oFilter)
{
foreach($aPointingTo as $iOperatorCode => $aFilter)
{
foreach($aFilter as $sAlias => $oFilter)
{
switch($iOperatorCode)
{
case TREE_OPERATOR_EQUALS:
$sOperator = ' = ';
break;
case TREE_OPERATOR_BELOW:
$sOperator = ' BELOW ';
break;
case TREE_OPERATOR_BELOW_STRICT:
$sOperator = ' BELOW STRICT ';
break;
case TREE_OPERATOR_NOT_BELOW:
$sOperator = ' NOT BELOW ';
break;
case TREE_OPERATOR_NOT_BELOW_STRICT:
$sOperator = ' NOT BELOW STRICT ';
break;
case TREE_OPERATOR_ABOVE:
$sOperator = ' ABOVE ';
break;
case TREE_OPERATOR_ABOVE_STRICT:
$sOperator = ' ABOVE STRICT ';
break;
case TREE_OPERATOR_NOT_ABOVE:
$sOperator = ' NOT ABOVE ';
break;
case TREE_OPERATOR_NOT_ABOVE_STRICT:
$sOperator = ' NOT ABOVE STRICT ';
break;
}
$sRes .= ' JOIN '.$oFilter->GetFirstJoinedClass().' AS '.$oFilter->GetFirstJoinedClassAlias().' ON '.$this->GetFirstJoinedClassAlias().'.'.$sExtKey.$sOperator.$oFilter->GetFirstJoinedClassAlias().'.id';
$sRes .= $oFilter->ToOQL_Joins();
}
}
$sRes .= ' JOIN '.$oFilter->GetClass().' AS '.$oFilter->GetClassAlias().' ON '.$this->GetClassAlias().'.'.$sExtKey.' = '.$oFilter->GetClassAlias().'.id';
$sRes .= $oFilter->ToOQL_Joins();
}
foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences)
{
foreach($aReferences as $sForeignExtKeyAttCode=>$oForeignFilter)
{
$sRes .= ' JOIN '.$oForeignFilter->GetFirstJoinedClass().' AS '.$oForeignFilter->GetFirstJoinedClassAlias().' ON '.$oForeignFilter->GetFirstJoinedClassAlias().'.'.$sForeignExtKeyAttCode.' = '.$this->GetFirstJoinedClassAlias().'.id';
$sRes .= ' JOIN '.$oForeignFilter->GetClass().' AS '.$oForeignFilter->GetClassAlias().' ON '.$oForeignFilter->GetClassAlias().'.'.$sForeignExtKeyAttCode.' = '.$this->GetClassAlias().'.id';
$sRes .= $oForeignFilter->ToOQL_Joins();
}
}
@@ -1137,7 +787,7 @@ class DBObjectSearch
if (!MetaModel::IsValidClass($sClass))
{
throw new UnknownClassOqlException($sQuery, $oOqlQuery->GetClassDetails(), MetaModel::GetClasses());
throw new OqlNormalizeException('Unknown class', $sQuery, $oOqlQuery->GetClassDetails(), MetaModel::GetClasses());
}
$oResultFilter = new DBObjectSearch($sClass, $sClassAlias);
@@ -1157,7 +807,7 @@ class DBObjectSearch
$sJoinClassAlias = $oJoinSpec->GetClassAlias();
if (!MetaModel::IsValidClass($sJoinClass))
{
throw new UnknownClassOqlException($sQuery, $oJoinSpec->GetClassDetails(), MetaModel::GetClasses());
throw new OqlNormalizeException('Unknown class', $sQuery, $oJoinSpec->GetClassDetails(), MetaModel::GetClasses());
}
if (array_key_exists($sJoinClassAlias, $aAliases))
{
@@ -1208,38 +858,7 @@ class DBObjectSearch
}
else
{
$sOperator = $oJoinSpec->GetOperator();
switch($sOperator)
{
case '=':
$iOperatorCode = TREE_OPERATOR_EQUALS;
break;
case 'BELOW':
$iOperatorCode = TREE_OPERATOR_BELOW;
break;
case 'BELOW_STRICT':
$iOperatorCode = TREE_OPERATOR_BELOW_STRICT;
break;
case 'NOT_BELOW':
$iOperatorCode = TREE_OPERATOR_NOT_BELOW;
break;
case 'NOT_BELOW_STRICT':
$iOperatorCode = TREE_OPERATOR_NOT_BELOW_STRICT;
break;
case 'ABOVE':
$iOperatorCode = TREE_OPERATOR_ABOVE;
break;
case 'ABOVE_STRICT':
$iOperatorCode = TREE_OPERATOR_ABOVE_STRICT;
break;
case 'NOT_ABOVE':
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE;
break;
case 'NOT_ABOVE_STRICT':
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE_STRICT;
break;
}
$aJoinItems[$sFromClass]->AddCondition_PointingTo($aJoinItems[$sToClass], $sExtKeyAttCode, $iOperatorCode);
$aJoinItems[$sFromClass]->AddCondition_PointingTo($aJoinItems[$sToClass], $sExtKeyAttCode);
}
}
}
@@ -1288,4 +907,4 @@ class DBObjectSearch
}
?>
?>

View File

@@ -32,28 +32,23 @@
class DBObjectSet
{
private $m_oFilter;
private $m_aAddedIds; // Ids of objects added (discrete lists)
private $m_aOrderBy;
public $m_bLoaded;
private $m_aData;
private $m_aId2Row;
private $m_iCurrRow;
public function __construct(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0)
public function __construct(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $iLimitCount = 0, $iLimitStart = 0)
{
$this->m_oFilter = $oFilter;
$this->m_aAddedIds = array();
$this->m_aOrderBy = $aOrderBy;
$this->m_aArgs = $aArgs;
$this->m_aAttToLoad = null;
$this->m_aExtendedDataSpec = $aExtendedDataSpec;
$this->m_iLimitCount = $iLimitCount;
$this->m_iLimitStart = $iLimitStart;
$this->m_iCount = null; // null if unknown yet
$this->m_bLoaded = false; // true when the filter has been used OR the set is built step by step (AddObject...)
$this->m_aData = array(); // array of (row => array of (classalias) => object/null)
$this->m_aId2Row = array(); // array of (pkey => index in m_aData)
$this->m_bLoaded = false;
$this->m_aData = array(); // array of (row => array of (classalias) => object)
$this->m_aId2Row = array();
$this->m_iCurrRow = 0;
}
@@ -81,46 +76,6 @@ class DBObjectSet
return $sRet;
}
public function OptimizeColumnLoad($aAttToLoad)
{
if (is_null($aAttToLoad))
{
$this->m_aAttToLoad = null;
}
else
{
// Complete the attribute list with the attribute codes
$aAttToLoadWithAttDef = array();
foreach($aAttToLoad as $sClassAlias => $aAttList)
{
$aSelectedClasses = $this->m_oFilter->GetSelectedClasses();
$sClass = $aSelectedClasses[$sClassAlias];
foreach($aAttList as $sAttToLoad)
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad);
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad] = $oAttDef;
if ($oAttDef->IsExternalKey())
{
// Add the external key friendly name anytime
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_friendlyname');
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_friendlyname'] = $oFriendlyNameAttDef;
}
}
// Add the friendly name anytime
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, 'friendlyname');
$aAttToLoadWithAttDef[$sClassAlias]['friendlyname'] = $oFriendlyNameAttDef;
// Make sure that the final class is requested anytime, whatever the specification (needed for object construction!)
if (!MetaModel::IsStandaloneClass($sClass) && !array_key_exists('finalclass', $aAttList))
{
$aAttToLoadWithAttDef[$sClassAlias]['finalclass'] = MetaModel::GetAttributeDef($sClass, 'finalclass');
}
}
$this->m_aAttToLoad = $aAttToLoadWithAttDef;
}
}
static public function FromObject($oObject)
{
$oRetSet = self::FromScratch(get_class($oObject));
@@ -130,8 +85,7 @@ class DBObjectSet
static public function FromScratch($sClass)
{
$oFilter = new DBObjectSearch($sClass);
$oFilter->AddConditionExpression(new FalseExpression());
$oFilter = new CMDBSearchFilter($sClass);
$oRetSet = new self($oFilter);
$oRetSet->m_bLoaded = true; // no DB load
return $oRetSet;
@@ -141,7 +95,9 @@ class DBObjectSet
// input = array of objects
static public function FromArray($sClass, $aObjects)
{
$oRetSet = self::FromScratch($sClass);
$oFilter = new CMDBSearchFilter($sClass);
$oRetSet = new self($oFilter);
$oRetSet->m_bLoaded = true; // no DB load
$oRetSet->AddObjectArray($aObjects, $sClass);
return $oRetSet;
}
@@ -206,42 +162,19 @@ class DBObjectSet
{
if (!$this->m_bLoaded) $this->Load();
$aSelectedClasses = $this->m_oFilter->GetSelectedClasses();
$aRet = array();
foreach($this->m_aData as $iRow => $aObjects)
{
foreach($aObjects as $sClassAlias => $oObject)
{
if (is_null($oObject))
{
$aRet[$iRow][$sClassAlias.'.'.'id'] = null;
}
else
{
$aRet[$iRow][$sClassAlias.'.'.'id'] = $oObject->GetKey();
}
if (is_null($oObject))
{
$sClass = $aSelectedClasses[$sClassAlias];
}
else
{
$sClass = get_class($oObject);
}
$aRet[$iRow][$sClassAlias.'.'.'id'] = $oObject->GetKey();
$sClass = get_class($oObject);
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if ($oAttDef->IsScalar())
{
$sAttName = $sClassAlias.'.'.$sAttCode;
if (is_null($oObject))
{
$aRet[$iRow][$sAttName] = null;
}
else
{
$aRet[$iRow][$sAttName] = $oObject->Get($sAttCode);
}
$aRet[$iRow][$sAttName] = $oObject->Get($sAttCode);
}
}
}
@@ -269,20 +202,7 @@ class DBObjectSet
public function GetFilter()
{
if (count($this->m_aAddedIds) == 0)
{
return $this->m_oFilter;
}
else
{
$oFilter = clone $this->m_oFilter;
$oIdListExpr = ListExpression::FromScalars(array_keys($this->m_aAddedIds));
$oIdExpr = new FieldExpression('id', $oFilter->GetClassAlias());
$oIdInList = new BinaryExpression($oIdExpr, 'IN', $oIdListExpr);
$oFilter->MergeConditionExpression($oIdInList);
return $oFilter;
}
return $this->m_oFilter;
}
public function GetClass()
@@ -290,11 +210,6 @@ class DBObjectSet
return $this->m_oFilter->GetClass();
}
public function GetClassAlias()
{
return $this->m_oFilter->GetClassAlias();
}
public function GetSelectedClasses()
{
return $this->m_oFilter->GetSelectedClasses();
@@ -305,30 +220,12 @@ class DBObjectSet
return MetaModel::GetRootClass($this->GetClass());
}
public function GetArgs()
{
return $this->m_aArgs;
}
public function SetLimit($iLimitCount, $iLimitStart = 0)
{
$this->m_iLimitCount = $iLimitCount;
$this->m_iLimitStart = $iLimitStart;
}
public function SetOrderBy($aOrderBy)
{
if ($this->m_aOrderBy != $aOrderBy)
{
$this->m_aOrderBy = $aOrderBy;
if ($this->m_bLoaded)
{
$this->m_bLoaded = false;
$this->Load();
}
}
}
public function GetLimitCount()
{
return $this->m_iLimitCount;
@@ -339,33 +236,16 @@ class DBObjectSet
return $this->m_iLimitStart;
}
public function GetRealSortOrder()
{
// Get the class default sort order if not specified with the API
//
if (empty($this->m_aOrderBy))
{
return MetaModel::GetOrderByDefault($this->m_oFilter->GetClass());
}
else
{
return $this->m_aOrderBy;
}
}
public function Load()
{
if ($this->m_bLoaded) return;
// Note: it is mandatory to set this value now, to protect against reentrance
$this->m_bLoaded = true;
if ($this->m_iLimitCount > 0)
{
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->GetRealSortOrder(), $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec, $this->m_iLimitCount, $this->m_iLimitStart);
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_iLimitCount, $this->m_iLimitStart);
}
else
{
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->GetRealSortOrder(), $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs);
}
$resQuery = CMDBSource::Query($sSQL);
if (!$resQuery) return;
@@ -376,42 +256,25 @@ class DBObjectSet
$aObjects = array();
foreach ($this->m_oFilter->GetSelectedClasses() as $sClassAlias => $sClass)
{
if (is_null($aRow[$sClassAlias.'id']))
{
$oObject = null;
}
else
{
$oObject = MetaModel::GetObjectByRow($sClass, $aRow, $sClassAlias, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
}
$oObject = MetaModel::GetObjectByRow($sClass, $aRow, $sClassAlias);
$aObjects[$sClassAlias] = $oObject;
}
$this->AddObjectExtended($aObjects, true /* internal load */);
$this->AddObjectExtended($aObjects);
}
CMDBSource::FreeResult($resQuery);
$this->m_bLoaded = true;
}
public function Count()
{
if ($this->m_bLoaded && ($this->m_iLimitCount == 0) && ($this->m_iLimitStart == 0))
{
return count($this->m_aData);
}
else
{
if (is_null($this->m_iCount))
{
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, array(), $this->m_aArgs, null, null, 0, 0, true);
$resQuery = CMDBSource::Query($sSQL);
if (!$resQuery) return 0;
$aRow = CMDBSource::FetchArray($resQuery);
CMDBSource::FreeResult($resQuery);
$this->m_iCount = $aRow['COUNT'];
}
return $this->m_iCount;
}
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, 0, 0, true);
$resQuery = CMDBSource::Query($sSQL);
if (!$resQuery) return 0;
$aRow = CMDBSource::FetchArray($resQuery);
CMDBSource::FreeResult($resQuery);
return $aRow['COUNT'];
}
public function Fetch($sClassAlias = '')
@@ -450,10 +313,7 @@ class DBObjectSet
public function Rewind()
{
if ($this->m_bLoaded)
{
$this->Seek(0);
}
$this->Seek(0);
}
public function Seek($iRow)
@@ -466,8 +326,6 @@ class DBObjectSet
public function AddObject($oObject, $sClassAlias = '')
{
if (!$this->m_bLoaded) $this->Load();
if (strlen($sClassAlias) == 0)
{
$sClassAlias = $this->m_oFilter->GetClassAlias();
@@ -475,37 +333,22 @@ class DBObjectSet
$iNextPos = count($this->m_aData);
$this->m_aData[$iNextPos][$sClassAlias] = $oObject;
if (!is_null($oObject))
{
$this->m_aId2Row[$sClassAlias][$oObject->GetKey()] = $iNextPos;
$this->m_aAddedIds[$oObject->GetKey()] = true;
}
$this->m_aId2Row[$sClassAlias][$oObject->GetKey()] = $iNextPos;
}
protected function AddObjectExtended($aObjectArray, $bInternalLoad = false)
protected function AddObjectExtended($aObjectArray)
{
if (!$this->m_bLoaded) $this->Load();
$iNextPos = count($this->m_aData);
foreach ($aObjectArray as $sClassAlias => $oObject)
{
$this->m_aData[$iNextPos][$sClassAlias] = $oObject;
if (!is_null($oObject))
{
$this->m_aId2Row[$sClassAlias][$oObject->GetKey()] = $iNextPos;
if (!$bInternalLoad)
{
$this->m_aAddedIds[$oObject->GetKey()] = true;
}
}
$this->m_aId2Row[$sClassAlias][$oObject->GetKey()] = $iNextPos;
}
}
public function AddObjectArray($aObjects, $sClassAlias = '')
{
if (!$this->m_bLoaded) $this->Load();
// #@# todo - add a check on the object class ?
foreach ($aObjects as $oObj)
{
@@ -550,43 +393,6 @@ class DBObjectSet
return $oNewSet;
}
// Note: This verb works only with objects existing in the database
//
public function HasSameContents($oObjectSet)
{
if ($this->GetRootClass() != $oObjectSet->GetRootClass())
{
return false;
}
if (!$this->m_bLoaded) $this->Load();
if ($this->Count() != $oObjectSet->Count())
{
return false;
}
$sClassAlias = $this->m_oFilter->GetClassAlias();
$oObjectSet->Rewind();
while ($oObject = $oObjectSet->Fetch())
{
$iObjectKey = $oObject->GetKey();
if ($iObjectKey < 0)
{
return false;
}
if (!array_key_exists($iObjectKey, $this->m_aId2Row[$sClassAlias]))
{
return false;
}
$iRow = $this->m_aId2Row[$sClassAlias][$iObjectKey];
$oSibling = $this->m_aData[$iRow][$sClassAlias];
if (!$oObject->Equals($oSibling))
{
return false;
}
}
return true;
}
public function CreateDelta($oObjectSet)
{
if ($this->GetRootClass() != $oObjectSet->GetRootClass())
@@ -631,156 +437,6 @@ class DBObjectSet
}
return $aRelatedObjs;
}
/**
* Builds an object that contains the values that are common to all the objects
* in the set. If for a given attribute, objects in the set have various values
* then the resulting object will contain null for this value.
* @param $aValues Hash Output: the distribution of the values, in the set, for each attribute
* @return Object
*/
public function ComputeCommonObject(&$aValues)
{
$sClass = $this->GetClass();
$aList = MetaModel::ListAttributeDefs($sClass);
$aValues = array();
foreach($aList as $sAttCode => $oAttDef)
{
if ($oAttDef->IsScalar())
{
$aValues[$sAttCode] = array();
}
}
$this->Rewind();
while($oObj = $this->Fetch())
{
foreach($aList as $sAttCode => $oAttDef)
{
if ($oAttDef->IsScalar() && $oAttDef->IsWritable())
{
$currValue = $oObj->Get($sAttCode);
if (is_object($currValue)) continue; // Skip non scalar values...
if(!array_key_exists($currValue, $aValues[$sAttCode]))
{
$aValues[$sAttCode][$currValue] = array('count' => 1, 'display' => $oObj->GetAsHTML($sAttCode));
}
else
{
$aValues[$sAttCode][$currValue]['count']++;
}
}
}
}
foreach($aValues as $sAttCode => $aMultiValues)
{
if (count($aMultiValues) > 1)
{
uasort($aValues[$sAttCode], 'HashCountComparison');
}
}
// Now create an object that has values for the homogenous values only
$oCommonObj = new $sClass(); // @@ What if the class is abstract ?
$aComments = array();
$iFormId = cmdbAbstractObject::GetNextFormId(); // Identifier that prefixes all the form fields
$sReadyScript = '';
$aDependsOn = array();
$sFormPrefix = '2_';
foreach($aList as $sAttCode => $oAttDef)
{
if ($oAttDef->IsScalar() && $oAttDef->IsWritable())
{
if ($oAttDef->GetEditClass() == 'One Way Password')
{
$oCommonObj->Set($sAttCode, null);
}
else
{
$iCount = count($aValues[$sAttCode]);
if ($iCount == 1)
{
// Homogenous value
reset($aValues[$sAttCode]);
$aKeys = array_keys($aValues[$sAttCode]);
$currValue = $aKeys[0]; // The only value is the first key
$oCommonObj->Set($sAttCode, $currValue);
}
else
{
// Non-homogenous value
$oCommonObj->Set($sAttCode, null);
}
}
}
}
$this->Rewind();
return $oCommonObj;
}
/**
* List the constant fields (and their value) in the given query
* @return Hash [Alias][AttCode] => value
*/
public function ListConstantFields()
{
$aScalarArgs = $this->ExpandArgs();
$aConst = $this->m_oFilter->ListConstantFields();
foreach($aConst as $sClassAlias => $aVals)
{
foreach($aVals as $sCode => $oExpr)
{
if ($oExpr instanceof ScalarExpression)
{
$aConst[$sClassAlias][$sCode] = $oExpr->GetValue();
}
else //Variable
{
$aConst[$sClassAlias][$sCode] = $aScalarArgs[$oExpr->GetName()];
}
}
}
return $aConst;
}
protected function ExpandArgs()
{
$aScalarArgs = $this->m_oFilter->GetInternalParams();
foreach($this->m_aArgs as $sArgName => $value)
{
if (MetaModel::IsValidObject($value))
{
$aScalarArgs = array_merge($aScalarArgs, $value->ToArgs($sArgName));
}
else
{
$aScalarArgs[$sArgName] = (string) $value;
}
}
$aScalarArgs['current_contact_id'] = UserRights::GetContactId();
return $aScalarArgs;
}
public function ApplyParameters()
{
$aScalarArgs = $this->ExpandArgs();
$this->m_oFilter->ApplyParameters($aScalarArgs);
}
}
/**
* Helper function to perform a custom sort of a hash array
*/
function HashCountComparison($a, $b) // Sort descending on 'count'
{
if ($a['count'] == $b['count'])
{
return 0;
}
return ($a['count'] > $b['count']) ? -1 : 1;
}
?>

View File

@@ -1,288 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Class dbObject: the root of persistent classes
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
class DeleteException extends CoreException
{
}
/**
* Deletion plan (other objects to be deleted/modified, eventual issues, etc.)
*
* @package iTopORM
*/
class DeletionPlan
{
//protected $m_aIssues;
protected $m_bFoundStopper;
protected $m_bFoundSecurityIssue;
protected $m_bFoundManualDelete;
protected $m_bFoundManualOperation;
protected $m_iToDelete;
protected $m_iToUpdate;
protected $m_aToDelete;
protected $m_aToUpdate;
protected static $m_aModeUpdate = array(
DEL_SILENT => array(
DEL_SILENT => DEL_SILENT,
DEL_AUTO => DEL_AUTO,
DEL_MANUAL => DEL_MANUAL
),
DEL_MANUAL => array(
DEL_SILENT => DEL_MANUAL,
DEL_AUTO => DEL_AUTO,
DEL_MANUAL => DEL_MANUAL
),
DEL_AUTO => array(
DEL_SILENT => DEL_AUTO,
DEL_AUTO => DEL_AUTO,
DEL_MANUAL => DEL_AUTO
)
);
public function __construct()
{
$this->m_iToDelete = 0;
$this->m_iToUpdate = 0;
$this->m_aToDelete = array();
$this->m_aToUpdate = array();
$this->m_bFoundStopper = false;
$this->m_bFoundSecurityIssue = false;
$this->m_bFoundManualDelete = false;
$this->m_bFoundManualOperation = false;
}
public function ComputeResults()
{
foreach($this->m_aToDelete as $sClass => $aToDelete)
{
foreach($aToDelete as $iId => $aData)
{
$this->m_iToDelete++;
if (isset($aData['issue']))
{
$this->m_bFoundStopper = true;
$this->m_bFoundManualOperation = true;
if (isset($aData['issue_security']))
{
$this->m_bFoundSecurityIssue = true;
}
}
if ($aData['mode'] == DEL_MANUAL)
{
$this->m_bFoundStopper = true;
$this->m_bFoundManualDelete = true;
}
}
}
foreach($this->m_aToUpdate as $sClass => $aToUpdate)
{
foreach($aToUpdate as $iId => $aData)
{
$this->m_iToUpdate++;
$oObject = $aData['to_reset'];
$aExtKeyLabels = array();
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef)
{
$oObject->Set($sRemoteExtKey, $aData['values'][$sRemoteExtKey]);
$aExtKeyLabels[] = $aRemoteAttDef->GetLabel();
}
$this->m_aToUpdate[$sClass][$iId]['attributes_list'] = implode(', ', $aExtKeyLabels);
list($bRes, $aIssues, $bSecurityIssues) = $oObject->CheckToWrite();
if (!$bRes)
{
$this->m_aToUpdate[$sClass][$iId]['issue'] = implode(', ', $aIssues);
$this->m_bFoundStopper = true;
if ($bSecurityIssues)
{
$this->m_aToUpdate[$sClass][$iId]['issue_security'] = true;
$this->m_bFoundSecurityIssue = true;
}
}
}
}
}
public function GetIssues()
{
$aIssues = array();
foreach ($this->m_aToDelete as $sClass => $aToDelete)
{
foreach ($aToDelete as $iId => $aData)
{
if (isset($aData['issue']))
{
$aIssues[] = $aData['issue'];
}
}
}
foreach ($this->m_aToUpdate as $sClass => $aToUpdate)
{
foreach ($aToUpdate as $iId => $aData)
{
if (isset($aData['issue']))
{
$aIssues[] = $aData['issue'];
}
}
}
return $aIssues;
}
public function ListDeletes()
{
return $this->m_aToDelete;
}
public function ListUpdates()
{
return $this->m_aToUpdate;
}
public function GetTargetCount()
{
return $this->m_iToDelete + $this->m_iToUpdate;
}
public function FoundStopper()
{
return $this->m_bFoundStopper;
}
public function FoundSecurityIssue()
{
return $this->m_bFoundSecurityIssue;
}
public function FoundManualOperation()
{
return $this->m_bFoundManualOperation;
}
public function FoundManualDelete()
{
return $this->m_bFoundManualDelete;
}
public function FoundManualUpdate()
{
}
public function AddToDelete($oObject, $iDeletionMode = null)
{
if (is_null($iDeletionMode))
{
$bRequestedExplicitely = true;
$iDeletionMode = DEL_AUTO;
}
else
{
$bRequestedExplicitely = false;
}
$sClass = get_class($oObject);
$iId = $oObject->GetKey();
if (isset($this->m_aToUpdate[$sClass][$iId]))
{
unset($this->m_aToUpdate[$sClass][$iId]);
}
if (isset($this->m_aToDelete[$sClass][$iId]))
{
if ($this->m_aToDelete[$sClass][$iId]['requested_explicitely'])
{
// No change: let it in mode DEL_AUTO
}
else
{
$iPrevDeletionMode = $this->m_aToDelete[$sClass][$iId]['mode'];
$iNewDeletionMode = self::$m_aModeUpdate[$iPrevDeletionMode][$iDeletionMode];
$this->m_aToDelete[$sClass][$iId]['mode'] = $iNewDeletionMode;
if ($bRequestedExplicitely)
{
// This object was in the root list
$this->m_aToDelete[$sClass][$iId]['requested_explicitely'] = true;
$this->m_aToDelete[$sClass][$iId]['mode'] = DEL_AUTO;
}
}
}
else
{
$this->m_aToDelete[$sClass][$iId] = array(
'to_delete' => $oObject,
'mode' => $iDeletionMode,
'requested_explicitely' => $bRequestedExplicitely,
);
}
}
public function SetDeletionIssues($oObject, $aIssues, $bSecurityIssue)
{
if (count($aIssues) > 0)
{
$sClass = get_class($oObject);
$iId = $oObject->GetKey();
$this->m_aToDelete[$sClass][$iId]['issue'] = implode(', ', $aIssues);
if ($bSecurityIssue)
{
$this->m_aToDelete[$sClass][$iId]['issue_security'] = true;
}
}
}
public function AddToUpdate($oObject, $oAttDef, $value = 0)
{
$sClass = get_class($oObject);
$iId = $oObject->GetKey();
if (isset($this->m_aToDelete[$sClass][$iId]))
{
// skip... it should be deleted anyhow !
}
else
{
if (!isset($this->m_aToUpdate[$sClass][$iId]))
{
$this->m_aToUpdate[$sClass][$iId] = array(
'to_reset' => $oObject,
);
}
$this->m_aToUpdate[$sClass][$iId]['attributes'][$oAttDef->GetCode()] = $oAttDef;
$this->m_aToUpdate[$sClass][$iId]['values'][$oAttDef->GetCode()] = $value;
}
}
}
?>

View File

@@ -1,332 +1,235 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Class Dict
* Management of localizable strings
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
class DictException extends CoreException
{
}
class DictExceptionUnknownLanguage extends DictException
{
public function __construct($sLanguageCode)
{
$aContext = array();
$aContext['language_code'] = $sLanguageCode;
parent::__construct('Unknown localization language', $aContext);
}
}
class DictExceptionMissingString extends DictException
{
public function __construct($sLanguageCode, $sStringCode)
{
$aContext = array();
$aContext['language_code'] = $sLanguageCode;
$aContext['string_code'] = $sStringCode;
parent::__construct('Missing localized string', $aContext);
}
}
define('DICT_ERR_STRING', 1); // when a string is missing, return the identifier
define('DICT_ERR_EXCEPTION', 2); // when a string is missing, throw an exception
//define('DICT_ERR_LOG', 3); // when a string is missing, log an error
class Dict
{
protected static $m_bTraceFiles = false;
protected static $m_aEntryFiles = array();
protected static $m_iErrorMode = DICT_ERR_STRING;
protected static $m_sDefaultLanguage = 'EN US';
protected static $m_sCurrentLanguage = null; // No language selected by default
protected static $m_aLanguages = array(); // array( code => array( 'description' => '...', 'localized_description' => '...') ...)
protected static $m_aData = array();
public static function EnableTraceFiles()
{
self::$m_bTraceFiles = true;
}
public static function GetEntryFiles()
{
return self::$m_aEntryFiles;
}
public static function SetDefaultLanguage($sLanguageCode)
{
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
{
throw new DictExceptionUnknownLanguage($sLanguageCode);
}
self::$m_sDefaultLanguage = $sLanguageCode;
}
public static function SetUserLanguage($sLanguageCode)
{
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
{
throw new DictExceptionUnknownLanguage($sLanguageCode);
}
self::$m_sCurrentLanguage = $sLanguageCode;
}
public static function GetUserLanguage()
{
if (self::$m_sCurrentLanguage == null) // May happen when no user is logged in (i.e login screen, non authentifed page)
{
// In which case let's use the default language
return self::$m_sDefaultLanguage;
}
return self::$m_sCurrentLanguage;
}
//returns a hash array( code => array( 'description' => '...', 'localized_description' => '...') ...)
public static function GetLanguages()
{
return self::$m_aLanguages;
}
// iErrorMode from {DICT_ERR_STRING, DICT_ERR_EXCEPTION}
public static function SetErrorMode($iErrorMode)
{
self::$m_iErrorMode = $iErrorMode;
}
public static function S($sStringCode, $sDefault = null)
{
// Attempt to find the string in the user language
//
if (!array_key_exists(self::GetUserLanguage(), self::$m_aData))
{
// It may happen, when something happens before the dictionnaries get loaded
return $sStringCode;
}
$aCurrentDictionary = self::$m_aData[self::GetUserLanguage()];
if (array_key_exists($sStringCode, $aCurrentDictionary))
{
return $aCurrentDictionary[$sStringCode];
}
// Attempt to find the string in the default language
//
$aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage];
if (array_key_exists($sStringCode, $aDefaultDictionary))
{
return $aDefaultDictionary[$sStringCode];
}
// Attempt to find the string in english
//
$aDefaultDictionary = self::$m_aData['EN US'];
if (array_key_exists($sStringCode, $aDefaultDictionary))
{
return $aDefaultDictionary[$sStringCode];
}
// Could not find the string...
//
switch (self::$m_iErrorMode)
{
case DICT_ERR_STRING:
if (is_null($sDefault))
{
return $sStringCode;
}
else
{
return $sDefault;
}
break;
case DICT_ERR_EXCEPTION:
default:
throw new DictExceptionMissingString(self::$m_sCurrentLanguage, $sStringCode);
break;
}
return 'bug!';
}
public static function Format($sFormatCode /*, ... arguments ....*/)
{
$sLocalizedFormat = self::S($sFormatCode);
$aArguments = func_get_args();
array_shift($aArguments);
if ($sLocalizedFormat == $sFormatCode)
{
// Make sure the information will be displayed (ex: an error occuring before the dictionary gets loaded)
return $sFormatCode.' - '.implode(', ', $aArguments);
}
return vsprintf($sLocalizedFormat, $aArguments);
}
// sLanguageCode: Code identifying the language i.e. FR-FR
// sEnglishLanguageDesc: Description of the language code, in English. i.e. French (France)
// sLocalizedLanguageDesc: Description of the language code, in its own language. i.e. Français (France)
// aEntries: Hash array of dictionnary entries
// ~~ or ~* can be used to indicate entries still to be translated.
public static function Add($sLanguageCode, $sEnglishLanguageDesc, $sLocalizedLanguageDesc, $aEntries)
{
if (self::$m_bTraceFiles)
{
$aBacktrace = debug_backtrace();
$sFile = $aBacktrace[0]["file"];
foreach($aEntries as $sKey => $sValue)
{
self::$m_aEntryFiles[$sLanguageCode][$sKey] = array(
'file' => $sFile,
'value' => $sValue
);
}
}
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
{
self::$m_aLanguages[$sLanguageCode] = array('description' => $sEnglishLanguageDesc, 'localized_description' => $sLocalizedLanguageDesc);
self::$m_aData[$sLanguageCode] = array();
}
foreach($aEntries as $sCode => $sValue)
{
self::$m_aData[$sLanguageCode][$sCode] = self::FilterString($sValue);
}
}
/**
* Clone a string in every language (if it exists in that language)
*/
public static function CloneString($sSourceCode, $sDestCode)
{
foreach(self::$m_aLanguages as $sLanguageCode => $foo)
{
if (isset(self::$m_aData[$sLanguageCode][$sSourceCode]))
{
self::$m_aData[$sLanguageCode][$sDestCode] = self::$m_aData[$sLanguageCode][$sSourceCode];
}
}
}
public static function MakeStats($sLanguageCode, $sLanguageRef = 'EN US')
{
$aMissing = array(); // Strings missing for the target language
$aUnexpected = array(); // Strings defined for the target language, but not found in the reference dictionary
$aNotTranslated = array(); // Strings having the same value in both dictionaries
$aOK = array(); // Strings having different values in both dictionaries
foreach (self::$m_aData[$sLanguageRef] as $sStringCode => $sValue)
{
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageCode]))
{
$aMissing[$sStringCode] = $sValue;
}
}
foreach (self::$m_aData[$sLanguageCode] as $sStringCode => $sValue)
{
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageRef]))
{
$aUnexpected[$sStringCode] = $sValue;
}
else
{
// The value exists in the reference
$sRefValue = self::$m_aData[$sLanguageRef][$sStringCode];
if ($sValue == $sRefValue)
{
$aNotTranslated[$sStringCode] = $sValue;
}
else
{
$aOK[$sStringCode] = $sValue;
}
}
}
return array($aMissing, $aUnexpected, $aNotTranslated, $aOK);
}
public static function Dump()
{
MyHelpers::var_dump_html(self::$m_aData);
}
public static function InCache($sApplicationPrefix)
{
if (function_exists('apc_fetch'))
{
$bResult = false;
// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
//
self::$m_aData = apc_fetch($sApplicationPrefix.'-dict');
if (is_bool(self::$m_aData) && (self::$m_aData === false))
{
self::$m_aData = array();
}
else
{
self::$m_aLanguages = apc_fetch($sApplicationPrefix.'-languages');
if (is_bool(self::$m_aLanguages) && (self::$m_aLanguages === false))
{
self::$m_aLanguages = array();
}
else
{
$bResult = true;
}
}
return $bResult;
}
return false;
}
public static function InitCache($sApplicationPrefix)
{
if (function_exists('apc_store'))
{
apc_store($sApplicationPrefix.'-languages', self::$m_aLanguages);
apc_store($sApplicationPrefix.'-dict', self::$m_aData);
}
}
public static function ResetCache($sApplicationPrefix)
{
if (function_exists('apc_delete'))
{
apc_delete($sApplicationPrefix.'-languages');
apc_delete($sApplicationPrefix.'-dict');
}
}
protected static function FilterString($s)
{
return str_replace(array('~~', '~*'), '', $s);
}
}
?>
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Class Dict
* Management of localizable strings
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
class DictException extends CoreException
{
}
class DictExceptionUnknownLanguage extends DictException
{
public function __construct($sLanguageCode)
{
$aContext = array();
$aContext['language_code'] = $sLanguageCode;
parent::__construct('Unknown localization language', $aContext);
}
}
class DictExceptionMissingString extends DictException
{
public function __construct($sLanguageCode, $sStringCode)
{
$aContext = array();
$aContext['language_code'] = $sLanguageCode;
$aContext['string_code'] = $sStringCode;
parent::__construct('Missing localized string', $aContext);
}
}
define('DICT_ERR_STRING', 1); // when a string is missing, return the identifier
define('DICT_ERR_EXCEPTION', 2); // when a string is missing, throw an exception
//define('DICT_ERR_LOG', 3); // when a string is missing, log an error
class Dict
{
protected static $m_iErrorMode = DICT_ERR_STRING;
protected static $m_sDefaultLanguage = 'EN US';
protected static $m_sCurrentLanguage = null; // No language selected by default
protected static $m_aLanguages = array(); // array( code => array( 'description' => '...', 'localized_description' => '...') ...)
protected static $m_aData = array();
public static function SetDefaultLanguage($sLanguageCode)
{
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
{
throw new DictExceptionUnknownLanguage($sLanguageCode);
}
self::$m_sDefaultLanguage = $sLanguageCode;
}
public static function SetUserLanguage($sLanguageCode)
{
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
{
throw new DictExceptionUnknownLanguage($sLanguageCode);
}
self::$m_sCurrentLanguage = $sLanguageCode;
}
public static function GetCurrentLanguage()
{
if (self::$m_sCurrentLanguage == null) // May happen when no user is logged in (i.e login screen, non authentifed page)
{
// In which case let's use the default language
return self::$m_sDefaultLanguage;
}
return self::$m_sCurrentLanguage;
}
//returns a hash array( code => array( 'description' => '...', 'localized_description' => '...') ...)
public static function GetLanguages()
{
return self::$m_aLanguages;
}
// iErrorMode from {DICT_ERR_STRING, DICT_ERR_EXCEPTION}
public static function SetErrorMode($iErrorMode)
{
self::$m_iErrorMode = $iErrorMode;
}
public static function S($sStringCode, $sDefault = null)
{
// Attempt to find the string in the user language
//
if (!array_key_exists(self::GetCurrentLanguage(), self::$m_aData))
{
// It may happen, when something happens before the dictionnaries get loaded
return $sStringCode;
}
$aCurrentDictionary = self::$m_aData[self::GetCurrentLanguage()];
if (array_key_exists($sStringCode, $aCurrentDictionary))
{
return $aCurrentDictionary[$sStringCode];
}
// Attempt to find the string in the default language
//
$aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage];
if (array_key_exists($sStringCode, $aDefaultDictionary))
{
return $aDefaultDictionary[$sStringCode];
}
// Attempt to find the string in english
//
$aDefaultDictionary = self::$m_aData['EN US'];
if (array_key_exists($sStringCode, $aDefaultDictionary))
{
return $aDefaultDictionary[$sStringCode];
}
// Could not find the string...
//
switch (self::$m_iErrorMode)
{
case DICT_ERR_STRING:
if (is_null($sDefault))
{
return $sStringCode;
}
else
{
return $sDefault;
}
break;
case DICT_ERR_EXCEPTION:
default:
throw new DictExceptionMissingString(self::$m_sCurrentLanguage, $sStringCode);
break;
}
return 'bug!';
}
public static function Format($sFormatCode /*, ... arguments ....*/)
{
$sLocalizedFormat = self::S($sFormatCode);
$aArguments = func_get_args();
if ($sLocalizedFormat == $sFormatCode)
{
// Make sure the information will be displayed (ex: an error occuring before the dictionary gets loaded)
return $sFormatCode.' - '.implode(', ', $aArguments);
}
array_shift($aArguments);
return vsprintf($sLocalizedFormat, $aArguments);
}
// sLanguageCode: Code identifying the language i.e. FR-FR
// sEnglishLanguageDesc: Description of the language code, in English. i.e. French (France)
// sLocalizedLanguageDesc: Description of the language code, in its own language. i.e. Français (France)
// aEntries: Hash array of dictionnary entries
public static function Add($sLanguageCode, $sEnglishLanguageDesc, $sLocalizedLanguageDesc, $aEntries)
{
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
{
self::$m_aLanguages[$sLanguageCode] = array('description' => $sEnglishLanguageDesc, 'localized_description' => $sLocalizedLanguageDesc);
self::$m_aData[$sLanguageCode] = array();
}
self::$m_aData[$sLanguageCode] = array_merge(self::$m_aData[$sLanguageCode], $aEntries);
}
public static function MakeStats($sLanguageCode, $sLanguageRef = 'EN US')
{
$aMissing = array(); // Strings missing for the target language
$aUnexpected = array(); // Strings defined for the target language, but not found in the reference dictionary
$aNotTranslated = array(); // Strings having the same value in both dictionaries
$aOK = array(); // Strings having different values in both dictionaries
foreach (self::$m_aData[$sLanguageRef] as $sStringCode => $sValue)
{
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageCode]))
{
$aMissing[$sStringCode] = $sValue;
}
}
foreach (self::$m_aData[$sLanguageCode] as $sStringCode => $sValue)
{
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageRef]))
{
$aUnexpected[$sStringCode] = $sValue;
}
else
{
// The value exists in the reference
$sRefValue = self::$m_aData[$sLanguageRef][$sStringCode];
if ($sValue == $sRefValue)
{
$aNotTranslated[$sStringCode] = $sValue;
}
else
{
$aOK[$sStringCode] = $sValue;
}
}
}
return array($aMissing, $aUnexpected, $aNotTranslated, $aOK);
}
public static function Dump()
{
MyHelpers::var_dump_html(self::$m_aData);
}
}
?>

View File

@@ -15,7 +15,8 @@
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Send an email (abstraction for synchronous/asynchronous modes)
* Send an mail (for notification, testing,... purposes)
* #@# TODO - replace by a more sophisticated mean (and update the prototype)
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
@@ -23,214 +24,90 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once(APPROOT.'/lib/swiftmailer/lib/swift_required.php');
Swift_Preferences::getInstance()->setCharset('UTF-8');
define ('EMAIL_SEND_OK', 0);
define ('EMAIL_SEND_PENDING', 1);
define ('EMAIL_SEND_ERROR', 2);
class EMail
{
protected static $m_oConfig = null;
public function LoadConfig($sConfigFile = ITOP_DEFAULT_CONFIG_FILE)
{
if (is_null(self::$m_oConfig))
{
self::$m_oConfig = new Config($sConfigFile);
}
}
protected $m_oMessage;
protected $m_sBody;
protected $m_sSubject;
protected $m_sTo;
protected $m_aHeaders; // array of key=>value
public function __construct()
{
$this->m_oMessage = Swift_Message::newInstance();
$oEncoder = new Swift_Mime_ContentEncoder_PlainContentEncoder('8bit');
$this->m_oMessage->setEncoder($oEncoder);
$this->m_sTo = '';
$this->m_sSubject = '';
$this->m_sBody = '';
$this->m_aHeaders = array();
}
protected function SendAsynchronous(&$aIssues, $oLog = null)
// Errors management : not that simple because we need that function to be
// executed in the background, while making sure that any issue would be reported clearly
protected $m_aMailErrors; //array of strings explaining the issues
public function mail_error_handler($errno, $errstr, $errfile, $errline)
{
try
{
AsyncSendEmail::AddToQueue($this, $oLog);
}
catch(Exception $e)
{
$aIssues = array($e->GetMessage());
return EMAIL_SEND_ERROR;
}
$aIssues = array();
return EMAIL_SEND_PENDING;
$sCleanMessage= str_replace("mail() [<a href='function.mail'>function.mail</a>]: ", "", $errstr);
$this->m_aMailErrors[] = $sCleanMessage;
}
protected function SendSynchronous(&$aIssues, $oLog = null)
// returns a list of issues if any
public function Send()
{
$this->LoadConfig();
$sTransport = self::$m_oConfig->Get('email_transport');
switch ($sTransport)
$sHeaders = 'MIME-Version: 1.0' . "\r\n";
// ! the case is important for MS-Outlook
$sHeaders .= 'Content-Type: text/html; charset=UTF-8' . "\r\n";
$sHeaders .= 'Content-Transfer-Encoding: 8bit' . "\r\n";
foreach ($this->m_aHeaders as $sKey => $sValue)
{
case 'SMTP':
$sHost = self::$m_oConfig->Get('email_transport_smtp.host');
$sPort = self::$m_oConfig->Get('email_transport_smtp.port');
$sEncryption = self::$m_oConfig->Get('email_transport_smtp.encryption');
$sUserName = self::$m_oConfig->Get('email_transport_smtp.username');
$sPassword = self::$m_oConfig->Get('email_transport_smtp.password');
$oTransport = Swift_SmtpTransport::newInstance($sHost, $sPort, $sEncryption);
if (strlen($sUserName) > 0)
{
$oTransport->setUsername($sUserName);
$oTransport->setPassword($sPassword);
}
break;
case 'PHPMail':
default:
$oTransport = Swift_MailTransport::newInstance();
$sHeaders .= "$sKey: $sValue\r\n";
}
$oMailer = Swift_Mailer::newInstance($oTransport);
$iSent = $oMailer->send($this->m_oMessage);
if ($iSent === false)
// Under Windows (not yet proven for Linux/PHP) mail may issue a warning
// that I could not mask (tried error_reporting(), etc.)
$this->m_aMailErrors = array();
set_error_handler(array($this, 'mail_error_handler'));
$bRes = mail
(
$this->m_sTo,
$this->m_sSubject,
$this->m_sBody,
$sHeaders
);
restore_error_handler();
if (!$bRes && empty($this->m_aMailErrors))
{
$aIssues = 'une erreur s\'est produite... mais quoi !!!';
return EMAIL_SEND_ERROR;
}
else
{
$aIssues = array();
return EMAIL_SEND_OK;
$this->m_aMailErrors[] = 'Unknown reason';
}
return $this->m_aMailErrors;
}
public function Send(&$aIssues, $bForceSynchronous = false, $oLog = null)
{
if ($bForceSynchronous)
{
return $this->SendSynchronous($aIssues, $oLog);
}
else
{
$bConfigASYNC = MetaModel::GetConfig()->Get('email_asynchronous');
if ($bConfigASYNC)
{
return $this->SendAsynchronous($aIssues, $oLog);
}
else
{
return $this->SendSynchronous($aIssues, $oLog);
}
}
}
public function AddToHeader($sKey, $sValue)
protected function AddToHeader($sKey, $sValue)
{
if (strlen($sValue) > 0)
{
$oHeaders = $this->m_oMessage->getHeaders();
switch(strtolower($sKey))
{
case 'from':
case 'cc':
case 'bcc':
$aMatches = array();
// Header may be in the form: John Doe <jd@company.com>
if (preg_match('/^([^<]+) <([^>]+)>$/', $sValue, $aMatches))
{
$aHeader = array($aMatches[2] => $aMatches[1]);
}
else
{
$aHeader = array($sValue);
}
$oHeaders->addMailboxHeader($sKey, $aHeader);
break;
default:
$oHeaders->addTextHeader($sKey, $sValue);
}
$this->m_aHeaders[$sKey] = $sValue;
}
}
public function SetMessageId($sId)
{
// Note: Swift will add the angle brackets for you
// so let's remove the angle brackets if present, for historical reasons
$sId = str_replace(array('<', '>'), '', $sId);
$oMsgId = $this->m_oMessage->getHeaders()->get('Message-ID');
$oMsgId->SetId($sId);
}
public function SetReferences($sReferences)
{
$this->AddToHeader('References', $sReferences);
}
public function SetBody($sBody, $sMimeType = 'text/html')
public function SetBody($sBody)
{
$this->m_oMessage->setBody($sBody, $sMimeType);
}
public function AddPart($sText, $sMimeType = 'text/html')
{
$this->m_oMessage->addPart($sText, $sMimeType);
}
public function AddAttachment($data, $sFileName, $sMimeType)
{
$this->m_oMessage->attach(Swift_Attachment::newInstance($data, $sFileName, $sMimeType));
$this->m_sBody = $sBody;
}
public function SetSubject($aSubject)
{
$this->m_oMessage->setSubject($aSubject);
}
public function GetSubject()
{
return $this->m_oMessage->getSubject();
$this->m_sSubject = $aSubject;
}
public function SetRecipientTO($sAddress)
{
$this->m_oMessage->setTo($sAddress);
}
public function GetRecipientTO($bAsString = false)
{
$aRes = $this->m_oMessage->getTo();
if ($bAsString)
{
$aStrings = array();
foreach ($aRes as $sEmail => $sName)
{
if (is_null($sName))
{
$aStrings[] = $sEmail;
}
else
{
$sName = str_replace(array('<', '>'), '', $sName);
$aStrings[] = "$sName <$sEmail>";
}
}
return implode(', ', $aStrings);
}
else
{
return $aRes;
}
$this->m_sTo = $sAddress;
}
public function SetRecipientCC($sAddress)
@@ -243,16 +120,14 @@ class EMail
$this->AddToHeader('Bcc', $sAddress);
}
public function SetRecipientFrom($sAddress, $sLabel = '')
public function SetRecipientFrom($sAddress)
{
if ($sLabel != '')
{
$this->m_oMessage->setFrom(array($sAddress => $sLabel));
}
else
{
$this->m_oMessage->setFrom($sAddress);
}
$this->AddToHeader('From', $sAddress);
// This is required on Windows because otherwise I would get the error
// "sendmail_from" not set in php.ini" even if it is correctly working
// (apparently, once it worked the SMTP server won't claim anymore for it)
ini_set("sendmail_from", $sAddress);
}
public function SetRecipientReplyTo($sAddress)

View File

@@ -25,7 +25,7 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
class Event extends DBObject implements iDisplay
class Event extends cmdbAbstractObject
{
public static function Init()
{
@@ -46,77 +46,14 @@ class Event extends DBObject implements iDisplay
MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('message', 'date', 'userinfo')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'finalclass', 'message')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
/**
* Maps the given context parameter name to the appropriate filter/search code for this class
* @param string $sContextParam Name of the context parameter, i.e. 'org_id'
* @return string Filter code, i.e. 'customer_id'
*/
public static function MapContextParam($sContextParam)
{
if ($sContextParam == 'menu')
{
return null;
}
else
{
return $sContextParam;
}
}
/**
* This function returns a 'hilight' CSS class, used to hilight a given row in a table
* There are currently (i.e defined in the CSS) 4 possible values HILIGHT_CLASS_CRITICAL,
* HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
* To Be overridden by derived classes
* @param void
* @return String The desired higlight class for the object/row
*/
public function GetHilightClass()
{
// Possible return values are:
// HILIGHT_CLASS_CRITICAL, HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
return HILIGHT_CLASS_NONE; // Not hilighted by default
}
public static function GetUIPage()
{
return 'UI.php';
}
function DisplayDetails(WebPage $oPage, $bEditMode = false)
{
// Object's details
//$this->DisplayBareHeader($oPage, $bEditMode);
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->SetCurrentTab(Dict::S('UI:PropertiesTab'));
$this->DisplayBareProperties($oPage, $bEditMode);
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{
if ($bEditMode) return; // Not editable
$aDetails = array();
$sClass = get_class($this);
$aZList = MetaModel::FlattenZlist(MetaModel::GetZListItems($sClass, 'details'));
foreach( $aZList as $sAttCode)
{
$sDisplayValue = $this->GetAsHTML($sAttCode);
$aDetails[] = array('label' => '<span title="'.MetaModel::GetDescription($sClass, $sAttCode).'">'.MetaModel::GetLabel($sClass, $sAttCode).'</span>', 'value' => $sDisplayValue);
}
$oPage->Details($aDetails);
}
}
class EventNotification extends Event
@@ -142,8 +79,8 @@ class EventNotification extends Event
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values"=>null, "sql"=>"object_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo', 'trigger_id', 'action_id', 'object_id')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'message')); // Attributes to be displayed for a list
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'trigger_id', 'action_id', 'object_id')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
@@ -174,11 +111,11 @@ class EventNotificationEmail extends EventNotification
MetaModel::Init_AddAttribute(new AttributeText("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeHTML("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'message', 'trigger_id', 'action_id', 'object_id', 'to', 'cc', 'bcc', 'from', 'subject', 'body')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'message', 'to', 'subject')); // Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'message', 'to', 'subject')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
@@ -321,43 +258,4 @@ class EventWebService extends Event
}
}
class EventLoginUsage extends Event
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_event_loginusage",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
$aZList = array('date', 'user_id');
if (MetaModel::IsValidAttCode('Contact', 'name'))
{
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_name", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"contactid", "is_null_allowed"=>true, "depends_on"=>array())));
$aZList[] = 'contact_name';
}
if (MetaModel::IsValidAttCode('Contact', 'email'))
{
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_email", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"email", "is_null_allowed"=>true, "depends_on"=>array())));
$aZList[] = 'contact_email';
}
// Display lists
MetaModel::Init_SetZListItems('details', array_merge($aZList, array('userinfo', 'message'))); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array_merge($aZList, array('userinfo'))); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', $aZList); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
?>

View File

@@ -30,22 +30,16 @@ class MissingQueryArgument extends CoreException
abstract class Expression
{
// recursive translation of identifiers
abstract public function GetUnresolvedFields($sAlias, &$aUnresolved);
abstract public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true);
abstract public function Translate($aTranslationData, $bMatchAll = true);
// recursive rendering (aArgs used as input by default, or used as output if bRetrofitParams set to True
abstract public function Render(&$aArgs = null, $bRetrofitParams = false);
abstract public function ApplyParameters($aArgs);
// recursively builds an array of class => fieldname
abstract public function ListRequiredFields();
abstract public function IsTrue();
// recursively builds an array of [classAlias][fieldName] => value
abstract public function ListConstantFields();
public function RequiresField($sClass, $sFieldName)
{
// #@# todo - optimize : this is called quite often when building a single query !
@@ -72,12 +66,6 @@ abstract class Expression
return $oExpression;
}
static public function FromSQL($sSQL)
{
$oSql = new SQLExpression($sSQL);
return $oSql;
}
public function LogAnd($oExpr)
{
if ($this->IsTrue()) return clone $oExpr;
@@ -89,73 +77,8 @@ abstract class Expression
{
return new BinaryExpression($this, 'OR', $oExpr);
}
abstract public function RenameParam($sOldName, $sNewName);
/**
* Make the most relevant label, given the value of the expression
*
* @param DBObjectSearch oFilter The context in which this expression has been used
* @param string sValue The value returned by the query, for this expression
* @param string sDefault The default value if no relevant label could be computed
* @return The label
*/
public function MakeValueLabel($oFilter, $sValue, $sDefault)
{
return $sDefault;
}
}
class SQLExpression extends Expression
{
protected $m_sSQL;
public function __construct($sSQL)
{
$this->m_sSQL = $sSQL;
}
public function IsTrue()
{
return false;
}
// recursive rendering
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
return $this->m_sSQL;
}
public function ApplyParameters($aArgs)
{
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
return clone $this;
}
public function ListRequiredFields()
{
return array();
}
public function ListConstantFields()
{
return array();
}
public function RenameParam($sOldName, $sNewName)
{
// Do nothing, since there is nothing to rename
}
}
class BinaryExpression extends Expression
{
@@ -191,11 +114,11 @@ class BinaryExpression extends Expression
// return true if we are certain that it will be true
if ($this->m_sOperator == 'AND')
{
if ($this->m_oLeftExpr->IsTrue() && $this->m_oRightExpr->IsTrue()) return true;
if ($this->m_oLeftExpr->IsTrue() && $this->m_oLeftExpr->IsTrue()) return true;
}
return false;
}
public function GetLeftExpr()
{
return $this->m_oLeftExpr;
@@ -219,37 +142,11 @@ class BinaryExpression extends Expression
$sRight = $this->GetRightExpr()->Render($aArgs, $bRetrofitParams);
return "($sLeft $sOperator $sRight)";
}
public function ApplyParameters($aArgs)
{
if ($this->m_oLeftExpr instanceof VariableExpression)
{
$this->m_oLeftExpr = $this->m_oLeftExpr->GetAsScalar($aArgs);
}
else //if ($this->m_oLeftExpr instanceof Expression)
{
$this->m_oLeftExpr->ApplyParameters($aArgs);
}
if ($this->m_oRightExpr instanceof VariableExpression)
{
$this->m_oRightExpr = $this->m_oRightExpr->GetAsScalar($aArgs);
}
else //if ($this->m_oRightExpr instanceof Expression)
{
$this->m_oRightExpr->ApplyParameters($aArgs);
}
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
$this->GetLeftExpr()->GetUnresolvedFields($sAlias, $aUnresolved);
$this->GetRightExpr()->GetUnresolvedFields($sAlias, $aUnresolved);
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
public function Translate($aTranslationData, $bMatchAll = true)
{
$oLeft = $this->GetLeftExpr()->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
$oRight = $this->GetRightExpr()->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
$oLeft = $this->GetLeftExpr()->Translate($aTranslationData, $bMatchAll);
$oRight = $this->GetRightExpr()->Translate($aTranslationData, $bMatchAll);
return new BinaryExpression($oLeft, $this->GetOperator(), $oRight);
}
@@ -259,50 +156,6 @@ class BinaryExpression extends Expression
$aRight = $this->GetRightExpr()->ListRequiredFields();
return array_merge($aLeft, $aRight);
}
/**
* List all constant expression of the form <field> = <scalar> or <field> = :<variable>
* Could be extended to support <field> = <function><constant_expression>
*/
public function ListConstantFields()
{
$aResult = array();
if ($this->m_sOperator == '=')
{
if (($this->m_oLeftExpr instanceof FieldExpression) && ($this->m_oRightExpr instanceof ScalarExpression))
{
$aResult[$this->m_oLeftExpr->GetParent()][$this->m_oLeftExpr->GetName()] = $this->m_oRightExpr;
}
else if (($this->m_oRightExpr instanceof FieldExpression) && ($this->m_oLeftExpr instanceof ScalarExpression))
{
$aResult[$this->m_oRightExpr->GetParent()][$this->m_oRightExpr->GetName()] = $this->m_oLeftExpr;
}
else if (($this->m_oLeftExpr instanceof FieldExpression) && ($this->m_oRightExpr instanceof VariableExpression))
{
$aResult[$this->m_oLeftExpr->GetParent()][$this->m_oLeftExpr->GetName()] = $this->m_oRightExpr;
}
else if (($this->m_oRightExpr instanceof FieldExpression) && ($this->m_oLeftExpr instanceof VariableExpression))
{
$aResult[$this->m_oRightExpr->GetParent()][$this->m_oRightExpr->GetName()] = $this->m_oLeftExpr;
}
else
{
$aResult = array_merge($this->m_oRightExpr->ListConstantFields(), $this->m_oLeftExpr->ListConstantFields()) ;
}
}
else
{
$aResult = array_merge($this->m_oRightExpr->ListConstantFields(), $this->m_oLeftExpr->ListConstantFields()) ;
}
return $aResult;
}
public function RenameParam($sOldName, $sNewName)
{
$this->GetLeftExpr()->RenameParam($sOldName, $sNewName);
$this->GetRightExpr()->RenameParam($sOldName, $sNewName);
}
}
@@ -329,18 +182,19 @@ class UnaryExpression extends Expression
// recursive rendering
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
return CMDBSource::Quote($this->m_value);
if ($bRetrofitParams)
{
$iParamIndex = count($aArgs) + 1; // 1-based indexation
$aArgs['param'.$iParamIndex] = $this->m_value;
return ':param'.$iParamIndex;
}
else
{
return CMDBSource::Quote($this->m_value);
}
}
public function ApplyParameters($aArgs)
{
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
public function Translate($aTranslationData, $bMatchAll = true)
{
return clone $this;
}
@@ -349,43 +203,18 @@ class UnaryExpression extends Expression
{
return array();
}
public function ListConstantFields()
{
return array();
}
public function RenameParam($sOldName, $sNewName)
{
// Do nothing
// really ? what about :param{$iParamIndex} ??
}
}
class ScalarExpression extends UnaryExpression
{
public function __construct($value)
{
if (!is_scalar($value) && !is_null($value))
if (!is_scalar($value))
{
throw new CoreException('Attempt to create a scalar expression from a non scalar', array('var_type'=>gettype($value)));
}
parent::__construct($value);
}
// recursive rendering
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
if (is_null($this->m_value))
{
$sRet = 'NULL';
}
else
{
$sRet = CMDBSource::Quote($this->m_value);
}
return $sRet;
}
}
class TrueExpression extends ScalarExpression
@@ -446,27 +275,7 @@ class FieldExpression extends UnaryExpression
return "`{$this->m_sParent}`.`{$this->m_sName}`";
}
public function ListRequiredFields()
{
return array($this->m_sParent.'.'.$this->m_sName);
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
if ($this->m_sParent == $sAlias)
{
// Add a reference to the field
$aUnresolved[$this->m_sName] = $this;
}
elseif ($sAlias == '')
{
// An empty alias means "any alias"
// In such a case, the results are indexed differently
$aUnresolved[$this->m_sParent][$this->m_sName] = $this;
}
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
public function Translate($aTranslationData, $bMatchAll = true)
{
if (!array_key_exists($this->m_sParent, $aTranslationData))
{
@@ -483,81 +292,21 @@ class FieldExpression extends UnaryExpression
}
$sNewParent = $aTranslationData[$this->m_sParent]['*'];
$sNewName = $this->m_sName;
if ($bMarkFieldsAsResolved)
{
$oRet = new FieldExpressionResolved($sNewName, $sNewParent);
}
else
{
$oRet = new FieldExpression($sNewName, $sNewParent);
}
}
else
{
$oRet = $aTranslationData[$this->m_sParent][$this->m_sName];
$sNewParent = $aTranslationData[$this->m_sParent][$this->m_sName][0];
$sNewName = $aTranslationData[$this->m_sParent][$this->m_sName][1];
}
return $oRet;
return new FieldExpression($sNewName, $sNewParent);
}
/**
* Make the most relevant label, given the value of the expression
*
* @param DBObjectSearch oFilter The context in which this expression has been used
* @param string sValue The value returned by the query, for this expression
* @param string sDefault The default value if no relevant label could be computed
* @return The label
*/
public function MakeValueLabel($oFilter, $sValue, $sDefault)
public function ListRequiredFields()
{
$sAttCode = $this->GetName();
$sParentAlias = $this->GetParent();
$aSelectedClasses = $oFilter->GetSelectedClasses();
$sClass = $aSelectedClasses[$sParentAlias];
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
// Set a default value for the general case
$sRes = $oAttDef->GetAsHtml($sValue);
// Exceptions...
if ($oAttDef->IsExternalKey())
{
$sObjClass = $oAttDef->GetTargetClass();
$iObjKey = (int)$sValue;
if ($iObjKey > 0)
{
$oObject = MetaModel::GetObject($sObjClass, $iObjKey);
$sRes = $oObject->GetHyperlink();
}
else
{
// Undefined
$sRes = DBObject::MakeHyperLink($sObjClass, 0);
}
}
elseif ($oAttDef->IsExternalField())
{
if (is_null($sValue))
{
$sRes = Dict::S('UI:UndefinedObject');
}
}
return $sRes;
return array($this->m_sParent.'.'.$this->m_sName);
}
}
// Has been resolved into an SQL expression
class FieldExpressionResolved extends FieldExpression
{
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
return clone $this;
}
}
class VariableExpression extends UnaryExpression
{
@@ -591,7 +340,7 @@ class VariableExpression extends UnaryExpression
}
elseif ($bRetrofitParams)
{
$aArgs[$this->m_sName] = null;
//$aArgs[$this->m_sName] = null;
return ':'.$this->m_sName;
}
else
@@ -599,28 +348,6 @@ class VariableExpression extends UnaryExpression
throw new MissingQueryArgument('Missing query argument', array('expecting'=>$this->m_sName, 'available'=>$aArgs));
}
}
public function RenameParam($sOldName, $sNewName)
{
if ($this->m_sName == $sOldName)
{
$this->m_sName = $sNewName;
}
}
public function GetAsScalar($aArgs)
{
$value = '';
if (array_key_exists($this->m_sName, $aArgs))
{
$value = $aArgs[$this->m_sName];
}
else
{
throw new MissingQueryArgument('Missing query argument', array('expecting'=>$this->m_sName, 'available'=>array_keys($aArgs)));
}
return new ScalarExpression($value);
}
}
// Temporary, until we implement functions and expression casting!
@@ -666,36 +393,12 @@ class ListExpression extends Expression
return '('.implode(', ', $aRes).')';
}
public function ApplyParameters($aArgs)
{
$aRes = array();
foreach ($this->m_aExpressions as $idx => $oExpr)
{
if ($oExpr instanceof VariableExpression)
{
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
}
else
{
$oExpr->ApplyParameters($aArgs);
}
}
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
foreach ($this->m_aExpressions as $oExpr)
{
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
}
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
public function Translate($aTranslationData, $bMatchAll = true)
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
$aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll);
}
return new ListExpression($aRes);
}
@@ -709,25 +412,6 @@ class ListExpression extends Expression
}
return $aRes;
}
public function ListConstantFields()
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$aRes = array_merge($aRes, $oExpr->ListConstantFields());
}
return $aRes;
}
public function RenameParam($sOldName, $sNewName)
{
$aRes = array();
foreach ($this->m_aExpressions as $key => $oExpr)
{
$this->m_aExpressions[$key] = $oExpr->RenameParam($sOldName, $sNewName);
}
}
}
@@ -769,36 +453,12 @@ class FunctionExpression extends Expression
return $this->m_sVerb.'('.implode(', ', $aRes).')';
}
public function ApplyParameters($aArgs)
{
$aRes = array();
foreach ($this->m_aArgs as $idx => $oExpr)
{
if ($oExpr instanceof VariableExpression)
{
$this->m_aArgs[$idx] = $oExpr->GetAsScalar($aArgs);
}
else
{
$oExpr->ApplyParameters($aArgs);
}
}
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
foreach ($this->m_aArgs as $oExpr)
{
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
}
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
public function Translate($aTranslationData, $bMatchAll = true)
{
$aRes = array();
foreach ($this->m_aArgs as $oExpr)
{
$aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
$aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll);
}
return new FunctionExpression($this->m_sVerb, $aRes);
}
@@ -812,63 +472,6 @@ class FunctionExpression extends Expression
}
return $aRes;
}
public function ListConstantFields()
{
$aRes = array();
foreach ($this->m_aArgs as $oExpr)
{
$aRes = array_merge($aRes, $oExpr->ListConstantFields());
}
return $aRes;
}
public function RenameParam($sOldName, $sNewName)
{
foreach ($this->m_aArgs as $key => $oExpr)
{
$this->m_aArgs[$key] = $oExpr->RenameParam($sOldName, $sNewName);
}
}
/**
* Make the most relevant label, given the value of the expression
*
* @param DBObjectSearch oFilter The context in which this expression has been used
* @param string sValue The value returned by the query, for this expression
* @param string sDefault The default value if no relevant label could be computed
* @return The label
*/
public function MakeValueLabel($oFilter, $sValue, $sDefault)
{
$sRes = $sDefault;
if (strtolower($this->m_sVerb) == 'date_format')
{
$oFormatExpr = $this->m_aArgs[1];
if ($oFormatExpr->Render() == "'%w'")
{
static $aWeekDayToString = null;
if (is_null($aWeekDayToString))
{
// Init the correspondance table
$aWeekDayToString = array(
0 => Dict::S('DayOfWeek-Sunday'),
1 => Dict::S('DayOfWeek-Monday'),
2 => Dict::S('DayOfWeek-Tuesday'),
3 => Dict::S('DayOfWeek-Wednesday'),
4 => Dict::S('DayOfWeek-Thursday'),
5 => Dict::S('DayOfWeek-Friday'),
6 => Dict::S('DayOfWeek-Saturday')
);
}
if (isset($aWeekDayToString[(int)$sValue]))
{
$sRes = $aWeekDayToString[(int)$sValue];
}
}
}
return $sRes;
}
}
class IntervalExpression extends Expression
@@ -904,42 +507,15 @@ class IntervalExpression extends Expression
return 'INTERVAL '.$this->m_oValue->Render($aArgs, $bRetrofitParams).' '.$this->m_sUnit;
}
public function ApplyParameters($aArgs)
public function Translate($aTranslationData, $bMatchAll = true)
{
if ($this->m_oValue instanceof VariableExpression)
{
$this->m_oValue = $this->m_oValue->GetAsScalar($aArgs);
}
else
{
$this->m_oValue->ApplyParameters($aArgs);
}
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
$this->m_oValue->GetUnresolvedFields($sAlias, $aUnresolved);
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
return new IntervalExpression($this->m_oValue->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved), $this->m_sUnit);
return new IntervalExpression($this->m_oValue->Translate($aTranslationData, $bMatchAll), $this->m_sUnit);
}
public function ListRequiredFields()
{
return array();
}
public function ListConstantFields()
{
return array();
}
public function RenameParam($sOldName, $sNewName)
{
$this->m_oValue->RenameParam($sOldName, $sNewName);
}
}
class CharConcatExpression extends Expression
@@ -975,36 +551,12 @@ class CharConcatExpression extends Expression
return "CAST(CONCAT(".implode(', ', $aRes).") AS CHAR)";
}
public function ApplyParameters($aArgs)
{
$aRes = array();
foreach ($this->m_aExpressions as $idx => $oExpr)
{
if ($oExpr instanceof VariableExpression)
{
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
}
else
{
$this->m_aExpressions->ApplyParameters($aArgs);
}
}
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
foreach ($this->m_aExpressions as $oExpr)
{
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
}
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
public function Translate($aTranslationData, $bMatchAll = true)
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
$aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll);
}
return new CharConcatExpression($aRes);
}
@@ -1018,163 +570,6 @@ class CharConcatExpression extends Expression
}
return $aRes;
}
public function ListConstantFields()
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$aRes = array_merge($aRes, $oExpr->ListConstantFields());
}
return $aRes;
}
public function RenameParam($sOldName, $sNewName)
{
foreach ($this->m_aExpressions as $key => $oExpr)
{
$this->m_aExpressions[$key] = $oExpr->RenameParam($sOldName, $sNewName);
}
}
}
class CharConcatWSExpression extends CharConcatExpression
{
protected $m_separator;
public function __construct($separator, $aExpressions)
{
$this->m_separator = $separator;
parent::__construct($aExpressions);
}
// recursive rendering
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$sCol = $oExpr->Render($aArgs, $bRetrofitParams);
// Concat will be globally NULL if one single argument is null !
$aRes[] = "COALESCE($sCol, '')";
}
$sSep = CMDBSource::Quote($this->m_separator);
return "CAST(CONCAT_WS($sSep, ".implode(', ', $aRes).") AS CHAR)";
}
}
class QueryBuilderExpressions
{
protected $m_oConditionExpr;
protected $m_aSelectExpr;
protected $m_aGroupByExpr;
protected $m_aJoinFields;
public function __construct($oCondition, $aGroupByExpr = null)
{
$this->m_oConditionExpr = $oCondition;
$this->m_aSelectExpr = array();
$this->m_aGroupByExpr = $aGroupByExpr;
$this->m_aJoinFields = array();
}
public function GetSelect()
{
return $this->m_aSelectExpr;
}
public function GetGroupBy()
{
return $this->m_aGroupByExpr;
}
public function GetCondition()
{
return $this->m_oConditionExpr;
}
public function PopJoinField()
{
return array_pop($this->m_aJoinFields);
}
public function AddSelect($sAttAlias, $oExpression)
{
$this->m_aSelectExpr[$sAttAlias] = $oExpression;
}
//$oConditionTree = $oConditionTree->LogAnd($oFinalClassRestriction);
public function AddCondition($oExpression)
{
$this->m_oConditionExpr = $this->m_oConditionExpr->LogAnd($oExpression);
}
public function PushJoinField($oExpression)
{
array_push($this->m_aJoinFields, $oExpression);
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
$this->m_oConditionExpr->GetUnresolvedFields($sAlias, $aUnresolved);
foreach($this->m_aSelectExpr as $sColAlias => $oExpr)
{
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
}
if ($this->m_aGroupByExpr)
{
foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
{
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
}
}
foreach($this->m_aJoinFields as $oExpression)
{
$oExpression->GetUnresolvedFields($sAlias, $aUnresolved);
}
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
$this->m_oConditionExpr = $this->m_oConditionExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
foreach($this->m_aSelectExpr as $sColAlias => $oExpr)
{
$this->m_aSelectExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
}
if ($this->m_aGroupByExpr)
{
foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
{
$this->m_aGroupByExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
}
}
foreach($this->m_aJoinFields as $index => $oExpression)
{
$this->m_aJoinFields[$index] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
}
}
public function RenameParam($sOldName, $sNewName)
{
$this->m_oConditionExpr->RenameParam($sOldName, $sNewName);
foreach($this->m_aSelectExpr as $sColAlias => $oExpr)
{
$this->m_aSelectExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName);
}
if ($this->m_aGroupByExpr)
{
foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
{
$this->m_aGroupByExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName);
}
}
foreach($this->m_aJoinFields as $index => $oExpression)
{
$this->m_aJoinFields[$index] = $oExpression->RenameParam($sOldName, $sNewName);
}
}
}
?>

View File

@@ -50,6 +50,21 @@ abstract class FilterDefinition
$this->ConsistencyCheck();
}
public function OverloadParams($aParams)
{
foreach ($aParams as $sParam => $value)
{
if (!array_key_exists($sParam, $this->m_aParams))
{
throw new CoreException("Unknown attribute definition parameter '$sParam', please select a value in {".implode(", ", $this->m_aParams)."}");
}
else
{
$this->m_aParams[$sParam] = $value;
}
}
}
// to be overloaded
static protected function ListExpectedParams()
{
@@ -155,13 +170,12 @@ class FilterFromAttribute extends FilterDefinition
return array_merge(parent::ListExpectedParams(), array("refattribute"));
}
public function __construct($oRefAttribute, $sSuffix = '')
public function __construct($oRefAttribute, $aParam = array())
{
// In this very specific case, the code is the one of the attribute
// (this to get a very very simple syntax upon declaration)
$aParam = array();
$aParam["refattribute"] = $oRefAttribute;
parent::__construct($oRefAttribute->GetCode().$sSuffix, $aParam);
parent::__construct($oRefAttribute->GetCode(), $aParam);
}
public function GetType() {return "Basic";}

View File

@@ -191,25 +191,6 @@ class ExecutionKPI
return $output[1] * 1024;
}
}
static public function memory_get_peak_usage($bRealUsage = false)
{
if (function_exists('memory_get_peak_usage'))
{
return memory_get_peak_usage($bRealUsage);
}
// PHP > 5.2.1 - this verb depends on a compilation option
return 0;
}
}
class ApplicationStartupKPI extends ExecutionKPI
{
public function __construct()
{
global $fItopStarted;
$this->m_fStarted = $fItopStarted;
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Any extension to hook the initialization of the metamodel
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
interface iOnClassInitialization
{
public function OnAfterClassInitialization($sClass);
}
?>

View File

@@ -1,4 +0,0 @@
#!/bin/bash
php /usr/share/php/PHP/LexerGenerator/cli.php oql-lexer.plex
php /usr/share/php/PHP/ParserGenerator/cli.php oql-parser.y

View File

@@ -3,6 +3,5 @@
# since they are used solely for constructing other files during the build process
#
build.cmd
build.bash
oql-lexer.plex
oql-parser.y
oql-parser.y

View File

@@ -1,29 +1,5 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* OQL syntax analyzer, to be used prior to run the lexical analyzer
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
// Notes (from the source file: oql-lexer.plex) - Romain
//
// The strval rule is a little bit cryptic.
@@ -104,163 +80,153 @@ class OQLLexerRaw
if ($this->count >= strlen($this->data)) {
return false; // end of input
}
do {
$rules = array(
'/\G[ \t\n\r]+/ ',
'/\GSELECT/ ',
'/\GFROM/ ',
'/\GAS/ ',
'/\GWHERE/ ',
'/\GJOIN/ ',
'/\GON/ ',
'/\G\// ',
'/\G\\*/ ',
'/\G\\+/ ',
'/\G-/ ',
'/\GAND/ ',
'/\GOR/ ',
'/\G,/ ',
'/\G\\(/ ',
'/\G\\)/ ',
'/\GREGEXP/ ',
'/\G=/ ',
'/\G!=/ ',
'/\G>/ ',
'/\G</ ',
'/\G>=/ ',
'/\G<=/ ',
'/\GLIKE/ ',
'/\GNOT LIKE/ ',
'/\GIN/ ',
'/\GNOT IN/ ',
'/\GINTERVAL/ ',
'/\GIF/ ',
'/\GELT/ ',
'/\GCOALESCE/ ',
'/\GISNULL/ ',
'/\GCONCAT/ ',
'/\GSUBSTR/ ',
'/\GTRIM/ ',
'/\GDATE/ ',
'/\GDATE_FORMAT/ ',
'/\GCURRENT_DATE/ ',
'/\GNOW/ ',
'/\GTIME/ ',
'/\GTO_DAYS/ ',
'/\GFROM_DAYS/ ',
'/\GYEAR/ ',
'/\GMONTH/ ',
'/\GDAY/ ',
'/\GHOUR/ ',
'/\GMINUTE/ ',
'/\GSECOND/ ',
'/\GDATE_ADD/ ',
'/\GDATE_SUB/ ',
'/\GROUND/ ',
'/\GFLOOR/ ',
'/\GINET_ATON/ ',
'/\GINET_NTOA/ ',
'/\GBELOW/ ',
'/\GBELOW STRICT/ ',
'/\GNOT BELOW/ ',
'/\GNOT BELOW STRICT/ ',
'/\GABOVE/ ',
'/\GABOVE STRICT/ ',
'/\GNOT ABOVE/ ',
'/\GNOT ABOVE STRICT/ ',
'/\G(0x[0-9a-fA-F]+|[0-9]+)/ ',
'/\G\"([^\\\\\"]|\\\\\"|\\\\\\\\)*\"|'.chr(94).chr(39).'([^\\\\'.chr(39).']|\\\\'.chr(39).'|\\\\\\\\)*'.chr(39).'/ ',
'/\G([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/ ',
'/\G:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/ ',
'/\G\\./ ',
);
$match = false;
foreach ($rules as $index => $rule) {
if (preg_match($rule, substr($this->data, $this->count), $yymatches)) {
if ($match) {
if (strlen($yymatches[0]) > strlen($match[0][0])) {
$match = array($yymatches, $index); // matches, token
}
} else {
$match = array($yymatches, $index);
}
}
}
if (!$match) {
throw new Exception('Unexpected input at line ' . $this->line .
': ' . $this->data[$this->count]);
}
$this->token = $match[1];
$this->value = $match[0][0];
$yysubmatches = $match[0];
array_shift($yysubmatches);
if (!$yysubmatches) {
$yysubmatches = array();
}
$r = $this->{'yy_r1_' . $this->token}($yysubmatches);
if ($r === null) {
$this->count += strlen($this->value);
$this->line += substr_count($this->value, "\n");
// accept this token
return true;
} elseif ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} elseif ($r === false) {
$this->count += strlen($this->value);
$this->line += substr_count($this->value, "\n");
if ($this->count >= strlen($this->data)) {
return false; // end of input
}
// skip this token
continue;
} else {
$yy_yymore_patterns = array_slice($rules, $this->token, true);
// yymore is needed
do {
if (!isset($yy_yymore_patterns[$this->token])) {
throw new Exception('cannot do yymore for the last token');
}
$match = false;
foreach ($yy_yymore_patterns[$this->token] as $index => $rule) {
if (preg_match('/' . $rule . '/',
$this->data, $yymatches, null, $this->count)) {
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
if ($match) {
if (strlen($yymatches[0]) > strlen($match[0][0])) {
$match = array($yymatches, $index); // matches, token
}
} else {
$match = array($yymatches, $index);
}
}
}
if (!$match) {
throw new Exception('Unexpected input at line ' . $this->line .
': ' . $this->data[$this->count]);
}
$this->token = $match[1];
$this->value = $match[0][0];
$yysubmatches = $match[0];
array_shift($yysubmatches);
if (!$yysubmatches) {
$yysubmatches = array();
}
$this->line = substr_count($this->value, "\n");
$r = $this->{'yy_r1_' . $this->token}();
} while ($r !== null || !$r);
if ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} else {
// accept
$this->count += strlen($this->value);
$this->line += substr_count($this->value, "\n");
return true;
}
}
do {
$rules = array(
'/^[ \t\n\r]+/',
'/^SELECT/',
'/^FROM/',
'/^AS/',
'/^WHERE/',
'/^JOIN/',
'/^ON/',
'/^\//',
'/^\\*/',
'/^\\+/',
'/^-/',
'/^AND/',
'/^OR/',
'/^,/',
'/^\\(/',
'/^\\)/',
'/^=/',
'/^!=/',
'/^>/',
'/^</',
'/^>=/',
'/^<=/',
'/^LIKE/',
'/^NOT LIKE/',
'/^IN/',
'/^NOT IN/',
'/^INTERVAL/',
'/^IF/',
'/^ELT/',
'/^COALESCE/',
'/^CONCAT/',
'/^SUBSTR/',
'/^TRIM/',
'/^DATE/',
'/^DATE_FORMAT/',
'/^CURRENT_DATE/',
'/^NOW/',
'/^TIME/',
'/^TO_DAYS/',
'/^FROM_DAYS/',
'/^YEAR/',
'/^MONTH/',
'/^DAY/',
'/^HOUR/',
'/^MINUTE/',
'/^SECOND/',
'/^DATE_ADD/',
'/^DATE_SUB/',
'/^ROUND/',
'/^FLOOR/',
'/^INET_ATON/',
'/^INET_NTOA/',
'/^[0-9]+|0x[0-9a-fA-F]+/',
'/^\"([^\\\\\"]|\\\\\"|\\\\\\\\)*\"|'.chr(94).chr(39).'([^\\\\'.chr(39).']|\\\\'.chr(39).'|\\\\\\\\)*'.chr(39).'/',
'/^([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/',
'/^:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/',
'/^\\./',
);
$match = false;
foreach ($rules as $index => $rule) {
if (preg_match($rule, substr($this->data, $this->count), $yymatches)) {
if ($match) {
if (strlen($yymatches[0]) > strlen($match[0][0])) {
$match = array($yymatches, $index); // matches, token
}
} else {
$match = array($yymatches, $index);
}
}
}
if (!$match) {
throw new Exception('Unexpected input at line' . $this->line .
': ' . $this->data[$this->count]);
}
$this->token = $match[1];
$this->value = $match[0][0];
$yysubmatches = $match[0];
array_shift($yysubmatches);
if (!$yysubmatches) {
$yysubmatches = array();
}
$r = $this->{'yy_r1_' . $this->token}($yysubmatches);
if ($r === null) {
$this->count += strlen($this->value);
$this->line += substr_count($this->value, "\n");
// accept this token
return true;
} elseif ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} elseif ($r === false) {
$this->count += strlen($this->value);
$this->line += substr_count($this->value, "\n");
if ($this->count >= strlen($this->data)) {
return false; // end of input
}
// skip this token
continue;
} else {
$yy_yymore_patterns = array_slice($rules, $this->token, true);
// yymore is needed
do {
if (!isset($yy_yymore_patterns[$this->token])) {
throw new Exception('cannot do yymore for the last token');
}
$match = false;
foreach ($yy_yymore_patterns[$this->token] as $index => $rule) {
if (preg_match('/' . $rule . '/',
substr($this->data, $this->count), $yymatches)) {
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
if ($match) {
if (strlen($yymatches[0]) > strlen($match[0][0])) {
$match = array($yymatches, $index); // matches, token
}
} else {
$match = array($yymatches, $index);
}
}
}
if (!$match) {
throw new Exception('Unexpected input at line' . $this->line .
': ' . $this->data[$this->count]);
}
$this->token = $match[1];
$this->value = $match[0][0];
$yysubmatches = $match[0];
array_shift($yysubmatches);
if (!$yysubmatches) {
$yysubmatches = array();
}
$this->line = substr_count($this->value, "\n");
$r = $this->{'yy_r1_' . $this->token}();
} while ($r !== null || !$r);
if ($r === true) {
// we have changed state
// process this token in the new state
return $this->yylex();
} else {
// accept
$this->count += strlen($this->value);
$this->line += substr_count($this->value, "\n");
return true;
}
}
} while (true);
} // end function
@@ -348,254 +314,204 @@ class OQLLexerRaw
function yy_r1_16($yy_subpatterns)
{
$this->token = OQLParser::REGEXP;
$this->token = OQLParser::EQ;
}
function yy_r1_17($yy_subpatterns)
{
$this->token = OQLParser::EQ;
$this->token = OQLParser::NOT_EQ;
}
function yy_r1_18($yy_subpatterns)
{
$this->token = OQLParser::NOT_EQ;
$this->token = OQLParser::GT;
}
function yy_r1_19($yy_subpatterns)
{
$this->token = OQLParser::GT;
$this->token = OQLParser::LT;
}
function yy_r1_20($yy_subpatterns)
{
$this->token = OQLParser::LT;
$this->token = OQLParser::GE;
}
function yy_r1_21($yy_subpatterns)
{
$this->token = OQLParser::GE;
$this->token = OQLParser::LE;
}
function yy_r1_22($yy_subpatterns)
{
$this->token = OQLParser::LE;
$this->token = OQLParser::LIKE;
}
function yy_r1_23($yy_subpatterns)
{
$this->token = OQLParser::LIKE;
$this->token = OQLParser::NOT_LIKE;
}
function yy_r1_24($yy_subpatterns)
{
$this->token = OQLParser::NOT_LIKE;
$this->token = OQLParser::IN;
}
function yy_r1_25($yy_subpatterns)
{
$this->token = OQLParser::IN;
$this->token = OQLParser::NOT_IN;
}
function yy_r1_26($yy_subpatterns)
{
$this->token = OQLParser::NOT_IN;
$this->token = OQLParser::INTERVAL;
}
function yy_r1_27($yy_subpatterns)
{
$this->token = OQLParser::INTERVAL;
$this->token = OQLParser::F_IF;
}
function yy_r1_28($yy_subpatterns)
{
$this->token = OQLParser::F_IF;
$this->token = OQLParser::F_ELT;
}
function yy_r1_29($yy_subpatterns)
{
$this->token = OQLParser::F_ELT;
$this->token = OQLParser::F_COALESCE;
}
function yy_r1_30($yy_subpatterns)
{
$this->token = OQLParser::F_COALESCE;
$this->token = OQLParser::F_CONCAT;
}
function yy_r1_31($yy_subpatterns)
{
$this->token = OQLParser::F_ISNULL;
$this->token = OQLParser::F_SUBSTR;
}
function yy_r1_32($yy_subpatterns)
{
$this->token = OQLParser::F_CONCAT;
$this->token = OQLParser::F_TRIM;
}
function yy_r1_33($yy_subpatterns)
{
$this->token = OQLParser::F_SUBSTR;
$this->token = OQLParser::F_DATE;
}
function yy_r1_34($yy_subpatterns)
{
$this->token = OQLParser::F_TRIM;
$this->token = OQLParser::F_DATE_FORMAT;
}
function yy_r1_35($yy_subpatterns)
{
$this->token = OQLParser::F_DATE;
$this->token = OQLParser::F_CURRENT_DATE;
}
function yy_r1_36($yy_subpatterns)
{
$this->token = OQLParser::F_DATE_FORMAT;
$this->token = OQLParser::F_NOW;
}
function yy_r1_37($yy_subpatterns)
{
$this->token = OQLParser::F_CURRENT_DATE;
$this->token = OQLParser::F_TIME;
}
function yy_r1_38($yy_subpatterns)
{
$this->token = OQLParser::F_NOW;
$this->token = OQLParser::F_TO_DAYS;
}
function yy_r1_39($yy_subpatterns)
{
$this->token = OQLParser::F_TIME;
$this->token = OQLParser::F_FROM_DAYS;
}
function yy_r1_40($yy_subpatterns)
{
$this->token = OQLParser::F_TO_DAYS;
$this->token = OQLParser::F_YEAR;
}
function yy_r1_41($yy_subpatterns)
{
$this->token = OQLParser::F_FROM_DAYS;
$this->token = OQLParser::F_MONTH;
}
function yy_r1_42($yy_subpatterns)
{
$this->token = OQLParser::F_YEAR;
$this->token = OQLParser::F_DAY;
}
function yy_r1_43($yy_subpatterns)
{
$this->token = OQLParser::F_MONTH;
$this->token = OQLParser::F_HOUR;
}
function yy_r1_44($yy_subpatterns)
{
$this->token = OQLParser::F_DAY;
$this->token = OQLParser::F_MINUTE;
}
function yy_r1_45($yy_subpatterns)
{
$this->token = OQLParser::F_HOUR;
$this->token = OQLParser::F_SECOND;
}
function yy_r1_46($yy_subpatterns)
{
$this->token = OQLParser::F_MINUTE;
$this->token = OQLParser::F_DATE_ADD;
}
function yy_r1_47($yy_subpatterns)
{
$this->token = OQLParser::F_SECOND;
$this->token = OQLParser::F_DATE_SUB;
}
function yy_r1_48($yy_subpatterns)
{
$this->token = OQLParser::F_DATE_ADD;
$this->token = OQLParser::F_ROUND;
}
function yy_r1_49($yy_subpatterns)
{
$this->token = OQLParser::F_DATE_SUB;
$this->token = OQLParser::F_FLOOR;
}
function yy_r1_50($yy_subpatterns)
{
$this->token = OQLParser::F_ROUND;
$this->token = OQLParser::F_INET_ATON;
}
function yy_r1_51($yy_subpatterns)
{
$this->token = OQLParser::F_FLOOR;
$this->token = OQLParser::F_INET_NTOA;
}
function yy_r1_52($yy_subpatterns)
{
$this->token = OQLParser::F_INET_ATON;
$this->token = OQLParser::NUMVAL;
}
function yy_r1_53($yy_subpatterns)
{
$this->token = OQLParser::F_INET_NTOA;
$this->token = OQLParser::STRVAL;
}
function yy_r1_54($yy_subpatterns)
{
$this->token = OQLParser::BELOW;
$this->token = OQLParser::NAME;
}
function yy_r1_55($yy_subpatterns)
{
$this->token = OQLParser::BELOW_STRICT;
}
function yy_r1_56($yy_subpatterns)
{
$this->token = OQLParser::NOT_BELOW;
}
function yy_r1_57($yy_subpatterns)
{
$this->token = OQLParser::NOT_BELOW_STRICT;
}
function yy_r1_58($yy_subpatterns)
{
$this->token = OQLParser::ABOVE;
}
function yy_r1_59($yy_subpatterns)
{
$this->token = OQLParser::ABOVE_STRICT;
}
function yy_r1_60($yy_subpatterns)
{
$this->token = OQLParser::NOT_ABOVE;
}
function yy_r1_61($yy_subpatterns)
{
$this->token = OQLParser::NOT_ABOVE_STRICT;
}
function yy_r1_62($yy_subpatterns)
{
$this->token = OQLParser::NUMVAL;
}
function yy_r1_63($yy_subpatterns)
{
$this->token = OQLParser::STRVAL;
}
function yy_r1_64($yy_subpatterns)
{
$this->token = OQLParser::NAME;
}
function yy_r1_65($yy_subpatterns)
{
$this->token = OQLParser::VARNAME;
}
function yy_r1_66($yy_subpatterns)
function yy_r1_56($yy_subpatterns)
{
$this->token = OQLParser::DOT;

View File

@@ -94,7 +94,6 @@ math_plus = "+"
math_minus = "-"
log_and = "AND"
log_or = "OR"
regexp = "REGEXP"
eq = "="
not_eq = "!="
gt = ">"
@@ -109,7 +108,6 @@ interval = "INTERVAL"
f_if = "IF"
f_elt = "ELT"
f_coalesce = "COALESCE"
f_isnull = "ISNULL"
f_concat = "CONCAT"
f_substr = "SUBSTR"
f_trim = "TRIM"
@@ -132,31 +130,7 @@ f_round = "ROUND"
f_floor = "FLOOR"
f_inet_aton = "INET_ATON"
f_inet_ntoa = "INET_NTOA"
below = "BELOW"
below_strict = "BELOW STRICT"
not_below = "NOT BELOW"
not_below_strict = "NOT BELOW STRICT"
above = "ABOVE"
above_strict = "ABOVE STRICT"
not_above = "NOT ABOVE"
not_above_strict = "NOT ABOVE STRICT"
//
// WARNING: there seems to be a bug in the Lexer about matching the longest pattern
// when there are alternates in the regexp.
//
// For instance:
// numval = /[0-9]+|0x[0-9a-fA-F]+/
// Does not work: SELECT Toto WHERE name = 'Text0xCTest' => Fails because 0xC is recongnized as a numval (inside the string) instead of a strval !!
//
// Inserting a ^ after the alternate (see comment at the top of this file) does not work either
// numval = /[0-9]+|'.chr(94).'0x[0-9a-fA-F]+/
// SELECT Toto WHERE name = 'Text0xCTest' => works but
// SELECT Toto WHERE id = 0xC => does not work, 'xC' is found as a name (apparently 0 is recognized as a numval and the remaining is a name !)
//
// numval = /([0-9]+|0x[0-9a-fA-F]+)/
// Does not work either, the hexadecimal numbers are not matched properly
// The following seems to work...
numval = /(0x[0-9a-fA-F]+|[0-9]+)/
numval = /[0-9]+|0x[0-9a-fA-F]+/
strval = /"([^\\"]|\\"|\\\\)*"|'.chr(94).chr(39).'([^\\'.chr(39).']|\\'.chr(39).'|\\\\)*'.chr(39).'/
name = /([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/
varname = /:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/
@@ -212,9 +186,6 @@ par_open {
par_close {
$this->token = OQLParser::PAR_CLOSE;
}
regexp {
$this->token = OQLParser::REGEXP;
}
eq {
$this->token = OQLParser::EQ;
}
@@ -257,9 +228,6 @@ f_elt {
f_coalesce {
$this->token = OQLParser::F_COALESCE;
}
f_isnull {
$this->token = OQLParser::F_ISNULL;
}
f_concat {
$this->token = OQLParser::F_CONCAT;
}
@@ -326,30 +294,6 @@ f_inet_aton {
f_inet_ntoa {
$this->token = OQLParser::F_INET_NTOA;
}
below {
$this->token = OQLParser::BELOW;
}
below_strict {
$this->token = OQLParser::BELOW_STRICT;
}
not_below {
$this->token = OQLParser::NOT_BELOW;
}
not_below_strict {
$this->token = OQLParser::NOT_BELOW_STRICT;
}
above {
$this->token = OQLParser::ABOVE;
}
above_strict {
$this->token = OQLParser::ABOVE_STRICT;
}
not_above {
$this->token = OQLParser::NOT_ABOVE;
}
not_above_strict {
$this->token = OQLParser::NOT_ABOVE_STRICT;
}
numval {
$this->token = OQLParser::NUMVAL;
}

File diff suppressed because it is too large Load Diff

View File

@@ -78,14 +78,6 @@ join_item(A) ::= JOIN class_name(X) ON join_condition(C).
}
join_condition(A) ::= field_id(X) EQ field_id(Y). { A = new BinaryOqlExpression(X, '=', Y); }
join_condition(A) ::= field_id(X) BELOW field_id(Y). { A = new BinaryOqlExpression(X, 'BELOW', Y); }
join_condition(A) ::= field_id(X) BELOW_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'BELOW_STRICT', Y); }
join_condition(A) ::= field_id(X) NOT_BELOW field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_BELOW', Y); }
join_condition(A) ::= field_id(X) NOT_BELOW_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_BELOW_STRICT', Y); }
join_condition(A) ::= field_id(X) ABOVE field_id(Y). { A = new BinaryOqlExpression(X, 'ABOVE', Y); }
join_condition(A) ::= field_id(X) ABOVE_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'ABOVE_STRICT', Y); }
join_condition(A) ::= field_id(X) NOT_ABOVE field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_ABOVE', Y); }
join_condition(A) ::= field_id(X) NOT_ABOVE_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_ABOVE_STRICT', Y); }
condition(A) ::= expression_prio4(X). { A = X; }
@@ -109,13 +101,13 @@ expression_prio4(A) ::= expression_prio3(X). { A = X; }
expression_prio4(A) ::= expression_prio4(X) operator4(Y) expression_prio3(Z). { A = new BinaryOqlExpression(X, Y, Z); }
list(A) ::= PAR_OPEN list_items(X) PAR_CLOSE. {
list(A) ::= PAR_OPEN scalar_list(X) PAR_CLOSE. {
A = new ListOqlExpression(X);
}
list_items(A) ::= expression_prio4(X). {
scalar_list(A) ::= scalar(X). {
A = array(X);
}
list_items(A) ::= list_items(L) COMA expression_prio4(X). {
scalar_list(A) ::= scalar_list(L) COMA scalar(X). {
array_push(L, X);
A = L;
}
@@ -172,7 +164,6 @@ str_value(A) ::= STRVAL(X). {A=stripslashes(substr(X, 1, strlen(X) - 2));}
operator1(A) ::= num_operator1(X). {A=X;}
operator2(A) ::= num_operator2(X). {A=X;}
operator2(A) ::= str_operator(X). {A=X;}
operator2(A) ::= REGEXP(X). {A=X;}
operator2(A) ::= EQ(X). {A=X;}
operator2(A) ::= NOT_EQ(X). {A=X;}
operator3(A) ::= LOG_AND(X). {A=X;}
@@ -196,7 +187,6 @@ list_operator(A) ::= NOT_IN(X). {A=X;}
func_name(A) ::= F_IF(X). { A=X; }
func_name(A) ::= F_ELT(X). { A=X; }
func_name(A) ::= F_COALESCE(X). { A=X; }
func_name(A) ::= F_ISNULL(X). { A=X; }
func_name(A) ::= F_CONCAT(X). { A=X; }
func_name(A) ::= F_SUBSTR(X). { A=X; }
func_name(A) ::= F_TRIM(X). { A=X; }

View File

@@ -50,54 +50,28 @@ class OQLException extends CoreException
parent::__construct($sMessage, 0);
}
public function GetUserFriendlyDescription()
public function getHtmlDesc($sHighlightHtmlBegin = '<b>', $sHighlightHtmlEnd = '</b>')
{
// Todo - translate all errors!
return $this->getMessage();
}
public function getHtmlDesc($sHighlightHtmlBegin = '<span style="font-weight: bolder">', $sHighlightHtmlEnd = '</span>')
{
$sRet = htmlentities($this->m_MyIssue.", found '".$this->m_sUnexpected."' in: ", ENT_QUOTES, 'UTF-8');
$sRet .= htmlentities(substr($this->m_sInput, 0, $this->m_iCol), ENT_QUOTES, 'UTF-8');
$sRet .= $sHighlightHtmlBegin.htmlentities(substr($this->m_sInput, $this->m_iCol, strlen($this->m_sUnexpected)), ENT_QUOTES, 'UTF-8').$sHighlightHtmlEnd;
$sRet .= htmlentities(substr($this->m_sInput, $this->m_iCol + strlen($this->m_sUnexpected)), ENT_QUOTES, 'UTF-8');
$sRet = htmlentities($this->m_MyIssue.", found '".$this->m_sUnexpected."' in: ");
$sRet .= htmlentities(substr($this->m_sInput, 0, $this->m_iCol));
$sRet .= $sHighlightHtmlBegin.htmlentities(substr($this->m_sInput, $this->m_iCol, strlen($this->m_sUnexpected))).$sHighlightHtmlEnd;
$sRet .= htmlentities(substr($this->m_sInput, $this->m_iCol + strlen($this->m_sUnexpected)));
if (!is_null($this->m_aExpecting) && (count($this->m_aExpecting) > 0))
{
$sExpectations = '{'.implode(', ', $this->m_aExpecting).'}';
$sRet .= ", expecting ".htmlentities($sExpectations, ENT_QUOTES, 'UTF-8');
$sRet .= ", expecting ".htmlentities($sExpectations);
$sSuggest = self::FindClosestString($this->m_sUnexpected, $this->m_aExpecting);
if (strlen($sSuggest) > 0)
{
$sRet .= ", I would suggest to use '$sHighlightHtmlBegin".htmlentities($sSuggest, ENT_QUOTES, 'UTF-8')."$sHighlightHtmlEnd'";
$sRet .= ", I would suggest to use '$sHighlightHtmlBegin".htmlentities($sSuggest)."$sHighlightHtmlEnd'";
}
}
return $sRet;
}
public function GetIssue()
{
return $this->m_MyIssue;
}
public function GetSuggestions()
{
return $this->m_aExpecting;
}
public function GetWrongWord()
{
return $this->m_sUnexpected;
}
public function GetColumn()
{
return $this->m_iCol;
}
static public function FindClosestString($sInput, $aDictionary)
static protected function FindClosestString($sInput, $aDictionary)
{
// no shortest distance found, yet
$fShortest = -1;
@@ -114,7 +88,7 @@ class OQLException extends CoreException
return $sSuggestion;
}
if (($fDist <= 3) && ($fShortest < 0 || $fDist <= $fShortest))
if ($fShortest < 0 || ($fDist < 4 && $fDist <= $fShortest))
{
// set the closest match, and shortest distance
$sRet = $sSuggestion;

View File

@@ -31,28 +31,6 @@ class OqlNormalizeException extends OQLException
parent::__construct($sIssue, $sInput, 0, $oName->GetPos(), $oName->GetValue(), $aExpecting);
}
}
class UnknownClassOqlException extends OqlNormalizeException
{
public function __construct($sInput, OqlName $oName, $aExpecting = null)
{
parent::__construct('Unknown class', $sInput, $oName, $aExpecting);
}
public function GetUserFriendlyDescription()
{
$sWrongClass = $this->GetWrongWord();
$sSuggest = self::FindClosestString($sWrongClass, $this->GetSuggestions());
if ($sSuggest != '')
{
return Dict::Format('UI:OQL:UnknownClassAndFix', $sWrongClass, $sSuggest);
}
else
{
return Dict::Format('UI:OQL:UnknownClassNoFix', $sWrongClass);
}
}
}
class OqlInterpreterException extends OQLException
{

View File

@@ -59,7 +59,6 @@ class OqlJoinSpec
protected $m_oClassAlias;
protected $m_oLeftField;
protected $m_oRightField;
protected $m_sOperator;
protected $m_oNextJoinspec;
@@ -69,8 +68,6 @@ class OqlJoinSpec
$this->m_oClassAlias = $oClassAlias;
$this->m_oLeftField = $oExpression->GetLeftExpr();
$this->m_oRightField = $oExpression->GetRightExpr();
$this->m_oRightField = $oExpression->GetRightExpr();
$this->m_sOperator = $oExpression->GetOperator();
}
public function GetClass()
@@ -99,10 +96,6 @@ class OqlJoinSpec
{
return $this->m_oRightField;
}
public function GetOperator()
{
return $this->m_sOperator;
}
}
class BinaryOqlExpression extends BinaryExpression

View File

@@ -1,263 +0,0 @@
<?php
// Copyright (C) 2011-2012 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
define('CASELOG_VISIBLE_ITEMS', 2);
define('CASELOG_SEPARATOR', "\n".'========== %1$s : %2$s (%3$d) ============'."\n\n");
//require_once(APPROOT.'/core/userrights.class.inc.php');
//require_once(APPROOT.'/application/webpage.class.inc.php');
/**
* Class to store a "case log" in a structured way, keeping track of its successive entries
*/
class ormCaseLog {
protected $m_sLog;
protected $m_aIndex;
protected $m_bModified;
/**
* Initializes the log with the first (initial) entry
* @param $sLog string The text of the whole case log
* @param $aIndex hash The case log index
*/
public function __construct($sLog = '', $aIndex = array())
{
$this->m_sLog = $sLog;
$this->m_aIndex = $aIndex;
$this->m_bModified = false;
}
public function GetText()
{
return $this->m_sLog;
}
public function GetIndex()
{
return $this->m_aIndex;
}
public function __toString()
{
return $this->m_sLog;
}
public function ClearModifiedFlag()
{
$this->m_bModified = false;
}
public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null)
{
$sHtml = '<table style="width:100%;table-layout:fixed"><tr><td>'; // Use table-layout:fixed to force the with to be independent from the actual content
$iPos = 0;
$aIndex = $this->m_aIndex;
if (($bEditMode) && (count($aIndex) > 0) && $this->m_bModified)
{
// Don't display the first element, that is still considered as editable
$iPos = $aIndex[0]['separator_length'] + $aIndex[0]['text_length'];
array_shift($aIndex);
}
for($index=count($aIndex)-1 ; $index >= 0 ; $index--)
{
if ($index < count($aIndex) - CASELOG_VISIBLE_ITEMS)
{
$sOpen = '';
$sDisplay = 'style="display:none;"';
}
else
{
$sOpen = ' open';
$sDisplay = '';
}
$iPos += $aIndex[$index]['separator_length'];
$sTextEntry = substr($this->m_sLog, $iPos, $aIndex[$index]['text_length']);
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
if (!is_null($aTransfoHandler))
{
$sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
}
$iPos += $aIndex[$index]['text_length'];
$sEntry = '<div class="caselog_header'.$sOpen.'">';
// Workaround: PHP < 5.3 cannot unserialize correctly DateTime objects,
// therefore we have changed the format. To preserve the compatibility with existing
// installations of iTop, both format are allowed:
// the 'date' item is either a DateTime object, or a unix timestamp
if (is_int($aIndex[$index]['date']))
{
// Unix timestamp
$sDate = date(Dict::S('UI:CaseLog:DateFormat'),$aIndex[$index]['date']);
}
elseif (is_object($aIndex[$index]['date']))
{
if (version_compare(phpversion(), '5.3.0', '>='))
{
// DateTime
$sDate = $aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat'));
}
else
{
// No Warning... but the date is unknown
$sDate = '';
}
}
$sEntry .= sprintf(Dict::S('UI:CaseLog:Header_Date_UserName'), $sDate, $aIndex[$index]['user_name']);
$sEntry .= '</div>';
$sEntry .= '<div class="caselog_entry"'.$sDisplay.'>';
$sEntry .= $sTextEntry;
$sEntry .= '</div>';
$sHtml = $sHtml.$sEntry;
}
// Process the case of an eventual remainder (quick migration of AttributeText fields)
if ($iPos < (strlen($this->m_sLog) - 1))
{
$sTextEntry = substr($this->m_sLog, $iPos);
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
if (!is_null($aTransfoHandler))
{
$sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
}
if (count($this->m_aIndex) == 0)
{
$sHtml .= '<div class="caselog_entry open">';
$sHtml .= $sTextEntry;
$sHtml .= '</div>';
}
else
{
if (count($this->m_aIndex) - CASELOG_VISIBLE_ITEMS > 0)
{
$sOpen = '';
$sDisplay = 'style="display:none;"';
}
else
{
$sOpen = ' open';
$sDisplay = '';
}
$sHtml .= '<div class="caselog_header'.$sOpen.'">';
$sHtml .= Dict::S('UI:CaseLog:InitialValue');
$sHtml .= '</div>';
$sHtml .= '<div class="caselog_entry"'.$sDisplay.'>';
$sHtml .= $sTextEntry;
$sHtml .= '</div>';
}
}
$sHtml .= '</td></tr></table>';
return $sHtml;
}
/**
* Add a new entry to the log or merge the given text into the currently modified entry
* and updates the internal index
* @param $sText string The text of the new entry
*/
public function AddLogEntry($sText, $sOnBehalfOf = '')
{
$bMergeEntries = false;
$sDate = date(Dict::S('UI:CaseLog:DateFormat'));
if ($sOnBehalfOf == '')
{
$sOnBehalfOf = UserRights::GetUserFriendlyName();
$iUserId = UserRights::GetUserId();
}
else
{
$iUserId = null;
}
if ($this->m_bModified)
{
$aLatestEntry = end($this->m_aIndex);
if ($aLatestEntry['user_name'] != $sOnBehalfOf)
{
$bMergeEntries = false;
}
else
{
$bMergeEntries = true;
}
}
if ($bMergeEntries)
{
$aLatestEntry = end($this->m_aIndex);
$this->m_sLog = substr($this->m_sLog, $aLatestEntry['separator_length']);
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
$iSepLength = strlen($sSeparator);
$iTextlength = strlen($sText."\n");
$this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
$this->m_aIndex[] = array(
'user_name' => $sOnBehalfOf,
'user_id' => $iUserId,
'date' => time(),
'text_length' => $aLatestEntry['text_length'] + $iTextlength,
'separator_length' => $iSepLength,
);
}
else
{
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
$iSepLength = strlen($sSeparator);
$iTextlength = strlen($sText);
$this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
$this->m_aIndex[] = array(
'user_name' => $sOnBehalfOf,
'user_id' => $iUserId,
'date' => time(),
'text_length' => $iTextlength,
'separator_length' => $iSepLength,
);
}
$this->m_bModified = true;
}
public function GetModifiedEntry()
{
$sModifiedEntry = '';
if ($this->m_bModified)
{
$sModifiedEntry = $this->GetLatestEntry();
}
return $sModifiedEntry;
}
/**
* Get the latest entry from the log
* @return string
*/
public function GetLatestEntry()
{
$aLastEntry = end($this->m_aIndex);
$sRes = substr($this->m_sLog, $aLastEntry['separator_length'], $aLastEntry['text_length']);
return $sRes;
}
/**
* Get the index of the latest entry from the log
* @return integer
*/
public function GetLatestEntryIndex()
{
$aKeys = array_keys($this->m_aIndex);
$iLast = end($aKeys); // Strict standards: the parameter passed to 'end' must be a variable since it is passed by reference
return $iLast;
}
}
?>

View File

@@ -105,7 +105,7 @@ class ormDocument
*/
public function GetDisplayLink($sClass, $Id, $sAttCode)
{
return "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=display_document&class=$sClass&id=$Id&field=$sAttCode\" target=\"_blank\" >".$this->GetFileName()."</a>\n";
return "<a href=\"../pages/ajax.render.php?operation=display_document&class=$sClass&id=$Id&field=$sAttCode\" target=\"_blank\" >".$this->GetFileName()."</a>\n";
}
/**
@@ -114,7 +114,7 @@ class ormDocument
*/
public function GetDownloadLink($sClass, $Id, $sAttCode)
{
return "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode\">".$this->GetFileName()."</a>\n";
return "<a href=\"../pages/ajax.render.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode\">".$this->GetFileName()."</a>\n";
}
}
?>

View File

@@ -1,465 +0,0 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
require_once('backgroundprocess.inc.php');
/**
* ormStopWatch
* encapsulate the behavior of a stop watch that will be stored as an attribute of class AttributeStopWatch
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
/**
* ormStopWatch
* encapsulate the behavior of a stop watch that will be stored as an attribute of class AttributeStopWatch
*
* @package itopORM
*/
class ormStopWatch
{
protected $iTimeSpent; // seconds
protected $iStarted; // unix time (seconds)
protected $iLastStart; // unix time (seconds)
protected $iStopped; // unix time (seconds)
protected $aThresholds;
/**
* Constructor
*/
public function __construct($iTimeSpent = 0, $iStarted = null, $iLastStart = null, $iStopped = null)
{
$this->iTimeSpent = (int) $iTimeSpent;
$this->iStarted = $iStarted;
$this->iLastStart = $iLastStart;
$this->iStopped = $iStopped;
$this->aThresholds = array();
}
/**
* Necessary for the triggers
*/
public function __toString()
{
return (string) $this->iTimeSpent;
}
public function DefineThreshold($iPercent, $tDeadline = null, $bPassed = false, $bTriggered = false, $iOverrun = null)
{
$this->aThresholds[$iPercent] = array(
'deadline' => $tDeadline, // unix time (seconds)
'passed' => $bPassed,
'triggered' => $bTriggered,
'overrun' => $iOverrun
);
}
public function MarkThresholdAsTriggered($iPercent)
{
$this->aThresholds[$iPercent]['triggered'] = true;
}
public function GetTimeSpent()
{
return $this->iTimeSpent;
}
public function GetStartDate()
{
return $this->iStarted;
}
public function GetLastStartDate()
{
return $this->iLastStart;
}
public function GetStopDate()
{
return $this->iStopped;
}
public function GetThresholdDate($iPercent)
{
if (array_key_exists($iPercent, $this->aThresholds))
{
return $this->aThresholds[$iPercent]['deadline'];
}
else
{
return null;
}
}
public function GetOverrun($iPercent)
{
if (array_key_exists($iPercent, $this->aThresholds))
{
return $this->aThresholds[$iPercent]['overrun'];
}
else
{
return null;
}
}
public function IsThresholdPassed($iPercent)
{
if (array_key_exists($iPercent, $this->aThresholds))
{
return $this->aThresholds[$iPercent]['passed'];
}
else
{
return false;
}
}
public function IsThresholdTriggered($iPercent)
{
if (array_key_exists($iPercent, $this->aThresholds))
{
return $this->aThresholds[$iPercent]['triggered'];
}
else
{
return false;
}
}
public function GetAsHTML($oAttDef, $oHostObject = null)
{
$aProperties = array();
$aProperties['States'] = implode(', ', $oAttDef->GetStates());
if (is_null($this->iLastStart))
{
if (is_null($this->iStarted))
{
$aProperties['Elapsed'] = 'never started';
}
else
{
$aProperties['Elapsed'] = $this->iTimeSpent.' s';
}
}
else
{
$iElapsedTemp = ''; //$this->ComputeDuration($oHostObject, $oAttDef, $this->iLastStart, time());
$aProperties['Elapsed'] = $this->iTimeSpent.' + '.$iElapsedTemp.' s + <img src="../images/indicator.gif">';
}
$aProperties['Started'] = $oAttDef->SecondsToDate($this->iStarted);
$aProperties['LastStart'] = $oAttDef->SecondsToDate($this->iLastStart);
$aProperties['Stopped'] = $oAttDef->SecondsToDate($this->iStopped);
foreach ($this->aThresholds as $iPercent => $aThresholdData)
{
$sThresholdDesc = $oAttDef->SecondsToDate($aThresholdData['deadline']);
if ($aThresholdData['triggered'])
{
$sThresholdDesc .= " <b>TRIGGERED</b>";
}
if ($aThresholdData['overrun'])
{
$sThresholdDesc .= " Overrun:".(int) $aThresholdData['overrun']." sec.";
}
$aProperties[$iPercent.'%'] = $sThresholdDesc;
}
$sRes = "<TABLE class=\"listResults\">";
$sRes .= "<TBODY>";
foreach ($aProperties as $sProperty => $sValue)
{
$sRes .= "<TR>";
$sCell = str_replace("\n", "<br>\n", $sValue);
$sRes .= "<TD class=\"label\">$sProperty</TD><TD>$sCell</TD>";
$sRes .= "</TR>";
}
$sRes .= "</TBODY>";
$sRes .= "</TABLE>";
return $sRes;
}
protected function ComputeGoal($oObject, $oAttDef)
{
$sMetricComputer = $oAttDef->Get('goal_computing');
$oComputer = new $sMetricComputer();
$aCallSpec = array($oComputer, 'ComputeMetric');
if (!is_callable($aCallSpec))
{
throw new CoreException("Unknown class/verb '$sMetricComputer/ComputeMetric'");
}
$iRet = call_user_func($aCallSpec, $oObject);
return $iRet;
}
protected function ComputeDeadline($oObject, $oAttDef, $iStartTime, $iDurationSec)
{
$sWorkingTimeComputer = $oAttDef->Get('working_time_computing');
$aCallSpec = array($sWorkingTimeComputer, '__construct');
if (!is_callable($aCallSpec))
{
//throw new CoreException("Pas de constructeur pour $sWorkingTimeComputer!");
}
$oComputer = new $sWorkingTimeComputer();
$aCallSpec = array($oComputer, 'GetDeadline');
if (!is_callable($aCallSpec))
{
throw new CoreException("Unknown class/verb '$sWorkingTimeComputer/GetDeadline'");
}
// GetDeadline($oObject, $iDuration, DateTime $oStartDate)
$oStartDate = new DateTime('@'.$iStartTime); // setTimestamp not available in PHP 5.2
$oDeadline = call_user_func($aCallSpec, $oObject, $iDurationSec, $oStartDate);
$iRet = $oDeadline->format('U');
return $iRet;
}
protected function ComputeDuration($oObject, $oAttDef, $iStartTime, $iEndTime)
{
$sWorkingTimeComputer = $oAttDef->Get('working_time_computing');
$oComputer = new $sWorkingTimeComputer();
$aCallSpec = array($oComputer, 'GetOpenDuration');
if (!is_callable($aCallSpec))
{
throw new CoreException("Unknown class/verb '$sWorkingTimeComputer/GetOpenDuration'");
}
// GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate)
$oStartDate = new DateTime('@'.$iStartTime); // setTimestamp not available in PHP 5.2
$oEndDate = new DateTime('@'.$iEndTime);
$iRet = call_user_func($aCallSpec, $oObject, $oStartDate, $oEndDate);
return $iRet;
}
public function Reset($oObject, $oAttDef)
{
$this->iTimeSpent = 0;
$this->iStarted = null;
$this->iLastStart = null;
$this->iStopped = null;
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
{
$aThresholdData['passed'] = false;
$aThresholdData['triggered'] = false;
$aThresholdData['deadline'] = null;
$aThresholdData['overrun'] = null;
}
}
/**
* Start or continue
* It is the responsibility of the caller to compute the deadlines
* (to avoid computing twice for the same result)
*/
public function Start($oObject, $oAttDef)
{
if (!is_null($this->iLastStart))
{
// Already started
return false;
}
if (is_null($this->iStarted))
{
$this->iStarted = time();
}
$this->iLastStart = time();
$this->iStopped = null;
return true;
}
/**
* Compute or recompute the goal and threshold deadlines
*/
public function ComputeDeadlines($oObject, $oAttDef)
{
if (is_null($this->iLastStart))
{
// Currently stopped - do nothing
return false;
}
$iDurationGoal = $this->ComputeGoal($oObject, $oAttDef);
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
{
if (is_null($iDurationGoal))
{
// No limit: leave null thresholds
$aThresholdData['deadline'] = null;
}
else
{
$iThresholdDuration = round($iPercent * $iDurationGoal / 100);
$aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $this->iLastStart, $iThresholdDuration - $this->iTimeSpent);
// OR $aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $this->iStarted, $iThresholdDuration);
}
if (is_null($aThresholdData['deadline']) || ($aThresholdData['deadline'] > time()))
{
// The threshold is in the future, reset
$aThresholdData['passed'] = false;
$aThresholdData['triggered'] = false;
$aThresholdData['overrun'] = null;
}
else
{
// The new threshold is in the past
$aThresholdData['passed'] = true;
// Note: the overrun can be wrong, but the correct algorithm to compute
// the overrun of a deadline in the past requires that the ormStopWatch keeps track of all its history!!!
}
}
return true;
}
/**
* Stop counting if not already done
*/
public function Stop($oObject, $oAttDef)
{
if (is_null($this->iLastStart))
{
// Already stopped
return false;
}
$iElapsed = $this->ComputeDuration($oObject, $oAttDef, $this->iLastStart, time());
$this->iTimeSpent = $this->iTimeSpent + $iElapsed;
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
{
if (!is_null($aThresholdData['deadline']) && (time() > $aThresholdData['deadline']))
{
if ($aThresholdData['overrun'] > 0)
{
// Accumulate from last start
$aThresholdData['overrun'] += $iElapsed;
}
else
{
// First stop after the deadline has been passed
$iOverrun = $this->ComputeDuration($oObject, $oAttDef, $aThresholdData['deadline'], time());
$aThresholdData['overrun'] = $iOverrun;
}
$aThresholdData['passed'] = true;
}
$aThresholdData['deadline'] = null;
}
$this->iLastStart = null;
$this->iStopped = time();
return true;
}
}
/**
* CheckStopWatchThresholds
* Implements the automatic actions
*
* @package itopORM
*/
class CheckStopWatchThresholds implements iBackgroundProcess
{
public function GetPeriodicity()
{
return 10; // seconds
}
public function Process($iTimeLimit)
{
foreach (MetaModel::GetClasses() as $sClass)
{
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if ($oAttDef instanceof AttributeStopWatch)
{
foreach ($oAttDef->ListThresholds() as $iThreshold => $aThresholdData)
{
$iPercent = $aThresholdData['percent']; // could be different than the index !
$sExpression = "SELECT $sClass WHERE {$sAttCode}_laststart AND {$sAttCode}_{$iThreshold}_triggered = 0 AND {$sAttCode}_{$iThreshold}_deadline < NOW()";
//echo $sExpression."<br/>\n";
$oFilter = DBObjectSearch::FromOQL($sExpression);
$aList = array();
$oSet = new DBObjectSet($oFilter);
while ((time() < $iTimeLimit) && ($oObj = $oSet->Fetch()))
{
$sClass = get_class($oObj);
$aList[] = $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold;
//echo $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold."\n";
// Execute planned actions
//
foreach ($aThresholdData['actions'] as $aActionData)
{
$sVerb = $aActionData['verb'];
$aParams = $aActionData['params'];
$sParams = implode(', ', $aParams);
//echo "Calling: $sVerb($sParams)<br/>\n";
$aCallSpec = array($oObj, $sVerb);
call_user_func_array($aCallSpec, $aParams);
}
// Mark the threshold as "triggered"
//
$oSW = $oObj->Get($sAttCode);
$oSW->MarkThresholdAsTriggered($iThreshold);
$oObj->Set($sAttCode, $oSW);
if($oObj->IsModified())
{
// Todo - factorize so that only one single change will be instantiated
$oMyChange = new CMDBChange();
$oMyChange->Set("date", time());
$oMyChange->Set("userinfo", "Automatic - threshold triggered");
$iChangeId = $oMyChange->DBInsertNoReload();
$oObj->DBUpdateTracked($oMyChange, true /*skip security*/);
}
// Activate any existing trigger
//
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
$oSet = new DBObjectSet(
DBObjectSearch::FromOQL("SELECT TriggerOnThresholdReached AS t WHERE t.target_class IN ('$sClassList') AND stop_watch_code=:stop_watch_code AND threshold_index = :threshold_index"),
array(), // order by
array('stop_watch_code' => $sAttCode, 'threshold_index' => $iThreshold)
);
while ($oTrigger = $oSet->Fetch())
{
$oTrigger->DoActivate($oObj->ToArgs('this'));
}
}
}
}
}
}
$iProcessed = count($aList);
return "Triggered $iProcessed threshold(s)";
}
}
?>

View File

@@ -1,74 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Associated with the metamodel -> MakeQuery/MakeQuerySingleTable
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
class QueryBuilderContext
{
protected $m_oRootFilter;
protected $m_aClassAliases;
protected $m_aTableAliases;
protected $m_aModifierProperties;
public $m_oQBExpressions;
public function __construct($oFilter, $aModifierProperties, $aGroupByExpr = null)
{
$this->m_oRootFilter = $oFilter;
$this->m_oQBExpressions = new QueryBuilderExpressions($oFilter->GetCriteria(), $aGroupByExpr);
$this->m_aClassAliases = $oFilter->GetJoinedClasses();
$this->m_aTableAliases = array();
$this->m_aModifierProperties = $aModifierProperties;
}
public function GetRootFilter()
{
return $this->m_oRootFilter;
}
public function GenerateTableAlias($sNewName, $sRealName)
{
return MetaModel::GenerateUniqueAlias($this->m_aTableAliases, $sNewName, $sRealName);
}
public function GenerateClassAlias($sNewName, $sRealName)
{
return MetaModel::GenerateUniqueAlias($this->m_aClassAliases, $sNewName, $sRealName);
}
public function GetModifierProperties($sPluginClass)
{
if (array_key_exists($sPluginClass, $this->m_aModifierProperties))
{
return $this->m_aModifierProperties[$sPluginClass];
}
else
{
return array();
}
}
}
?>

View File

@@ -1,33 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Interface iQueryModifier
* Defines the API to tweak queries (e.g. translate data on the fly)
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
interface iQueryModifier
{
public function __construct();
public function GetFieldExpression(QueryBuilderContext &$oBuild, $sClass, $sAttCode, $sColId, Expression $oFieldSQLExp, SQLQuery &$oSelect);
}
?>

View File

@@ -35,20 +35,36 @@
require_once('cmdbsource.class.inc.php');
class SQLExpression extends BinaryExpression
{
}
class ScalarSQLExpression extends ScalarExpression
{
}
class TrueSQLExpression extends TrueExpression
{
}
class FieldSQLExpression extends FieldExpression
{
}
class VariableSQLExpression extends VariableExpression
{
}
class SQLQuery
{
private $m_SourceOQL = '';
private $m_sTable = '';
private $m_sTableAlias = '';
private $m_aFields = array();
private $m_aGroupBy = array();
private $m_oConditionExpr = null;
private $m_aFullTextNeedles = array();
private $m_bToDelete = true; // The current table must be listed for deletion ?
private $m_aValues = array(); // Values to set in case of an update query
private $m_oSelectedIdField = null;
private $m_aJoinSelects = array();
public function __construct($sTable, $sTableAlias, $aFields, $bToDelete = true, $aValues = array(), $oSelectedIdField = null)
public function __construct($sTable, $sTableAlias, $aFields, $oConditionExpr, $aFullTextNeedles, $bToDelete = true, $aValues = array())
{
// This check is not needed but for developping purposes
//if (!CMDBSource::IsTable($sTable))
@@ -63,26 +79,18 @@ class SQLQuery
$this->m_sTable = $sTable;
$this->m_sTableAlias = $sTableAlias;
$this->m_aFields = $aFields;
$this->m_aGroupBy = null;
$this->m_oConditionExpr = null;
$this->m_oConditionExpr = $oConditionExpr;
if (is_null($oConditionExpr))
{
$this->m_oConditionExpr = new TrueExpression;
}
else if (!$oConditionExpr instanceof Expression)
{
throw new CoreException('Invalid type for condition, expecting an Expression', array('class' => get_class($oConditionExpr)));
}
$this->m_aFullTextNeedles = $aFullTextNeedles;
$this->m_bToDelete = $bToDelete;
$this->m_aValues = $aValues;
$this->m_oSelectedIdField = $oSelectedIdField;
}
public function GetTableAlias()
{
return $this->m_sTableAlias;
}
public function SetSourceOQL($sOQL)
{
$this->m_SourceOQL = $sOQL;
}
public function GetSourceOQL()
{
return $this->m_SourceOQL;
}
public function DisplayHtml()
@@ -100,6 +108,16 @@ class SQLQuery
echo "<b>$this->m_sTable</b>$sFields<br/>\n";
// #@# todo - display html of an expression tree
//$this->m_oConditionExpr->DisplayHtml()
if (count($this->m_aFullTextNeedles) > 0)
{
echo "Full text criteria...<br/>\n";
echo "<ul class=\"treeview\">\n";
foreach ($this->m_aFullTextNeedles as $sFTNeedle)
{
echo "<li>$sFTNeedle</li>\n";
}
echo "</ul>";
}
if (count($this->m_aJoinSelects) > 0)
{
echo "Joined to...<br/>\n";
@@ -108,47 +126,26 @@ class SQLQuery
{
$sJoinType = $aJoinInfo["jointype"];
$oSQLQuery = $aJoinInfo["select"];
if (isset($aJoinInfo["on_expression"]))
{
$sOnCondition = $aJoinInfo["on_expression"]->Render();
$sLeftField = $aJoinInfo["leftfield"];
$sRightField = $aJoinInfo["rightfield"];
$sRightTableAlias = $aJoinInfo["righttablealias"];
echo "<li>Join '$sJoinType', ON ($sOnCondition)".$oSQLQuery->DisplayHtml()."</li>\n";
}
else
{
$sLeftField = $aJoinInfo["leftfield"];
$sRightField = $aJoinInfo["rightfield"];
$sRightTableAlias = $aJoinInfo["righttablealias"];
echo "<li>Join '$sJoinType', $sLeftField, $sRightTableAlias.$sRightField".$oSQLQuery->DisplayHtml()."</li>\n";
}
echo "<li>Join '$sJoinType', $sLeftField, $sRightTableAlias.$sRightField".$oSQLQuery->DisplayHtml()."</li>\n";
}
echo "</ul>";
}
$aFrom = array();
$aFields = array();
$aGroupBy = array();
$oCondition = null;
$aDelTables = array();
$aSetValues = array();
$aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues);
echo "From ...<br/>\n";
echo "<pre style=\"font-size: smaller;\">\n";
print_r($aFrom);
echo "</pre>";
}
public function SetSelect($aExpressions)
{
$this->m_aFields = $aExpressions;
}
public function SetGroupBy($aExpressions)
{
$this->m_aGroupBy = $aExpressions;
}
public function SetCondition($oConditionExpr)
{
$this->m_oConditionExpr = $oConditionExpr;
@@ -156,14 +153,7 @@ class SQLQuery
public function AddCondition($oConditionExpr)
{
if (is_null($this->m_oConditionExpr))
{
$this->m_oConditionExpr = $oConditionExpr;
}
else
{
$this->m_oConditionExpr->LogAnd($oConditionExpr);
}
$this->m_oConditionExpr->LogAnd($oConditionExpr);
}
private function AddJoin($sJoinType, $oSQLQuery, $sLeftField, $sRightField, $sRightTableAlias = '')
@@ -185,6 +175,7 @@ class SQLQuery
// {
// throw new CoreException("Unknown field '$sRightField' in table '".$sRightTable."'");
// }
$this->m_aJoinSelects[] = array(
"jointype" => $sJoinType,
"select" => $oSQLQuery,
@@ -193,49 +184,14 @@ class SQLQuery
"righttablealias" => $sRightTableAlias
);
}
public function AddInnerJoin($oSQLQuery, $sLeftField, $sRightField, $sRightTable = '')
public function AddInnerJoin($oSQLQuery, $sLeftField, $sRightField, $sRigthtTable = '')
{
$this->AddJoin("inner", $oSQLQuery, $sLeftField, $sRightField, $sRightTable);
}
public function AddInnerJoinTree($oSQLQuery, $sLeftFieldLeft, $sLeftFieldRight, $sRightFieldLeft, $sRightFieldRight, $sRightTableAlias = '', $iOperatorCode = TREE_OPERATOR_BELOW)
{
assert((get_class($oSQLQuery) == __CLASS__) || is_subclass_of($oSQLQuery, __CLASS__));
if (empty($sRightTableAlias))
{
$sRightTableAlias = $oSQLQuery->m_sTableAlias;
}
$this->m_aJoinSelects[] = array(
"jointype" => 'inner_tree',
"select" => $oSQLQuery,
"leftfield" => $sLeftFieldLeft,
"rightfield" => $sLeftFieldRight,
"rightfield_left" => $sRightFieldLeft,
"rightfield_right" => $sRightFieldRight,
"righttablealias" => $sRightTableAlias,
"tree_operator" => $iOperatorCode);
$this->AddJoin("inner", $oSQLQuery, $sLeftField, $sRightField, $sRigthtTable);
}
public function AddLeftJoin($oSQLQuery, $sLeftField, $sRightField)
{
return $this->AddJoin("left", $oSQLQuery, $sLeftField, $sRightField);
}
public function AddInnerJoinEx(SQLQuery $oSQLQuery, Expression $oOnExpression)
{
$this->m_aJoinSelects[] = array(
"jointype" => 'inner',
"select" => $oSQLQuery,
"on_expression" => $oOnExpression
);
}
public function AddLeftJoinEx(SQLQuery $oSQLQuery, Expression $oOnExpression)
{
$this->m_aJoinSelects[] = array(
"jointype" => 'left',
"select" => $oSQLQuery,
"on_expression" => $oOnExpression
);
}
// Interface, build the SQL query
public function RenderDelete($aArgs = array())
@@ -243,12 +199,10 @@ class SQLQuery
// The goal will be to complete the list as we build the Joins
$aFrom = array();
$aFields = array();
$aGroupBy = array();
$oCondition = null;
$aDelTables = array();
$aSetValues = array();
$aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues);
// Target: DELETE myAlias1, myAlias2 FROM t1 as myAlias1, t2 as myAlias2, t3 as topreserve WHERE ...
@@ -262,15 +216,8 @@ class SQLQuery
throw new CoreException("Building a request wich will delete every object of a given table -looks suspicious- please use truncate instead...");
}
*/
if (is_null($oCondition))
{
// Delete all !!!
}
else
{
$sWhere = self::ClauseWhere($oCondition, $aArgs);
return "DELETE $sDelete FROM $sFrom WHERE $sWhere";
}
$sWhere = self::ClauseWhere($oCondition, $aArgs);
return "DELETE $sDelete FROM $sFrom WHERE $sWhere";
}
// Interface, build the SQL query
@@ -279,12 +226,11 @@ class SQLQuery
// The goal will be to complete the list as we build the Joins
$aFrom = array();
$aFields = array();
$aGroupBy = array();
$oCondition = null;
$aDelTables = array();
$aSetValues = array();
$aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues);
$sFrom = self::ClauseFrom($aFrom);
$sValues = self::ClauseValues($aSetValues);
$sWhere = self::ClauseWhere($oCondition, $aArgs);
@@ -297,26 +243,16 @@ class SQLQuery
// The goal will be to complete the lists as we build the Joins
$aFrom = array();
$aFields = array();
$aGroupBy = array();
$oCondition = null;
$aDelTables = array();
$aSetValues = array();
$aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues);
$sFrom = self::ClauseFrom($aFrom);
$sWhere = self::ClauseWhere($oCondition, $aArgs);
if ($bGetCount)
{
if (count($aSelectedIdFields) > 0)
{
$sIDFields = implode(', ', $aSelectedIdFields);
$sSQL = "SELECT COUNT(DISTINCT $sIDFields) AS COUNT FROM $sFrom WHERE $sWhere";
}
else
{
$sSQL = "SELECT COUNT(*) AS COUNT FROM $sFrom WHERE $sWhere";
}
$sSQL = "SELECT COUNT(*) AS COUNT FROM $sFrom WHERE $sWhere";
}
else
{
@@ -339,27 +275,6 @@ class SQLQuery
return $sSQL;
}
// Interface, build the SQL query
public function RenderGroupBy($aArgs = array())
{
// The goal will be to complete the lists as we build the Joins
$aFrom = array();
$aFields = array();
$aGroupBy = array();
$oCondition = null;
$aDelTables = array();
$aSetValues = array();
$aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
$sSelect = self::ClauseSelect($aFields);
$sFrom = self::ClauseFrom($aFrom);
$sWhere = self::ClauseWhere($oCondition, $aArgs);
$sGroupBy = self::ClauseGroupBy($aGroupBy);
$sSQL = "SELECT $sSelect, COUNT(*) AS _itop_count_ FROM $sFrom WHERE $sWhere GROUP BY $sGroupBy";
return $sSQL;
}
private static function ClauseSelect($aFields)
{
$aSelect = array();
@@ -371,12 +286,6 @@ class SQLQuery
return $sSelect;
}
private static function ClauseGroupBy($aGroupBy)
{
$sRes = implode(', ', $aGroupBy);
return $sRes;
}
private static function ClauseDelete($aDelTableAliases)
{
$aDelTables = array();
@@ -400,7 +309,6 @@ class SQLQuery
$sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]);
break;
case "inner":
case "inner_tree":
$sFrom .= " INNER JOIN (`".$aJoinInfo["tablename"]."` AS `$sTableAlias`";
$sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]);
$sFrom .= ") ON ".$aJoinInfo["joincondition"];
@@ -430,14 +338,7 @@ class SQLQuery
private static function ClauseWhere($oConditionExpr, $aArgs = array())
{
if (is_null($oConditionExpr))
{
return '1';
}
else
{
return $oConditionExpr->Render($aArgs);
}
return $oConditionExpr->Render($aArgs);
}
private static function ClauseOrderBy($aOrderBy)
@@ -445,22 +346,50 @@ class SQLQuery
$aOrderBySpec = array();
foreach($aOrderBy as $sFieldAlias => $bAscending)
{
// Note: sFieldAlias must have backticks around column aliases
$aOrderBySpec[] = $sFieldAlias.($bAscending ? " ASC" : " DESC");
$aOrderBySpec[] = '`'.$sFieldAlias.'`'.($bAscending ? " ASC" : " DESC");
}
$sOrderBy = implode(", ", $aOrderBySpec);
return $sOrderBy;
}
// Purpose: prepare the query data, once for all
private function privRender(&$aFrom, &$aFields, &$aGroupBy, &$oCondition, &$aDelTables, &$aSetValues, &$aSelectedIdFields)
private function privRender(&$aFrom, &$aFields, &$oCondition, &$aDelTables, &$aSetValues)
{
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aGroupBy, $aDelTables, $aSetValues, $aSelectedIdFields, '', array('jointype' => 'first'));
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues);
// Add the full text search condition, based on each and every requested field
//
// To be updated with a real full text search based on the mySQL settings
// (then it might move somewhere else !)
//
$oCondition = $this->m_oConditionExpr;
if ((count($aFields) > 0) && (count($this->m_aFullTextNeedles) > 0))
{
$aFieldExp = array();
foreach ($aFields as $sField)
{
// This is TEMPORARY (that's why it is weird, actually)
// Full text match will be done as an expression in the filter condition
// $sField is already a string `table`.`column`
// Let's make an expression out of it (again !)
$aFieldExp[] = Expression::FromOQL($sField);
}
$oFullTextExpr = new CharConcatExpression($aFieldExp);
// The cast is necessary because the CONCAT result in a binary string:
// if any of the field is a binary string => case sensitive comparison
//
foreach($this->m_aFullTextNeedles as $sFTNeedle)
{
$oNewCond = new BinaryExpression($oFullTextExpr, 'LIKE', new ScalarExpression("%$sFTNeedle%"));
$oCondition = $oCondition->LogAnd($oNewCond);
}
}
return $sTableAlias;
}
private function privRenderSingleTable(&$aFrom, &$aFields, &$aGroupBy, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sCallerAlias = '', $aJoinData)
private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, $sJoinType = 'first', $sCallerAlias = '', $sLeftField = '', $sRightField = '', $sRightTableAlias = '')
{
$aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable);
@@ -468,72 +397,20 @@ class SQLQuery
// Handle the various kinds of join (or first table in the list)
//
if (empty($aJoinData['righttablealias']))
if (empty($sRightTableAlias))
{
$sRightTableAlias = $this->m_sTableAlias;
}
else
{
$sRightTableAlias = $aJoinData['righttablealias'];
}
switch ($aJoinData['jointype'])
$sJoinCond = "`$sCallerAlias`.`$sLeftField` = `$sRightTableAlias`.`$sRightField`";
switch ($sJoinType)
{
case "first":
$aFrom[$this->m_sTableAlias] = array("jointype"=>"first", "tablename"=>$this->m_sTable, "joincondition"=>"");
break;
case "inner":
case "left":
if (isset($aJoinData["on_expression"]))
{
$sJoinCond = $aJoinData["on_expression"]->Render();
}
else
{
$sJoinCond = "`$sCallerAlias`.`{$aJoinData['leftfield']}` = `$sRightTableAlias`.`{$aJoinData['rightfield']}`";
}
$aFrom[$this->m_sTableAlias] = array("jointype"=>$aJoinData['jointype'], "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond");
break;
case "inner_tree":
$sNodeLeft = "`$sCallerAlias`.`{$aJoinData['leftfield']}`";
$sNodeRight = "`$sCallerAlias`.`{$aJoinData['rightfield']}`";
$sRootLeft = "`$sRightTableAlias`.`{$aJoinData['rightfield_left']}`";
$sRootRight = "`$sRightTableAlias`.`{$aJoinData['rightfield_right']}`";
switch($aJoinData['tree_operator'])
{
case TREE_OPERATOR_BELOW:
$sJoinCond = "$sNodeLeft >= $sRootLeft AND $sNodeLeft <= $sRootRight";
break;
case TREE_OPERATOR_BELOW_STRICT:
$sJoinCond = "$sNodeLeft > $sRootLeft AND $sNodeLeft < $sRootRight";
break;
case TREE_OPERATOR_NOT_BELOW: // Complementary of 'BELOW'
$sJoinCond = "$sNodeLeft < $sRootLeft OR $sNodeLeft > $sRootRight";
break;
case TREE_OPERATOR_NOT_BELOW_STRICT: // Complementary of BELOW_STRICT
$sJoinCond = "$sNodeLeft <= $sRootLeft OR $sNodeLeft >= $sRootRight";
break;
case TREE_OPERATOR_ABOVE:
$sJoinCond = "$sNodeLeft <= $sRootLeft AND $sNodeRight >= $sRootRight";
break;
case TREE_OPERATOR_ABOVE_STRICT:
$sJoinCond = "$sNodeLeft < $sRootLeft AND $sNodeRight > $sRootRight";
break;
case TREE_OPERATOR_NOT_ABOVE: // Complementary of 'ABOVE'
$sJoinCond = "$sNodeLeft > $sRootLeft OR $sNodeRight < $sRootRight";
break;
case TREE_OPERATOR_NOT_ABOVE_STRICT: // Complementary of ABOVE_STRICT
$sJoinCond = "$sNodeLeft >= $sRootLeft OR $sNodeRight <= $sRootRight";
break;
}
$aFrom[$this->m_sTableAlias] = array("jointype"=>$aJoinData['jointype'], "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond");
// table or tablealias ???
$aFrom[$this->m_sTableAlias] = array("jointype"=>$sJoinType, "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond");
break;
}
@@ -542,38 +419,31 @@ class SQLQuery
//
foreach($this->m_aFields as $sAlias => $oExpression)
{
$sTable = $oExpression->GetParent();
$sColumn = $oExpression->GetName();
$aFields["`$sAlias`"] = $oExpression->Render();
}
if ($this->m_aGroupBy)
{
foreach($this->m_aGroupBy as $sAlias => $oExpression)
{
$aGroupBy["`$sAlias`"] = $oExpression->Render();
}
}
if ($this->m_bToDelete)
{
$aDelTables[] = "`{$this->m_sTableAlias}`";
}
//echo "<p>in privRenderSingleTable this->m_aValues<pre>".print_r($this->m_aValues, true)."</pre></p>\n";
foreach($this->m_aValues as $sFieldName=>$value)
{
$aSetValues["`{$this->m_sTableAlias}`.`$sFieldName`"] = $value; // quoted further!
}
if (!is_null($this->m_oSelectedIdField))
{
$aSelectedIdFields[] = $this->m_oSelectedIdField->Render();
}
// loop on joins, to complete the list of tables/fields/conditions
//
$aTempFrom = array(); // temporary subset of 'from' specs, to be grouped in the final query
foreach ($this->m_aJoinSelects as $aJoinData)
{
$sJoinType = $aJoinData["jointype"];
$oRightSelect = $aJoinData["select"];
$sLeftField = $aJoinData["leftfield"];
$sRightField = $aJoinData["rightfield"];
$sRightTableAlias = $aJoinData["righttablealias"];
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aGroupBy, $aDelTables, $aSetValues, $aSelectedIdFields, $this->m_sTableAlias, $aJoinData);
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $sJoinType, $this->m_sTableAlias, $sLeftField, $sRightField, $sRightTableAlias);
}
$aFrom[$this->m_sTableAlias]['subfrom'] = $aTempFrom;

View File

@@ -1,177 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Simple helper class to interpret and transform a template string
*
* Usage:
* $oString = new TemplateString("Blah $this->friendlyname$ is in location $this->location_id->name$ ('$this->location_id->org_id->name$)");
* echo $oString->Render(array('this' => $oContact));
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
/**
* Helper class
*/
class TemplateStringPlaceholder
{
public $sToken;
public $sAttCode;
public $sFunction;
public $sParamName;
public $bIsValid;
public function __construct($sToken)
{
$this->sToken = $sToken;
$this->sAttcode = '';
$this->sFunction = '';
$this->sParamName = '';
$this->bIsValid = false; // Validity may be false in general, but it can work anyway (thanks to specialization) when rendering
}
}
/**
* Class TemplateString
*/
class TemplateString
{
protected $m_sRaw;
protected $m_aPlaceholders;
public function __construct($sRaw)
{
$this->m_sRaw = $sRaw;
$this->m_aPlaceholders = null;
}
/**
* Split the string into placholders
* @param Hash $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
* @return void
*/
protected function Analyze($aParamTypes = array())
{
if (!is_null($this->m_aPlaceholders)) return;
$this->m_aPlaceholders = array();
if (preg_match_all('/\\$([a-z0-9_]+(->[a-z0-9_]+)*)\\$/', $this->m_sRaw, $aMatches))
{
foreach($aMatches[1] as $sPlaceholder)
{
$oPlaceholder = new TemplateStringPlaceholder($sPlaceholder);
$oPlaceholder->bIsValid = false;
foreach ($aParamTypes as $sParamName => $sClass)
{
$sParamPrefix = $sParamName.'->';
if (substr($sPlaceholder, 0, strlen($sParamPrefix)) == $sParamPrefix)
{
// Todo - detect functions (label...)
$oPlaceholder->sFunction = '';
$oPlaceholder->sParamName = $sParamName;
$sAttcode = substr($sPlaceholder, strlen($sParamPrefix));
$oPlaceholder->sAttcode = $sAttcode;
$oPlaceholder->bIsValid = MetaModel::IsValidAttCode($sClass, $sAttcode, true /* extended */);
}
}
$this->m_aPlaceholders[] = $oPlaceholder;
}
}
}
/**
* Return the placeholders (for reporting purposes)
* @return void
*/
public function GetPlaceholders()
{
return $this->m_aPlaceholders;
}
/**
* Check the format when possible
* @param Hash $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
* @return void
*/
public function IsValid($aParamTypes = array())
{
$this->Analyze($aParamTypes);
foreach($this->m_aPlaceholders as $oPlaceholder)
{
if (!$oPlaceholder->bIsValid)
{
if (count($aParamTypes) == 0)
{
return false;
}
if (array_key_exists($oPlaceholder->sParamName, $aParamTypes))
{
return false;
}
}
}
return true;
}
/**
* Apply the given parameters to replace the placeholders
* @param Hash $aParamValues Value of the expected parameters: hash array of '<param_id>' => '<value>'
* @return void
*/
public function Render($aParamValues = array())
{
$aParamTypes = array();
foreach($aParamValues as $sParamName => $value)
{
$aParamTypes[$sParamName] = get_class($value);
}
$this->Analyze($aParamTypes);
$aSearch = array();
$aReplace = array();
foreach($this->m_aPlaceholders as $oPlaceholder)
{
if (array_key_exists($oPlaceholder->sParamName, $aParamValues))
{
$oRef = $aParamValues[$oPlaceholder->sParamName];
try
{
$value = $oRef->Get($oPlaceholder->sAttcode);
$aSearch[] = '$'.$oPlaceholder->sToken.'$';
$aReplace[] = $value;
$oPlaceholder->bIsValid = true;
}
catch(Exception $e)
{
$oPlaceholder->bIsValid = false;
}
}
else
{
$oPlaceholder->bIsValid = false;
}
}
return str_replace($aSearch, $aReplace, $this->m_sRaw);
}
}
?>

View File

@@ -41,7 +41,7 @@ abstract class Trigger extends cmdbAbstractObject
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"reconc_keys" => array(),
"db_table" => "priv_trigger",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
@@ -87,7 +87,7 @@ abstract class TriggerOnObject extends Trigger
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"reconc_keys" => array(),
"db_table" => "priv_trigger_onobject",
"db_key_field" => "id",
"db_finalclass_field" => "",
@@ -105,34 +105,6 @@ abstract class TriggerOnObject extends Trigger
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
/**
* To trigger notifications when a ticket is updated from the portal
*/
class TriggerOnPortalUpdate extends TriggerOnObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,bizmodel",
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"db_table" => "priv_trigger_onportalupdate",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list
// Search criteria
}
}
abstract class TriggerOnStateChange extends TriggerOnObject
{
@@ -144,7 +116,7 @@ abstract class TriggerOnStateChange extends TriggerOnObject
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"reconc_keys" => array(),
"db_table" => "priv_trigger_onstatechange",
"db_key_field" => "id",
"db_finalclass_field" => "",
@@ -158,7 +130,7 @@ abstract class TriggerOnStateChange extends TriggerOnObject
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'state', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'state')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
@@ -169,11 +141,11 @@ class TriggerOnStateEnter extends TriggerOnStateChange
{
$aParams = array
(
"category" => "core/cmdb,bizmodel",
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"reconc_keys" => array(),
"db_table" => "priv_trigger_onstateenter",
"db_key_field" => "id",
"db_finalclass_field" => "",
@@ -186,7 +158,7 @@ class TriggerOnStateEnter extends TriggerOnStateChange
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'state', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
@@ -197,11 +169,11 @@ class TriggerOnStateLeave extends TriggerOnStateChange
{
$aParams = array
(
"category" => "core/cmdb,bizmodel",
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"reconc_keys" => array(),
"db_table" => "priv_trigger_onstateleave",
"db_key_field" => "id",
"db_finalclass_field" => "",
@@ -214,7 +186,7 @@ class TriggerOnStateLeave extends TriggerOnStateChange
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'state', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('standard_search', array('')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('')); // Criteria of the advanced search form
}
}
@@ -225,11 +197,11 @@ class TriggerOnObjectCreate extends TriggerOnObject
{
$aParams = array
(
"category" => "core/cmdb,bizmodel",
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"reconc_keys" => array(),
"db_table" => "priv_trigger_onobjcreate",
"db_key_field" => "id",
"db_finalclass_field" => "",
@@ -242,7 +214,7 @@ class TriggerOnObjectCreate extends TriggerOnObject
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
@@ -253,11 +225,11 @@ class lnkTriggerAction extends cmdbAbstractObject
{
$aParams = array
(
"category" => "core/cmdb,bizmodel",
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array('action_id', 'trigger_id'),
"reconc_keys" => array(""),
"db_table" => "priv_link_action_trigger",
"db_key_field" => "link_id",
"db_finalclass_field" => "",
@@ -278,35 +250,4 @@ class lnkTriggerAction extends cmdbAbstractObject
MetaModel::Init_SetZListItems('advanced_search', array('action_id', 'trigger_id', 'order')); // Criteria of the advanced search form
}
}
class TriggerOnThresholdReached extends TriggerOnObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,bizmodel",
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"db_table" => "priv_trigger_threshold",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("stop_watch_code", array("allowed_values"=>null, "sql"=>"stop_watch_code", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("threshold_index", array("allowed_values"=>null, "sql"=>"threshold_index", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'stop_watch_code', 'threshold_index', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('target_class', 'threshold_index', 'threshold_index')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
?>

View File

@@ -41,8 +41,6 @@ define('UR_ACTION_BULK_READ', 4); // Export multiple objects
define('UR_ACTION_BULK_MODIFY', 5); // Create/modify multiple objects
define('UR_ACTION_BULK_DELETE', 6); // Delete multiple objects
define('UR_ACTION_CREATE', 7); // Instantiate an object
define('UR_ACTION_APPLICATION_DEFINED', 10000); // Application specific actions (CSV import, View schema...)
/**
@@ -57,7 +55,7 @@ abstract class UserRightsAddOnAPI
abstract public function Init(); // loads data (possible optimizations)
// Used to build select queries showing only objects visible for the given user
abstract public function GetSelectFilter($sLogin, $sClass, $aSettings = array()); // returns a filter object
abstract public function GetSelectFilter($sLogin, $sClass); // returns a filter object
abstract public function IsActionAllowed($oUser, $sClass, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null);
abstract public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, /*dbObjectSet*/ $oInstanceSet = null);
@@ -162,7 +160,8 @@ abstract class User extends cmdbAbstractObject
}
// Check that this user has at least one profile assigned
$oSet = $this->Get('profile_list');
if ($oSet->Count() == 0)
$aProfileLinks = $oSet->ToArray();
if (count($aProfileLinks) == 0)
{
$this->m_aCheckIssues[] = Dict::Format('Class:User/Error:AtLeastOneProfileIsNeeded');
}
@@ -203,7 +202,7 @@ abstract class User extends cmdbAbstractObject
{
if (UserRights::IsStimulusAllowed($sClass, $sStimulusCode, null, $this))
{
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription()).'">'.htmlentities($oStimulus->GetLabel()).'</span>';
}
}
$sStimuli = implode(', ', $aStimuli);
@@ -297,35 +296,6 @@ abstract class UserInternal extends User
}
}
/**
* Self register extension
*
* @package iTopORM
*/
interface iSelfRegister
{
/**
* Called when no user is found in iTop for the corresponding 'name'. This method
* can create/synchronize the User in iTop with an external source (such as AD/LDAP) on the fly
* @param string $sName The typed-in user name
* @param string $sPassword The typed-in password
* @param string $sLoginMode The login method used (cas|form|basic|url)
* @param string $sAuthentication The authentication method used (any|internal|external)
* @return bool true if the user is a valid one, false otherwise
*/
public static function CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication);
/**
* Called after the user has been authenticated and found in iTop. This method can
* Update the user's definition on the fly (profiles...) to keep it in sync with an external source
* @param User $oUser The user to update/synchronize
* @param string $sLoginMode The login mode used (cas|form|basic|url)
* @param string $sAuthentication The authentication method used
* @return void
*/
public static function UpdateUser(User $oUser, $sLoginMode, $sAuthentication);
}
/**
* User management core API
*
@@ -336,7 +306,6 @@ class UserRights
protected static $m_oAddOn;
protected static $m_oUser;
protected static $m_oRealUser;
protected static $m_sSelfRegisterAddOn = null;
public static function SelectModule($sModuleName)
{
@@ -356,15 +325,6 @@ class UserRights
self::$m_oRealUser = null;
}
public static function SelectSelfRegister($sModuleName)
{
if (!class_exists($sModuleName))
{
throw new CoreException("Could not select the class, '$sModuleName' for self register, is not a valid class name");
}
self::$m_sSelfRegisterAddOn = $sModuleName;
}
public static function GetModuleInstance()
{
return self::$m_oAddOn;
@@ -402,38 +362,21 @@ class UserRights
return true;
}
public static function CheckCredentials($sName, $sPassword, $sLoginMode = 'form', $sAuthentication = 'any')
public static function CheckCredentials($sName, $sPassword, $sAuthentication = 'any')
{
$oUser = self::FindUser($sName, $sAuthentication);
if (is_null($oUser))
{
return self::CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication);
return false;
}
if (!$oUser->CheckCredentials($sPassword))
{
return false;
}
self::UpdateUser($oUser, $sLoginMode, $sAuthentication);
return true;
}
public static function CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication)
{
if (self::$m_sSelfRegisterAddOn != null)
{
return call_user_func(array(self::$m_sSelfRegisterAddOn, 'CheckCredentialsAndCreateUser'), $sName, $sPassword, $sLoginMode, $sAuthentication);
}
}
public static function UpdateUser($oUser, $sLoginMode, $sAuthentication)
{
if (self::$m_sSelfRegisterAddOn != null)
{
call_user_func(array(self::$m_sSelfRegisterAddOn, 'UpdateUser'), $oUser, $sLoginMode, $sAuthentication);
}
}
public static function TrustWebServerContext()
{
if (!is_null(self::$m_oUser))
@@ -463,6 +406,18 @@ class UserRights
}
}
public static function CanLogOff()
{
if (!is_null(self::$m_oUser))
{
return self::$m_oUser->CanLogOff();
}
else
{
return false;
}
}
public static function ChangePassword($sOldPassword, $sNewPassword, $sName = '')
{
if (empty($sName))
@@ -649,16 +604,18 @@ class UserRights
return true;
}
public static function GetSelectFilter($sClass, $aSettings = array())
public static function GetSelectFilter($sClass)
{
// When initializing, we need to let everything pass trough
if (!self::CheckLogin()) return true;
if (self::IsAdministrator()) return true;
// Portal users actions are limited by the portal page...
if (self::IsPortalUser()) return true;
if (MetaModel::HasCategory($sClass, 'bizmodel'))
{
return self::$m_oAddOn->GetSelectFilter(self::$m_oUser, $sClass, $aSettings);
return self::$m_oAddOn->GetSelectFilter(self::$m_oUser, $sClass);
}
else
{
@@ -673,21 +630,9 @@ class UserRights
if (MetaModel::DBIsReadOnly())
{
if ($iActionCode == UR_ACTION_CREATE) return false;
if ($iActionCode == UR_ACTION_MODIFY) return false;
if ($iActionCode == UR_ACTION_DELETE) return false;
if ($iActionCode == UR_ACTION_BULK_MODIFY) return false;
if ($iActionCode == UR_ACTION_DELETE) return false;
if ($iActionCode == UR_ACTION_BULK_DELETE) return false;
}
$aPredefinedObjects = call_user_func(array($sClass, 'GetPredefinedObjects'));
if ($aPredefinedObjects != null)
{
// As opposed to the read-only DB, modifying an object is allowed
// (the constant columns will be marked as read-only)
//
if ($iActionCode == UR_ACTION_CREATE) return false;
if ($iActionCode == UR_ACTION_DELETE) return false;
if ($iActionCode == UR_ACTION_BULK_DELETE) return false;
}
@@ -695,16 +640,14 @@ class UserRights
if (MetaModel::HasCategory($sClass, 'bizmodel'))
{
// #@# Temporary?????
// The read access is controlled in MetaModel::MakeSelectQuery()
if ($iActionCode == UR_ACTION_READ) return true;
if (is_null($oUser))
{
$oUser = self::$m_oUser;
}
if ($iActionCode == UR_ACTION_CREATE)
{
// The addons currently DO NOT handle the case "CREATE"
// Therefore it is considered to be equivalent to "MODIFY"
$iActionCode = UR_ACTION_MODIFY;
}
return self::$m_oAddOn->IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet);
}
elseif(($iActionCode == UR_ACTION_READ) && MetaModel::HasCategory($sClass, 'view_in_gui'))
@@ -725,7 +668,10 @@ class UserRights
if (MetaModel::DBIsReadOnly())
{
return false;
if ($iActionCode == UR_ACTION_MODIFY) return false;
if ($iActionCode == UR_ACTION_DELETE) return false;
if ($iActionCode == UR_ACTION_BULK_MODIFY) return false;
if ($iActionCode == UR_ACTION_BULK_DELETE) return false;
}
if (self::IsAdministrator($oUser)) return true;
@@ -874,506 +820,4 @@ class UserRights
}
}
/**
* Helper class to get the number/list of items for which a given action is allowed/possible
*/
class ActionChecker
{
var $oFilter;
var $iActionCode;
var $iAllowedCount = null;
var $aAllowedIDs = null;
public function __construct(DBObjectSearch $oFilter, $iActionCode)
{
$this->oFilter = $oFilter;
$this->iActionCode = $iActionCode;
$this->iAllowedCount = null;
$this->aAllowedIDs = null;
}
/**
* returns the number of objects for which the action is allowed
* @return integer The number of "allowed" objects 0..N
*/
public function GetAllowedCount()
{
if ($this->iAllowedCount == null) $this->CheckObjects();
return $this->iAllowedCount;
}
/**
* If IsAllowed returned UR_ALLOWED_DEPENDS, this methods returns
* an array of ObjKey => Status (true|false)
* @return array
*/
public function GetAllowedIDs()
{
if ($this->aAllowedIDs == null) $this->IsAllowed();
return $this->aAllowedIDs;
}
/**
* Check if the speficied stimulus is allowed for the set of objects
* @return UR_ALLOWED_YES, UR_ALLOWED_NO or UR_ALLOWED_DEPENDS
*/
public function IsAllowed()
{
$sClass = $this->oFilter->GetClass();
$oSet = new DBObjectSet($this->oFilter);
$iActionAllowed = UserRights::IsActionAllowed($sClass, $this->iActionCode, $oSet);
if ($iActionAllowed == UR_ALLOWED_DEPENDS)
{
// Check for each object if the action is allowed or not
$this->aAllowedIDs = array();
$oSet->Rewind();
$this->iAllowedCount = 0;
while($oObj = $oSet->Fetch())
{
$oObjSet = DBObjectSet::FromArray($sClass, array($oObj));
if (UserRights::IsActionAllowed($sClass, $this->iActionCode, $oObjSet) == UR_ALLOWED_NO)
{
$this->aAllowedIDs[$oObj->GetKey()] = false;
}
else
{
// Assume UR_ALLOWED_YES, since there is just one object !
$this->aAllowedIDs[$oObj->GetKey()] = true;
$this->iAllowedCount++;
}
}
}
else if ($iActionAllowed == UR_ALLOWED_YES)
{
$this->iAllowedCount = $oSet->Count();
$this->aAllowedIDs = array(); // Optimization: not filled when Ok for all objects
}
else // UR_ALLOWED_NO
{
$this->iAllowedCount = 0;
$this->aAllowedIDs = array();
}
return $iActionAllowed;
}
}
/**
* Helper class to get the number/list of items for which a given stimulus can be applied (allowed & possible)
*/
class StimulusChecker extends ActionChecker
{
var $sState = null;
public function __construct(DBObjectSearch $oFilter, $sState, $iStimulusCode)
{
parent::__construct($oFilter, $iStimulusCode);
$this->sState = $sState;
}
/**
* Check if the speficied stimulus is allowed for the set of objects
* @return UR_ALLOWED_YES, UR_ALLOWED_NO or UR_ALLOWED_DEPENDS
*/
public function IsAllowed()
{
$sClass = $this->oFilter->GetClass();
if (MetaModel::IsAbstract($sClass)) return UR_ALLOWED_NO; // Safeguard, not implemented if the base class of the set is abstract !
$oSet = new DBObjectSet($this->oFilter);
$iActionAllowed = UserRights::IsStimulusAllowed($sClass, $this->iActionCode, $oSet);
if ($iActionAllowed == UR_ALLOWED_NO)
{
$this->iAllowedCount = 0;
$this->aAllowedIDs = array();
}
else // Even if UR_ALLOWED_YES, we need to check if each object is in the appropriate state
{
// Hmmm, may not be needed right now because we limit the "multiple" action to object in
// the same state... may be useful later on if we want to extend this behavior...
// Check for each object if the action is allowed or not
$this->aAllowedIDs = array();
$oSet->Rewind();
$iAllowedCount = 0;
$iActionAllowed = UR_ALLOWED_DEPENDS;
while($oObj = $oSet->Fetch())
{
$aTransitions = $oObj->EnumTransitions();
if (array_key_exists($this->iActionCode, $aTransitions))
{
// Temporary optimization possible: since the current implementation
// of IsActionAllowed does not perform a 'per instance' check, we could
// skip this second validation phase and assume it would return UR_ALLOWED_YES
$oObjSet = DBObjectSet::FromArray($sClass, array($oObj));
if (!UserRights::IsStimulusAllowed($sClass, $this->iActionCode, $oObjSet))
{
$this->aAllowedIDs[$oObj->GetKey()] = false;
}
else
{
// Assume UR_ALLOWED_YES, since there is just one object !
$this->aAllowedIDs[$oObj->GetKey()] = true;
$this->iState = $oObj->GetState();
$this->iAllowedCount++;
}
}
else
{
$this->aAllowedIDs[$oObj->GetKey()] = false;
}
}
}
if ($this->iAllowedCount == $oSet->Count())
{
$iActionAllowed = UR_ALLOWED_YES;
}
if ($this->iAllowedCount == 0)
{
$iActionAllowed = UR_ALLOWED_NO;
}
return $iActionAllowed;
}
public function GetState()
{
return $this->iState;
}
}
/**
* Self-register extension to allow the automatic creation & update of CAS users
*
* @package iTopORM
*
*/
class CAS_SelfRegister implements iSelfRegister
{
/**
* Called when no user is found in iTop for the corresponding 'name'. This method
* can create/synchronize the User in iTop with an external source (such as AD/LDAP) on the fly
* @param string $sName The CAS authenticated user name
* @param string $sPassword Ignored
* @param string $sLoginMode The login mode used (cas|form|basic|url)
* @param string $sAuthentication The authentication method used
* @return bool true if the user is a valid one, false otherwise
*/
public static function CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication)
{
$bOk = true;
if ($sLoginMode != 'cas') return false; // Must be authenticated via CAS
$sCASMemberships = MetaModel::GetConfig()->Get('cas_memberof');
$bFound = false;
if (!empty($sCASMemberships))
{
if (phpCAS::hasAttribute('memberOf'))
{
// A list of groups is specified, the user must a be member of (at least) one of them to pass
$aCASMemberships = array();
$aTmp = explode(';', $sCASMemberships);
setlocale(LC_ALL, "en_US.utf8"); // !!! WARNING: this is needed to have the iconv //TRANSLIT working fine below !!!
foreach($aTmp as $sGroupName)
{
$aCASMemberships[] = trim(iconv('UTF-8', 'ASCII//TRANSLIT', $sGroupName)); // Just in case remove accents and spaces...
}
$aMemberOf = phpCAS::getAttribute('memberOf');
if (!is_array($aMemberOf)) $aMemberOf = array($aMemberOf); // Just one entry, turn it into an array
$aFilteredGroupNames = array();
foreach($aMemberOf as $sGroupName)
{
phpCAS::log("Info: user if a member of the group: ".$sGroupName);
$sGroupName = trim(iconv('UTF-8', 'ASCII//TRANSLIT', $sGroupName)); // Remove accents and spaces as well
$aFilteredGroupNames[] = $sGroupName;
$bIsMember = false;
foreach($aCASMemberships as $sCASPattern)
{
if (self::IsPattern($sCASPattern))
{
if (preg_match($sCASPattern, $sGroupName))
{
$bIsMember = true;
break;
}
}
else if ($sPattern == $sGroupName)
{
$bIsMember = true;
break;
}
}
if ($bIsMember)
{
$bCASUserSynchro = MetaModel::GetConfig()->Get('cas_user_synchro');
if ($bCASUserSynchro)
{
// If needed create a new user for this email/profile
phpCAS::log('Info: cas_user_synchro is ON');
$bOk = self::CreateCASUser(phpCAS::getUser(), $aMemberOf);
if($bOk)
{
$bFound = true;
}
else
{
phpCAS::log("User ".phpCAS::getUser()." cannot be created in iTop. Logging off...");
}
}
else
{
phpCAS::log('Info: cas_user_synchro is OFF');
$bFound = true;
}
break;
}
}
if($bOk && !$bFound)
{
phpCAS::log("User ".phpCAS::getUser().", none of his/her groups (".implode('; ', $aFilteredGroupNames).") match any of the required groups: ".implode('; ', $aCASMemberships));
}
}
else
{
// Too bad, the user is not part of any of the group => not allowed
phpCAS::log("No 'memberOf' attribute found for user ".phpCAS::getUser().". Are you using the SAML protocol (S1) ?");
}
}
else
{
// No membership required, anybody will pass
$bFound = true;
}
if (!$bFound)
{
// The user is not part of the allowed groups, => log out
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php';
$sCASLogoutUrl = MetaModel::GetConfig()->Get('cas_logout_redirect_service');
if (empty($sCASLogoutUrl))
{
$sCASLogoutUrl = $sUrl;
}
phpCAS::logoutWithRedirectService($sCASLogoutUrl); // Redirects to the CAS logout page
// Will never return !
}
return $bFound;
}
/**
* Called after the user has been authenticated and found in iTop. This method can
* Update the user's definition (profiles...) on the fly to keep it in sync with an external source
* @param User $oUser The user to update/synchronize
* @param string $sLoginMode The login mode used (cas|form|basic|url)
* @param string $sAuthentication The authentication method used
* @return void
*/
public static function UpdateUser(User $oUser, $sLoginMode, $sAuthentication)
{
$bCASUpdateProfiles = MetaModel::GetConfig()->Get('cas_update_profiles');
if (($sLoginMode == 'cas') && $bCASUpdateProfiles && (phpCAS::hasAttribute('memberOf')))
{
$aMemberOf = phpCAS::getAttribute('memberOf');
if (!is_array($aMemberOf)) $aMemberOf = array($aMemberOf); // Just one entry, turn it into an array
return self::SetProfilesFromCAS($oUser, $aMemberOf);
}
// No groups defined in CAS or not CAS at all: do nothing...
return true;
}
/**
* Helper method to create a CAS based user
* @param string $sEmail
* @param array $aGroups
* @return bool true on success, false otherwise
*/
protected static function CreateCASUser($sEmail, $aGroups)
{
if (!MetaModel::IsValidClass('URP_Profiles'))
{
phpCAS::log("URP_Profiles is not a valid class. Automatic creation of Users is not supported in this context, sorry.");
return false;
}
$oUser = MetaModel::GetObjectByName('UserExternal', $sEmail, false);
if ($oUser == null)
{
// Create the user, link it to a contact
phpCAS::log("Info: the user '$sEmail' does not exist. A new UserExternal will be created.");
$oSearch = new DBObjectSearch('Person');
$oSearch->AddCondition('email', $sEmail);
$oSet = new DBObjectSet($oSearch);
$iContactId = 0;
switch($oSet->Count())
{
case 0:
phpCAS::log("Error: found no contact with the email: '$sEmail'. Cannot create the user in iTop.");
return false;
case 1:
$oContact = $oSet->Fetch();
$iContactId = $oContact->GetKey();
phpCAS::log("Info: Found 1 contact '".$oContact->GetName()."' (id=$iContactId) corresponding to the email '$sEmail'.");
break;
default:
phpCAS::log("Error: ".$oSet->Count()." contacts have the same email: '$sEmail'. Cannot create a user for this email.");
return false;
}
$oUser = new UserExternal();
$oUser->Set('login', $sEmail);
$oUser->Set('contactid', $iContactId);
$oUser->Set('language', MetaModel::GetConfig()->GetDefaultLanguage());
}
else
{
phpCAS::log("Info: the user '$sEmail' already exists (id=".$oUser->GetKey().").");
}
// Now synchronize the profiles
if (!self::SetProfilesFromCAS($oUser, $aGroups))
{
return false;
}
else
{
if ($oUser->IsNew() || $oUser->IsModified())
{
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$oMyChange->Set("userinfo", 'CAS/LDAP Synchro');
$oMyChange->DBInsert();
if ($oUser->IsNew())
{
$oUser->DBInsertTracked($oMyChange);
}
else
{
$oUser->DBUpdateTracked($oMyChange);
}
}
return true;
}
}
protected static function SetProfilesFromCAS($oUser, $aGroups)
{
if (!MetaModel::IsValidClass('URP_Profiles'))
{
phpCAS::log("URP_Profiles is not a valid class. Automatic creation of Users is not supported in this context, sorry.");
return false;
}
// read all the existing profiles
$oProfilesSearch = new DBObjectSearch('URP_Profiles');
$oProfilesSet = new DBObjectSet($oProfilesSearch);
$aAllProfiles = array();
while($oProfile = $oProfilesSet->Fetch())
{
$aAllProfiles[strtolower($oProfile->GetName())] = $oProfile->GetKey();
}
// Translate the CAS/LDAP group names into iTop profile names
$aProfiles = array();
$sPattern = MetaModel::GetConfig()->Get('cas_profile_pattern');
foreach($aGroups as $sGroupName)
{
if (preg_match($sPattern, $sGroupName, $aMatches))
{
if (array_key_exists(strtolower($aMatches[1]), $aAllProfiles))
{
$aProfiles[] = $aAllProfiles[strtolower($aMatches[1])];
phpCAS::log("Info: Adding the profile '{$aMatches[1]}' from CAS.");
}
else
{
phpCAS::log("Warning: {$aMatches[1]} is not a valid iTop profile (extracted from group name: '$sGroupName'). Ignored.");
}
}
else
{
phpCAS::log("Info: The CAS group '$sGroupName' does not seem to match an iTop pattern. Ignored.");
}
}
if (count($aProfiles) == 0)
{
phpCAS::log("Info: The user '".$oUser->GetName()."' has no profiles retrieved from CAS. Default profile(s) will be used.");
// Second attempt: check if there is/are valid default profile(s)
$sCASDefaultProfiles = MetaModel::GetConfig()->Get('cas_default_profiles');
$aCASDefaultProfiles = explode(';', $sCASDefaultProfiles);
foreach($aCASDefaultProfiles as $sDefaultProfileName)
{
if (array_key_exists(strtolower($sDefaultProfileName), $aAllProfiles))
{
$aProfiles[] = $aAllProfiles[strtolower($sDefaultProfileName)];
phpCAS::log("Info: Adding the default profile '".$aAllProfiles[strtolower($sDefaultProfileName)]."' from CAS.");
}
else
{
phpCAS::log("Warning: the default profile {$sDefaultProfileName} is not a valid iTop profile. Ignored.");
}
}
if (count($aProfiles) == 0)
{
phpCAS::log("Error: The user '".$oUser->GetName()."' has no profiles in iTop, and therefore cannot be created.");
return false;
}
}
// Now synchronize the profiles
$oProfilesSet = DBObjectSet::FromScratch('URP_UserProfile');
foreach($aProfiles as $iProfileId)
{
$oLink = new URP_UserProfile();
$oLink->Set('profileid', $iProfileId);
$oLink->Set('reason', 'CAS/LDAP Synchro');
$oProfilesSet->AddObject($oLink);
}
$oUser->Set('profile_list', $oProfilesSet);
phpCAS::log("Info: the user '".$oUser->GetName()."' (id=".$oUser->GetKey().") now has the following profiles: '".implode("', '", $aProfiles)."'.");
if ($oUser->IsModified())
{
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$oMyChange->Set("userinfo", 'CAS/LDAP Synchro');
$oMyChange->DBInsert();
if ($oUser->IsNew())
{
$oUser->DBInsertTracked($oMyChange);
}
else
{
$oUser->DBUpdateTracked($oMyChange);
}
}
return true;
}
/**
* Helper function to check if the supplied string is a litteral string or a regular expression pattern
* @param string $sCASPattern
* @return bool True if it's a regular expression pattern, false otherwise
*/
protected static function IsPattern($sCASPattern)
{
if ((substr($sCASPattern, 0, 1) == '/') && (substr($sCASPattern, -1) == '/'))
{
// the string is enclosed by slashes, let's assume it's a pattern
return true;
}
else
{
return false;
}
}
}
// By default enable the 'CAS_SelfRegister' defined above
UserRights::SelectSelfRegister('CAS_SelfRegister');
?>

View File

@@ -60,12 +60,10 @@ abstract class ValueSetDefinition
}
if (strlen($sContains) == 0)
{
// No filtering
$aRet = $this->m_aValues;
}
else
{
// Filter on results containing the needle <sContain>
$aRet = array();
foreach ($this->m_aValues as $sKey=>$sValue)
{
@@ -75,7 +73,6 @@ abstract class ValueSetDefinition
}
}
}
// Sort on the display value
asort($aRet);
return $aRet;
}
@@ -91,76 +88,21 @@ abstract class ValueSetDefinition
*/
class ValueSetObjects extends ValueSetDefinition
{
protected $m_sContains;
protected $m_sFilterExpr; // in OQL
protected $m_sValueAttCode;
protected $m_aOrderBy;
protected $m_aExtraConditions;
private $m_bAllowAllData;
private $m_aModifierProperties;
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false, $aModifierProperties = array())
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false)
{
$this->m_sContains = '';
$this->m_sFilterExpr = $sFilterExp;
$this->m_sValueAttCode = $sValueAttCode;
$this->m_aOrderBy = $aOrderBy;
$this->m_bAllowAllData = $bAllowAllData;
$this->m_aModifierProperties = $aModifierProperties;
$this->m_aExtraConditions = array();
}
public function SetModifierProperty($sPluginClass, $sProperty, $value)
protected function LoadValues($aArgs)
{
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
}
public function AddCondition(DBObjectSearch $oFilter)
{
$this->m_aExtraConditions[] = $oFilter;
}
public function ToObjectSet($aArgs = array(), $sContains = '')
{
if ($this->m_bAllowAllData)
{
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
}
else
{
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
}
foreach($this->m_aExtraConditions as $oExtraFilter)
{
$oFilter->MergeWith($oExtraFilter);
}
foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
{
foreach ($aProperties as $sProperty => $value)
{
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
}
}
return new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
}
public function GetValues($aArgs, $sContains = '')
{
if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains))
{
$this->LoadValues($aArgs, $sContains);
$this->m_bIsLoaded = true;
}
// The results are already filtered and sorted (on friendly name)
$aRet = $this->m_aValues;
return $aRet;
}
protected function LoadValues($aArgs, $sContains = '')
{
$this->m_sContains = $sContains;
$this->m_aValues = array();
if ($this->m_bAllowAllData)
@@ -172,22 +114,6 @@ class ValueSetObjects extends ValueSetDefinition
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
}
if (!$oFilter) return false;
foreach($this->m_aExtraConditions as $oExtraFilter)
{
$oFilter->MergeWith($oExtraFilter);
}
foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
{
foreach ($aProperties as $sProperty => $value)
{
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
}
}
$oValueExpr = new ScalarExpression('%'.$sContains.'%');
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
$oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
$oFilter->AddConditionExpression($oNewCondition);
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
while ($oObject = $oObjects->Fetch())
@@ -208,11 +134,6 @@ class ValueSetObjects extends ValueSetDefinition
{
return 'Filter: '.$this->m_sFilterExpr;
}
public function GetFilterExpression()
{
return $this->m_sFilterExpr;
}
}
@@ -277,7 +198,7 @@ class ValueSetRelatedObjectsFromLinkSet extends ValueSetDefinition
}
// #@# or AddObjectArray($aObjects) ?
$oSetToCreate = DBObjectSet::FromArray($this->m_sTargetLinkClass, $aLinksToCreate);
$this->m_aValues[$oObject->GetKey()] = $oObject->GetName();
$this->m_aValues[$oObject->GetKey()] = $oObject->GetAsHTML($oObject->GetName());
}
return true;
@@ -304,13 +225,6 @@ class ValueSetEnum extends ValueSetDefinition
$this->m_values = $Values;
}
// Helper to export the datat model
public function GetValueList()
{
$this->LoadValues($aArgs = array());
return $this->m_aValues;
}
protected function LoadValues($aArgs)
{
if (is_array($this->m_values))
@@ -336,34 +250,6 @@ class ValueSetEnum extends ValueSetDefinition
}
}
/**
* Fixed set values, defined as a range: 0..59 (with an optional increment)
*
* @package iTopORM
*/
class ValueSetRange extends ValueSetDefinition
{
protected $m_iStart;
protected $m_iEnd;
public function __construct($iStart, $iEnd, $iStep = 1)
{
$this->m_iStart = $iStart;
$this->m_iEnd = $iEnd;
$this->m_iStep = $iStep;
}
protected function LoadValues($aArgs)
{
$iValue = $this->m_iStart;
for($iValue = $this->m_iStart; $iValue <= $this->m_iEnd; $iValue += $this->m_iStep)
{
$this->m_aValues[$iValue] = $iValue;
}
return true;
}
}
/**
* Data model classes

View File

@@ -1,115 +0,0 @@
/* Styles for jQuery menu widget
Author: Maggie Wachs, maggie@filamentgroup.com
Date: September 2008
*/
/* REQUIRED STYLES - the menus will only render correctly with these rules */
.positionHelper { z-index: 2999; }
.fg-menu-container { position: absolute; top:0; left:-999px; padding: .4em; overflow: hidden; }
.fg-menu-container.fg-menu-flyout { overflow: visible; }
.fg-menu, .fg-menu ul { list-style-type:none; padding: 0; margin:0; }
.fg-menu { position:relative; }
.fg-menu-flyout .fg-menu { position:static; }
.fg-menu ul { position:absolute; top:0; }
.fg-menu ul ul { top:-1px; }
.fg-menu-container.fg-menu-ipod .fg-menu-content,
.fg-menu-container.fg-menu-ipod .fg-menu-content ul { background: none !important; }
.fg-menu.fg-menu-scroll,
.fg-menu ul.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
.fg-menu li { clear:both; float:left; width:100%; margin: 0; padding:0; border: 0; }
.fg-menu li li { font-size:1em; } /* inner li font size must be reset so that they don't blow up */
.fg-menu-flyout ul ul { padding: .4em; }
.fg-menu-flyout li { position:relative; }
.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
.fg-menu-breadcrumb { margin: 0; padding: 0; }
.fg-menu-footer { margin-top: .4em; padding: .4em; }
.fg-menu-header { margin-bottom: .4em; padding: .4em; }
.fg-menu-breadcrumb li { float: left; list-style: none; margin: 0; padding: 0 .2em; font-size: .9em; opacity: .7; }
.fg-menu-breadcrumb li.fg-menu-prev-list,
.fg-menu-breadcrumb li.fg-menu-current-crumb { clear: left; float: none; opacity: 1; }
.fg-menu-breadcrumb li.fg-menu-current-crumb { padding-top: .2em; }
.fg-menu-breadcrumb a,
.fg-menu-breadcrumb span { float: left; }
.fg-menu-footer a:link,
.fg-menu-footer a:visited { float:left; width:100%; text-decoration: none; }
.fg-menu-footer a:hover,
.fg-menu-footer a:active { }
.fg-menu-footer a span { float:left; cursor: pointer; }
.fg-menu-breadcrumb .fg-menu-prev-list a:link,
.fg-menu-breadcrumb .fg-menu-prev-list a:visited,
.fg-menu-breadcrumb .fg-menu-prev-list a:hover,
.fg-menu-breadcrumb .fg-menu-prev-list a:active { background-image: none; text-decoration:none; }
.fg-menu-breadcrumb .fg-menu-prev-list a { float: left; padding-right: .4em; }
.fg-menu-breadcrumb .fg-menu-prev-list a .ui-icon { float: left; }
.fg-menu-breadcrumb .fg-menu-current-crumb a:link,
.fg-menu-breadcrumb .fg-menu-current-crumb a:visited,
.fg-menu-breadcrumb .fg-menu-current-crumb a:hover,
.fg-menu-breadcrumb .fg-menu-current-crumb a:active { display:block; background-image:none; font-size:1.3em; text-decoration:none; }
/* REQUIRED LINK STYLES: links are "display:block" by default; if the menu options are split into
selectable node links and 'next' links, the script floats the node links left and floats the 'next' links to the right */
.fg-menu a:link,
.fg-menu a:visited,
.fg-menu a:hover,
.fg-menu a:active { float:left; width:92%; padding:.3em 3%; text-decoration:none; outline: 0 !important; }
.fg-menu a { border: 1px dashed transparent; }
.fg-menu a.ui-state-default:link,
.fg-menu a.ui-state-default:visited,
.fg-menu a.ui-state-default:hover,
.fg-menu a.ui-state-default:active,
.fg-menu a.ui-state-hover:link,
.fg-menu a.ui-state-hover:visited,
.fg-menu a.ui-state-hover:hover,
.fg-menu a.ui-state-hover:active,
.fg-menu a.ui-state-active:link,
.fg-menu a.ui-state-active:visited,
.fg-menu a.ui-state-active:hover,
.fg-menu a.ui-state-active:active { border-style: solid; font-weight: normal; }
.fg-menu a span { display:block; cursor:pointer; }
/* SUGGESTED STYLES - for use with jQuery UI Themeroller CSS */
.fg-menu-indicator span { float:left; }
.fg-menu-indicator span.ui-icon { float:right; }
.fg-menu-content.ui-widget-content,
.fg-menu-content ul.ui-widget-content { border:0; }
/* ICONS AND DIVIDERS */
.fg-menu.fg-menu-has-icons a:link,
.fg-menu.fg-menu-has-icons a:visited,
.fg-menu.fg-menu-has-icons a:hover,
.fg-menu.fg-menu-has-icons a:active { padding-left:20px; }
.fg-menu .horizontal-divider hr, .fg-menu .horizontal-divider span { padding:0; margin:5px .6em; }
.fg-menu .horizontal-divider hr { border:0; height:1px; }
.fg-menu .horizontal-divider span { font-size:.9em; text-transform: uppercase; padding-left:.2em; }

View File

@@ -1,7 +1,8 @@
/* CSS Document */
body {
font-family: Tahoma, Verdana, Arial, Helvetica;
font-family: Tahoma, Verdana, Arial, Helevtica;
font-size: 10pt;
background-color: #fff;
color:#000000;
margin: 0; /* Remove body margin/padding */
padding: 0;
@@ -9,7 +10,7 @@ body {
}
.raw_output {
font-family: Courier-New, Courier, Arial, Helvetica;
font-family: Courier-New, Courier, Arial, Helevtica;
font-size: 8pt;
background-color: #eeeeee;
color: #000000;
@@ -40,14 +41,6 @@ h3 {
color: #EB8F00;
text-decoration: none;
}
table.datatable {
width: 100%;
border: 0;
padding: 0;
}
td.menucontainer {
text-align: right;
}
table.listResults {
padding: 0px;
border-top: 3px solid #f6f6f1;
@@ -66,8 +59,7 @@ table.listContainer {
border: 0;
padding: 0;
margin:0;
width: 100%;
clear: both;
width: 97%;
}
tr.containerHeader, tr.containerHeader td {
@@ -134,9 +126,9 @@ th.headerSortDown {
td {
font-family: Tahoma, Verdana, Arial, Helvetica;
font-size: 12px;
font-size: 8pt;
color:#696969;
nobackground-color: #ffffff;
background-color: #ffffff;
padding: 0px;
}
@@ -147,52 +139,12 @@ tr.clicked td {
}
td.label {
vertical-align: top;
}
td.label span {
font-family: Tahoma, Verdana, Arial, Helvetica;
font-size: 12px;
color: #000000;
padding: 5px;
padding-right: 10px;
font-weight:bold;
vertical-align: top;
text-align: right;
display: block;
}
fieldset td.label span {
padding: 3px;
padding-right: 10px;
}
fieldset {
margin-top: 3px;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
border-style: solid;
border-color: #ddd;
}
legend {
font-family: Tahoma, Verdana, Arial, Helvetica;
font-size: 12px;
padding:8px;
color: #fff;
background-color: #1C94C4;
font-weight: bold;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
}
legend.transparent {
background: transparent;
color: #333333;
font-size: 1em;
font-weight: normal;
padding: 0;
}
.ui-widget-content td legend a, .ui-widget-content td legend a:hover, .ui-widget-content td legend a:visited {
color: #fff;
background-color:#f6f6f6;
padding: 0.25em;
font-weight:bold;
}
.ui-widget-content td a, p a, p a:visited, td a, td a:visited {
@@ -208,7 +160,7 @@ p a:hover, td a:hover {
background: url(../images/mini-arrow-orange.gif) no-repeat left;
}
td a.no-arrow, td a.no-arrow:visited, .SearchDrawer a.no-arrow, .SearchDrawer a.no-arrow:visited {
td a.no-arrow, td a.no-arrow:visited {
text-decoration:none;
color:#000000;
padding-left:0px;
@@ -400,10 +352,6 @@ a.CollapsibleLabel.open, td a.CollapsibleLabel.open {
background-color:#f6f6f1;
padding:5px;
}
/* move up a header immediately following a display block (i.e. "actions" menu) */
.display_block + .page_header {
margin-top: -8px;
}
.notreeview li { background: url(../images/tv-item.gif) 0 0 no-repeat; }
.notreeview .collapsable { background-image: url(../images/tv-collapsable.gif); }
@@ -422,43 +370,34 @@ div.itop_popup {
padding: 0;
float:right;
}
div.itop_popup > ul > li {
list-style: none;
cursor: pointer;
}
div.actions_menu > ul {
div.itop_popup > ul {
height:19px;
line-height: 17px;
vertical-align: middle;
display:block;
nowidth:70px; /* Nasty work-around for IE... en attendant mieux */
width:70px; /* Nasty work-around for IE... en attendant mieux */
padding-left: 5px;
background: url(../images/actions_left.png) no-repeat top left;
cursor: pointer;
margin: 0;
}
div.actions_menu > ul > li {
div.itop_popup > ul > li {
float: left;
list-style: none;
font-size: 11px;
font-family: Tahoma,sans-serif;
height: 17px;
height: 19px;
padding-right: 16px;
padding-left: 4px;
background: url(../images/actions_right.png) no-repeat top right transparent;
font-weight: bold;
color: #fff;
vertical-align: middle;
margin: 0;
}
#logOffBtn > ul > li {
list-style: none;
vertical-align: middle;
margin: 0;
padding: 0;
cursor: pointer;
}
#logOffBtn > ul {
list-style: none;
@@ -489,14 +428,6 @@ div.actions_menu > ul > li {
white-space: nowrap;
background: #fff;
}
.itop_popup ul {
padding-left: 0;
}
.menucontainer div.toolkit_menu {
margin-left: 10px;
}
.itop_popup li a:hover, #logOffBtn li a:hover {
background: #1A4473;
}
@@ -531,9 +462,6 @@ div.actions_menu > ul > li {
color: #fff;
font-weight: bold;
}
.itop_popup > ul {
margin: 0;
}
hr.menu-separator {
border: none 0;
border-top: 1px solid #ccc;;
@@ -810,10 +738,9 @@ p.page-header {
}
td.dashboard {
vertical-align:top;
text-align: center;
border: 1px solid #ccc;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
padding: 10px;
width: 50%;
}
@@ -824,6 +751,7 @@ td.dashboard {
/*** New Lacanau layout ***/
.ui-layout-pane { /* all 'panes' */
background: #FFF;
overflow: auto;
}
@@ -852,7 +780,6 @@ div#right {
}
div#menu {
width: 100%;
overflow: auto;
}
.header-menu {
padding-left: 24px;
@@ -990,382 +917,3 @@ span.form_validation {
width: 95%;
-moz-border-radius: 0.5em;
}
.wiki_broken_link {
text-decoration: line-through;
}
.synoptics, .synoptics tr td {
background: transparent;
padding:10px;
font-size:1em;
vertical-align:middle;
color:#fff;
text-align:center;
}
.synoptics tr td.arrow {
color:#333;
border-top: 1px dashed #333;
width:100px;
}
.synoptics tr.synoptics_header td {
color:#000; font-size:1em;
vertical-align:middle;
text-align:center;
}
.mono_value {
display: inline-block;
background-color: #3c3;
color: #fff;
font-weight:bold;
padding: 3px;
padding-left: 5px;
padding-right: 5px;
margin-left:3px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
}
.multi_values {
display: inline-block;
background-color: #c33;
color: #fff;
font-weight:bold;
padding: 3px;
padding-left: 5px;
padding-right: 5px;
margin-left:3px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
}
.caselog {
overflow-x: hidden;
display: block;
overflow-y: auto;
border: 1px #ddd solid;
font-family: Tahoma, Verdana, Arial, Helvetica;
font-size: 12px;
}
.caselog_input_header {
padding-top:3px;
padding-bottom:3px;
border-top:1px solid #fff;
background: #ddd;
width:100%;
}
.caselog_header {
padding:3px;
border-top:1px solid #fff;
background: #ddd url(../images/plus.gif) left no-repeat;
padding-left: 16px;
cursor: pointer;
width:100%;
}
.caselog_header.open {
background: #ddd url(../images/minus.gif) left no-repeat;
}
.caselog_entry {
padding:3px;
padding-left: 16px;
border-bottom:1px #999 solid;
margin-left:0;
margin-right:0;
white-space: pre-wrap; /* css-3 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+, CSS3 */
}
table.details {
border-collapse: collapse;
noborder-bottom: 2px #fff solid;
width:100%;
}
table.details>tbody>tr>td {
border-bottom: 2px #ddd solid;
padding-bottom: 5px;
padding-top: 3px;
}
fieldset table.details>tbody>tr>td {
padding-top: 3px;
background: transparent;
border: 0;
}
.ac_dlg_loading {
background: white url('../images/indicator.gif') right center no-repeat;
}
table.pagination {
display:inline-block;
}
table.pagination tr td {
padding: 3px;
}
.pagination_container {
padding-left: 3px;
}
.pager {
display:inline-block;
}
.pager p {
margin-top: 0;
margin-bottom: 0;
}
.pager td span {
min-width: 20px;
padding-left: 2px;
padding-right: 2px;
display:inline-block;
text-align: center;
cursor: pointer;
}
.pager td span.curr_page {
color: #fff;
background: #999;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
img.prev, img.first, img.next, img.last {
cursor: pointer;
}
div.actions_button {
float:right;
background: url("../images/actions_left.png") no-repeat scroll left top transparent;
padding-left: 5px;
margin-top: 0;
margin-right: 10px;
height:17px;
vertical-align: middle;
}
div.actions_button a, .actions_button a:hover, .actions_button a:visited {
background:url(../images/actions_bkg.png) no-repeat scroll right top transparent;
color:#fff;
padding-right: 8px;
cursor:pointer;
font-family: Tahoma,sans-serif;
font-size: 11px;
font-weight: bold;
padding-left: 4px;
text-decoration: none;
height:17px;
line-height: 17px;
display: block;
}
select#org_id {
max-width: 90%;
}
/*********** Dashboards ***********/
.itop-dashboard {
background-color: #fff;
}
.dragHover {
background: url(./ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png);
}
.edit_mode .dashlet {
background: url(./ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png);
padding: 5px;
margin:0;
position:relative;
}
.edit_mode .dashlet-selected {
background: #EB8F00 !important;
padding: 5px;
margin:0;
}
td.layout_cell {
height: 50px; /* min-height does not work */
vertical-align: top;
}
.dashlet-content {
background: #fff;
margin:0;
}
table.prop_table {
border-bottom: 2px solid #F9F9F1;
padding: 1px;
width: 100%;
}
.close-box {
margin: 5px;
width: 20px;
height: 20px;
position: absolute;
top: 0;
right: 0;
z-index: 10;
background: transparent url(../images/delete.png) no-repeat center;
}
td.prop_value {
text-align: left;
}
tr.itop-property-field-modified td {
background: #fbb;
}
tr.itop-property-field-modified td.hover {
background: #f99;
}
td.prop_value textarea, td.prop_value input[type=text]{
width: 98%;
}
td.prop_icon {
width: 20px;
}
.dashlet {
text-align:left;
}
.dashlet-inline {
display: inline-block;
}
.dashlet-badge a.actions {
background: none repeat scroll 0 0 transparent;
color: #666666;
font-size: 16px;
text-decoration: none;
}
.dashlet-content .display_block {
text-align:left;
}
.prop_apply .ui-icon-alert {
display: none;
}
.prop_apply .ui-state-error .ui-icon-alert {
display: block;
}
.ui-state-error .ui-icon-circle-check {
display: none;
}
.summary-details {
float: right;
margin-top: 5px;
}
.summary-details th {
background: none repeat scroll 0 0 #CCCCCC;
color: #EEEEEE;
padding: 5px;
text-align: center;
}
.main_header {
background-color: #F1F1F6;
min-height: 60px;
width: 100%;
}
.main_header h1 {
color: #1C94C4;
line-height: 16px;
margin-bottom: 0;
margin-top: 0;
padding-bottom: 10px;
padding-top: 10px;
}
.main_header img {
margin-top: 10px;
margin-right: 10px;
float:left;
}
a.summary, a.summary:hover {
background: none repeat scroll 0 0 transparent;
color: #666666;
text-decoration: none;
padding-left: 0;
}
.summary-details td {
background: none repeat scroll 0 0 transparent;
padding: 5px;
text-align: center;
}
#DashboardMenu > ul > li {
list-style: none;
vertical-align: middle;
margin: 0;
padding: 0;
cursor: pointer;
}
#DashboardMenu > ul {
list-style: none;
vertical-align: middle;
margin: 0;
padding: 0;
height: 25px;
}
#DashboardMenu li a {
display: block;
padding: 5px 12px;
text-decoration: none;
color: #000;
font-weight: bold;
text-align: left;
white-space: nowrap;
background: #fff;
}
#DashboardMenu li span {
display: block;
padding: 5px 12px;
text-decoration: none;
color: #000;
white-space: nowrap;
background: #fff;
}
#DashboardMenu li {
list-style: none;
}
#DashboardMenu li a:hover {
background: #1A4473;
}
#DashboardMenu ul > li > ul
{
border: 1px solid black;
background: #fff;
}
#DashboardMenu li > ul
{ margin: 0;
padding: 0;
position: absolute;
display: none;
border-top: 1px solid white;
z-index: 999;
}
#DashboardMenu li ul li a:hover{
background: #D81515;
color: #fff;
font-weight: bold;
list-style: none;
}
.sortable_field_list {
display: inline-block;
width: 250px;
height: 150px;
border: 1px #333 solid;
overflow: auto;
padding-left: 0;
margin: 0;
}
.sortable_field_list li {
list-style: none;
font-size: 11px;
}
.sort_order {
display: inline-block;
width: 16px;
height: 12px;
}
.sort_none {
background: url(../images/bg.gif) no-repeat center;
}
.sort_asc {
background: url(../images/desc.gif) no-repeat center;
}
.sort_desc {
background: url(../images/asc.gif) no-repeat center;
}
.sort_hidden {
display: none;
}
.sortable_field_list > li.selected {
background: #F6A828;
}

View File

@@ -1,15 +0,0 @@
@CHARSET "UTF-8";
#left-pane { display: none; }
span.ui-layout-resizer { display: none; }
#header-logo { display: none; }
#logo { display: none; }
div.header-menu { display:none; }
div.footer { display:none; }
#top-bar { display: none; }
#menu { display: none; }
div.actions_button { display:none; }
div.itop_popup { display:none; }
div.HRDrawer { display:none; }
div.DrawerHandle { display:none; }
a.tab { display:none; }
div.itop-tab { border: #ccc 1px solid; margin-top: 1em; padding-bottom:1em; }

View File

@@ -1,565 +0,0 @@
/*
* jQuery UI CSS Framework 1.8.17
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Theming/API
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
.ui-helper-clearfix:after { clear: both; }
.ui-helper-clearfix { zoom: 1; }
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*
* jQuery UI CSS Framework 1.8.17
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Theming/API
*
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
*/
/* Component containers
----------------------------------*/
.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; }
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; }
.ui-widget-content a { color: #333333; }
.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
.ui-widget-header a { color: #ffffff; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; }
.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; }
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; }
.ui-widget :active { outline: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; }
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
/* Overlays */
.ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); }
.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*
* jQuery UI Resizable 1.8.17
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Resizable#theming
*/
.ui-resizable { position: relative;}
.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; }
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
* jQuery UI Selectable 1.8.17
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Selectable#theming
*/
.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
/*
* jQuery UI Accordion 1.8.17
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Accordion#theming
*/
/* IE/Win - Fix animation bug - #4615 */
.ui-accordion { width: 100%; }
.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
.ui-accordion .ui-accordion-li-fix { display: inline; }
.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
.ui-accordion .ui-accordion-content-active { display: block; }
/*
* jQuery UI Autocomplete 1.8.17
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Autocomplete#theming
*/
.ui-autocomplete { position: absolute; cursor: default; }
/* workarounds */
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
/*
* jQuery UI Menu 1.8.17
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Menu#theming
*/
.ui-menu {
list-style:none;
padding: 2px;
margin: 0;
display:block;
float: left;
}
.ui-menu .ui-menu {
margin-top: -3px;
}
.ui-menu .ui-menu-item {
margin:0;
padding: 0;
zoom: 1;
float: left;
clear: left;
width: 100%;
}
.ui-menu .ui-menu-item a {
text-decoration:none;
display:block;
padding:.2em .4em;
line-height:1.5;
zoom:1;
}
.ui-menu .ui-menu-item a.ui-state-hover,
.ui-menu .ui-menu-item a.ui-state-active {
font-weight: normal;
margin: -1px;
}
/*
* jQuery UI Button 1.8.17
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Button#theming
*/
.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
.ui-button-icons-only { width: 3.4em; }
button.ui-button-icons-only { width: 3.7em; }
/*button text element */
.ui-button .ui-button-text { display: block; line-height: 1.4; }
.ui-button-text-only .ui-button-text { padding: .4em 1em; }
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
/* no icon support for input elements, provide padding by default */
input.ui-button { padding: .4em 1em; }
/*button icon element(s) */
.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
/*button sets*/
.ui-buttonset { margin-right: 7px; }
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
/* workarounds */
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
/*
* jQuery UI Dialog 1.8.17
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Dialog#theming
*/
.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
.ui-draggable .ui-dialog-titlebar { cursor: move; }
/*
* jQuery UI Slider 1.8.17
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Slider#theming
*/
.ui-slider { position: relative; text-align: left; }
.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
.ui-slider-horizontal { height: .8em; }
.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
.ui-slider-horizontal .ui-slider-range-min { left: 0; }
.ui-slider-horizontal .ui-slider-range-max { right: 0; }
.ui-slider-vertical { width: .8em; height: 100px; }
.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
* jQuery UI Tabs 1.8.17
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Tabs#theming
*/
.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
.ui-tabs .ui-tabs-hide { display: none !important; }
/*
* jQuery UI Datepicker 1.8.17
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Datepicker#theming
*/
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
display: none; /*sorry for IE5*/
display/**/: block; /*sorry for IE5*/
position: absolute; /*must have*/
z-index: -1; /*must have*/
filter: mask(); /*must have*/
top: -4px; /*must have*/
left: -4px; /*must have*/
width: 200px; /*must have*/
height: 200px; /*must have*/
}/*
* jQuery UI Progressbar 1.8.17
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Progressbar#theming
*/
.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }

View File

@@ -1,28 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
Dict::Add('FR FR', 'French', 'Français', array(
'Class:UserExternal' => 'Utilisateur externe à iTop',
'Class:UserExternal+' => 'Utilisateur authentifié à l\'extérieur d\'iTop',
));
?>

View File

@@ -1,25 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:UserExternal' => 'Külső felhasználó',
'Class:UserExternal+' => '',
));
?>

View File

@@ -1,25 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:UserExternal' => 'Usuário externo',
'Class:UserExternal+' => '',
));
?>

View File

@@ -1,30 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
Dict::Add('FR FR', 'French', 'Français', array(
'Class:UserLDAP' => 'Utilisateur LDAP',
'Class:UserLDAP+' => 'Utilisateur authentifié par un serveur LDAP',
'Class:UserLDAP/Attribute:password' => 'Mot de passe LDAP',
'Class:UserLDAP/Attribute:password+' => '',
));
?>

View File

@@ -1,27 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:UserLDAP' => 'LDAP felhasználó',
'Class:UserLDAP+' => '',
'Class:UserLDAP/Attribute:password' => 'Jelszó',
'Class:UserLDAP/Attribute:password+' => '',
));
?>

View File

@@ -1,27 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:UserLDAP' => 'Usuário externo',
'Class:UserLDAP+' => '',
'Class:UserLDAP/Attribute:password' => 'Senha',
'Class:UserLDAP/Attribute:password+' => '',
));
?>

View File

@@ -1,30 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
Dict::Add('FR FR', 'French', 'Français', array(
'Class:UserLocal' => 'Utilisateur iTop',
'Class:UserLocal+' => 'Utilisateur authentifié par iTop',
'Class:UserLocal/Attribute:password' => 'Mot de passe',
'Class:UserLocal/Attribute:password+' => '',
));
?>

View File

@@ -1,27 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:UserLocal' => 'iTop felhasználó',
'Class:UserLocal+' => '',
'Class:UserLocal/Attribute:password' => 'Jelszó',
'Class:UserLocal/Attribute:password+' => '',
));
?>

View File

@@ -1,50 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Localized data
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @author Hirofumi Kosaka <kosaka@rworks.jp>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: UserLocal
//
Dict::Add('JA JP', 'Japanese', '日本語', array(
'Class:UserLocal' => 'iTopユーザー', // 'iTop user',
'Class:UserLocal+' => 'iTopローカル認証ユーザー', // 'User authentified by iTop',
'Class:UserLocal/Attribute:password' => 'パスワード', // 'Password',
'Class:UserLocal/Attribute:password+' => '認証文字列', // 'user authentication string',
));
?>

View File

@@ -1,27 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:UserLocal' => 'Usuário local',
'Class:UserLocal+' => '',
'Class:UserLocal/Attribute:password' => 'Senha',
'Class:UserLocal/Attribute:password+' => '',
));
?>

View File

@@ -1,126 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<installation>
<steps type="array">
<step>
<title>Configuration Management options</title>
<description><![CDATA[<h2>The options below allow you to configure the type of elements that are to be managed inside iTop.</h2>]]></description>
<banner>/images/modules.png</banner>
<options type="array">
<choice>
<title>Configuration Management Base</title>
<description>This module is always installed, it contains all the base objects that are mandatory in the iTop CMDB: Organizations, Locations, Teams, Persons, etc.</description>
<modules type="array">
<module>itop-config-mgmt</module>
<module>itop-profiles</module>
<module>itop-welcome-itil</module>
</modules>
<mandatory>true</mandatory>
</choice>
<choice>
<title>End-User Devices</title>
<description>This optional module manages end-user devices like Phones, Printers, Desktop PCs.</description>
<modules type="array">
<module>cmdb-end-user</module>
</modules>
</choice>
<choice>
<title>Data Center Management</title>
<description>This optional modules manages data center devices like Power Supplies, Racks, Enclosures.</description>
<default>true</default>
<modules type="array">
<module>cmdb-datacenter</module>
</modules>
</choice>
</options>
</step>
<step>
<title>Service Management options</title>
<description><![CDATA[<h2>Select the choice that best describes the relationships between the services and the IT infrastructure in your IT environment.</h2>]]></description>
<banner>./wizard_icons/service.png</banner>
<alternatives type="array">
<choice>
<title>Service Management for Enterprises</title>
<description>Select this option if the IT delivers services based on a shared infrastructure. For example if different organizations within your company subscribe to services (like Mail and Print services) delivered by a single shared backend.</description>
<modules type="array">
<module>itop-service-mgmt-enterprise</module>
</modules>
<default>true</default>
</choice>
<choice>
<title>Service Management for Service Providers</title>
<description>Select this option if the IT manages the infrastructure of independent customers. This is the most flexible model, since the services can be delivered with a mix of shared and customer specific infrastructure devices.</description>
<modules type="array">
<module>itop-service-mgmt-provider</module>
</modules>
</choice>
</alternatives>
</step>
<step>
<title>Incident Management options</title>
<description>Select the type of tickets you want to use in order to respond to user requests and incidents.</description>
<banner></banner>
<alternatives type="array">
<choice>
<title>Simple Ticket Management</title>
<description>Select this option to use one single type of tickets for all kind of requests.</description>
<modules type="array">
<module>itop-simple-tickets</module>
</modules>
<default>true</default>
</choice>
<choice>
<title>ITIL Compliant Tickets Management</title>
<description>Select this option to have different types of ticket for managing user requests and incidents.</description>
<modules type="array">
<module>itop-itil-tickets</module>
</modules>
<sub_options>
<options type="array">
<choice>
<title>Problem Management</title>
<description>Manage problem ticket to solve recurring incidents.</description>
<modules type="array">
<module>itop-problem-management</module>
</modules>
</choice>
<choice>
<title>Known Error Database</title>
<description>Manage Known Error tickets to document the possible root causes of incidents.</description>
<modules type="array">
<module>itop-kedb-management</module>
</modules>
</choice>
</options>
</sub_options>
</choice>
<choice>
<title>None</title>
<description>Don't manage incidents in iTop</description>
<modules type="array">
</modules>
</choice>
</alternatives>
</step>
<step>
<title>Change Management options</title>
<description><![CDATA[<h2>Select the type of tickets you want to use in order to manage changes to the IT infrastructure.</h2>]]></description>
<banner>./itop-change-mgmt-1.0.0/images/change.png</banner>
<alternatives type="array">
<choice>
<title>ITIL Change Management</title>
<description>Select this option to use Normal/Routine/Emergency change tickets.</description>
<modules type="array">
<module>itop-change-mgmt</module>
</modules>
<default>true</default>
</choice>
<choice>
<title>None</title>
<description>Don't manage changes in iTop</description>
<modules type="array">
</modules>
</choice>
</alternatives>
</step>
</steps>
</installation>

View File

@@ -1,108 +0,0 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Handles various ajax requests
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../../approot.inc.php');
require_once(APPROOT.'/application/application.inc.php');
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/ajaxwebpage.class.inc.php');
try
{
require_once(APPROOT.'/application/startup.inc.php');
// require_once(APPROOT.'/application/user.preferences.class.inc.php');
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(false /* bMustBeAdmin */, true /* IsAllowedToPortalUsers */); // Check user rights and prompt if needed
$oPage = new ajax_page("");
$oPage->no_cache();
$sOperation = utils::ReadParam('operation', '');
switch($sOperation)
{
case 'add':
$aResult = array(
'error' => '',
'att_id' => 0,
'msg' => ''
);
$sObjClass = stripslashes(utils::ReadParam('obj_class', '', false, 'class'));
$sTempId = utils::ReadParam('temp_id', '');
if (empty($sObjClass))
{
$aResult['error'] = "Missing argument 'obj_class'";
}
elseif (empty($sTempId))
{
$aResult['error'] = "Missing argument 'temp_id'";
}
else
{
try
{
$oDoc = utils::ReadPostedDocument('file');
$oAttachment = MetaModel::NewObject('Attachment');
$oAttachment->Set('expire', time() + 3600); // one hour...
$oAttachment->Set('temp_id', $sTempId);
$oAttachment->Set('item_class', $sObjClass);
$oAttachment->SetDefaultOrgId();
$oAttachment->Set('contents', $oDoc);
$iAttId = $oAttachment->DBInsert();
$aResult['msg'] = $oDoc->GetFileName();
$aResult['icon'] = utils::GetAbsoluteUrlAppRoot().AttachmentPlugIn::GetFileIcon($oDoc->GetFileName());
$aResult['att_id'] = $iAttId;
}
catch (FileUploadException $e)
{
$aResult['error'] = $e->GetMessage();
}
}
$oPage->add(json_encode($aResult));
break;
case 'remove':
$iAttachmentId = utils::ReadParam('att_id', '');
$oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE id = :id");
$oSet = new DBObjectSet($oSearch, array(), array('id' => $iAttachmentId));
while ($oAttachment = $oSet->Fetch())
{
$oAttachment->DBDelete();
}
break;
default:
$oPage->p("Missing argument 'operation'");
}
$oPage->output();
}
catch (Exception $e)
{
echo $e->GetMessage();
IssueLog::Error($e->getMessage());
}
?>

View File

@@ -1,191 +0,0 @@
jQuery.extend(
{
createUploadIframe: function(id, uri)
{
//create frame
var frameId = 'jUploadFrame' + id;
var iframeHtml = '<iframe id="' + frameId + '" name="' + frameId + '" style="position:absolute; top:-9999px; left:-9999px"';
if(window.ActiveXObject)
{
if(typeof uri== 'boolean')
{
iframeHtml += ' src="' + 'javascript:false' + '"';
}
else if(typeof uri== 'string')
{
iframeHtml += ' src="' + uri + '"';
}
}
iframeHtml += ' />';
jQuery(iframeHtml).appendTo(document.body);
return jQuery('#' + frameId).get(0);
},
createUploadForm: function(id, fileElementId)
{
//create form
var formId = 'jUploadForm' + id;
var fileId = 'jUploadFile' + id;
var form = jQuery('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');
var oldElement = jQuery('#' + fileElementId);
var newElement = jQuery(oldElement).clone();
jQuery(oldElement).attr('id', fileId);
jQuery(oldElement).before(newElement);
jQuery(oldElement).appendTo(form);
//set attributes
jQuery(form).css('position', 'absolute');
jQuery(form).css('top', '-1200px');
jQuery(form).css('left', '-1200px');
jQuery(form).appendTo('body');
return form;
},
ajaxFileUpload: function(s) {
// TODO introduce global settings, allowing the client to modify them for all requests, not only timeout
s = jQuery.extend({}, jQuery.ajaxSettings, s);
var id = new Date().getTime();
var form = jQuery.createUploadForm(id, s.fileElementId);
var io = jQuery.createUploadIframe(id, s.secureuri);
var frameId = 'jUploadFrame' + id;
var formId = 'jUploadForm' + id;
// Watch for a new set of requests
if ( s.global && ! jQuery.active++ )
{
jQuery.event.trigger( "ajaxStart" );
}
var requestDone = false;
// Create the request object
var xml = {};
if ( s.global )
jQuery.event.trigger("ajaxSend", [xml, s]);
// Wait for a response to come back
var uploadCallback = function(isTimeout)
{
var io = document.getElementById(frameId);
try
{
if(io.contentWindow)
{
xml.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
xml.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
}else if(io.contentDocument)
{
xml.responseText = io.contentDocument.document.body?io.contentDocument.document.body.innerHTML:null;
xml.responseXML = io.contentDocument.document.XMLDocument?io.contentDocument.document.XMLDocument:io.contentDocument.document;
}
}
catch(e)
{
jQuery.handleError(s, xml, null, e);
}
if ( xml || isTimeout == "timeout")
{
requestDone = true;
var status;
try {
status = isTimeout != "timeout" ? "success" : "error";
// Make sure that the request was successful or notmodified
if ( status != "error" )
{
// process the data (runs the xml through httpData regardless of callback)
var data = jQuery.uploadHttpData( xml, s.dataType );
// If a local callback was specified, fire it and pass it the data
if ( s.success )
s.success( data, status );
// Fire the global callback
if( s.global )
jQuery.event.trigger( "ajaxSuccess", [xml, s] );
} else
jQuery.handleError(s, xml, status);
} catch(e)
{
status = "error";
jQuery.handleError(s, xml, status, e);
}
// The request was completed
if( s.global )
jQuery.event.trigger( "ajaxComplete", [xml, s] );
// Handle the global AJAX counter
if ( s.global && ! --jQuery.active )
jQuery.event.trigger( "ajaxStop" );
// Process result
if ( s.complete )
s.complete(xml, status);
jQuery(io).unbind();
setTimeout(function()
{ try
{
jQuery(io).remove();
jQuery(form).remove();
} catch(e)
{
jQuery.handleError(s, xml, null, e);
}
}, 100)
xml = null
}
}
// Timeout checker
if ( s.timeout > 0 )
{
setTimeout(function(){
// Check to see if the request is still happening
if( !requestDone ) uploadCallback( "timeout" );
}, s.timeout);
}
try
{
var form = jQuery('#' + formId);
jQuery(form).attr('action', s.url);
jQuery(form).attr('method', 'POST');
jQuery(form).attr('target', frameId);
if(form.encoding)
{
jQuery(form).attr('encoding', 'multipart/form-data');
}
else
{
jQuery(form).attr('enctype', 'multipart/form-data');
}
jQuery(form).submit();
} catch(e)
{
jQuery.handleError(s, xml, null, e);
}
jQuery('#' + frameId).load(uploadCallback );
return {abort: function () {}};
},
uploadHttpData: function( r, type ) {
var data = !type;
data = type == "xml" || data ? r.responseXML : r.responseText;
// If the type is "script", eval it in global context
if ( type == "script" )
jQuery.globalEval( data );
// Get the JavaScript object, if JSON is used.
if ( type == "json" )
eval( "data = " + data );
// evaluate scripts within html
if ( type == "html" )
jQuery("<div>").html(data).evalScripts();
return data;
}
})

Some files were not shown because too many files have changed in this diff Show More