diff --git a/application/template.class.inc.php b/application/template.class.inc.php index 6436dfc52..20d57620c 100644 --- a/application/template.class.inc.php +++ b/application/template.class.inc.php @@ -16,7 +16,7 @@ class DisplayTemplate public function Render(web_page $oPage, $aParams = array()) { - $this->ApplyParams($aParams); + $this->m_sTemplate = MetaModel::ApplyParams($this->m_sTemplate, $aParams); $iStart = 0; $iEnd = strlen($this->m_sTemplate); $iCount = 0; @@ -40,21 +40,6 @@ class DisplayTemplate $oPage->add(substr($this->m_sTemplate, $iAfterTagPos)); } - /** - * Replaces all the parameters by the values passed in the hash array - */ - public function ApplyParams($aParams) - { - $aSearches = array(); - $aReplacements = array(); - foreach($aParams as $sSearch => $sReplace) - { - $aSearches[] = '$'.$sSearch.'$'; - $aReplacements[] = $sReplace; - } - $this->m_sTemplate = str_replace($aSearches, $aReplacements, $this->m_sTemplate); - } - public function GetNextTag(&$iStartPos, &$iEndPos) { $iChunkStartPos = $iStartPos; diff --git a/business/itop.business.class.inc.php b/business/itop.business.class.inc.php index 1ce270925..ceda3e8e2 100644 --- a/business/itop.business.class.inc.php +++ b/business/itop.business.class.inc.php @@ -200,7 +200,7 @@ class bizContact extends logRealObject MetaModel::Init_Params($aParams); MetaModel::Init_InheritAttributes(); MetaModel::Init_AddAttribute(new AttributeExternalField("org_name", array("label"=>"Organization", "description"=>"Company / Department of the contact", "allowed_values"=>null, "extkey_attcode"=> 'org_id', "target_attcode"=>"name"))); - MetaModel::Init_AddAttribute(new AttributeString("email", array("label"=>"eMail", "description"=>"Email address", "allowed_values"=>null, "sql"=>"email", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEmailAddress("email", array("label"=>"eMail", "description"=>"Email address", "allowed_values"=>null, "sql"=>"email", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("phone", array("label"=>"Phone", "description"=>"Telephone", "allowed_values"=>null, "sql"=>"telephone", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("location_id", array("targetclass"=>"bizLocation", "label"=>"Location", "description"=>"Id of the location where the contact is located", "allowed_values"=>null, "sql"=>"location_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeExternalField("location_name", array("label"=>"Location Name", "description"=>"Name of the location where the contact is located", "allowed_values"=>null, "extkey_attcode"=> 'location_id', "target_attcode"=>"name"))); diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index 6f920f7bc..c73479268 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -547,7 +547,7 @@ class AttributeString extends AttributeDBField } public function ScalarToSQL($value) { - if (!is_string($value)) + if (!is_string($value) && !is_null($value)) { throw new CoreWarning('Expected the attribute value to be a string', array('found_type' => gettype($value), 'value' => $value, 'class' => $this->GetCode(), 'attribute' => $this->GetHostClass())); } @@ -615,6 +615,66 @@ class AttributeText extends AttributeString } } +/** + * Specialization of a string: email + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeEmailAddress extends AttributeString +{ + public function GetTypeDesc() {return "Email address(es)";} +} + +/** + * Specialization of a string: OQL expression + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeOQL extends AttributeString +{ + public function GetTypeDesc() {return "OQL expression";} +} + +/** + * Specialization of a string: template + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeTemplateString extends AttributeString +{ + public function GetTypeDesc() {return "Template string";} +} + +/** + * Specialization of a text: template + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeTemplateText extends AttributeText +{ + public function GetTypeDesc() {return "Multiline template string";} +} + /** * Map a enum column to an attribute * diff --git a/core/cmdbobject.class.inc.php b/core/cmdbobject.class.inc.php index 79b448071..997f605d4 100644 --- a/core/cmdbobject.class.inc.php +++ b/core/cmdbobject.class.inc.php @@ -37,9 +37,19 @@ require_once('dbobject.class.php'); require_once('dbobjectsearch.class.php'); require_once('dbobjectset.class.php'); +// db change tracking data model require_once('cmdbchange.class.inc.php'); require_once('cmdbchangeop.class.inc.php'); +// customization data model +// Romain: temporary moved into application.inc.php (see explanations there) +//require_once('trigger.class.inc.php'); +//require_once('action.class.inc.php'); + +// application log +// Romain: temporary moved into application.inc.php (see explanations there) +//require_once('event.class.inc.php'); + require_once('csvparser.class.inc.php'); require_once('bulkchange.class.inc.php'); diff --git a/core/config.class.inc.php b/core/config.class.inc.php index 6d6e5e982..aa7aa5289 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -289,6 +289,14 @@ class Config fwrite($hFile, "\t'application' => array (\n"); fwrite($hFile, "\t\t'../application/menunode.class.inc.php',\n"); fwrite($hFile, "\t\t'../application/audit.rule.class.inc.php',\n"); +// 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 +// to create the tables. + fwrite($hFile, "\t\t'../core/event.class.inc.php',\n"); + fwrite($hFile, "\t\t'../core/action.class.inc.php',\n"); + fwrite($hFile, "\t\t'../core/trigger.class.inc.php',\n"); fwrite($hFile, "\t\t// to be continued...\n"); fwrite($hFile, "\t),\n"); fwrite($hFile, "\t'business' => array (\n"); diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 45b02c0c1..d309ca4db 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -611,7 +611,7 @@ abstract class DBObject if (!empty($this->m_iKey) && ($this->m_iKey >= 0)) { // Add it to the list of fields to write - $aFieldsToWrite[] = MetaModel::DBGetKey($sTableClass); + $aFieldsToWrite[] = '`'.MetaModel::DBGetKey($sTableClass).'`'; $aValuesToWrite[] = CMDBSource::Quote($this->m_iKey); } @@ -622,7 +622,7 @@ abstract class DBObject $aAttColumns = $oAttDef->GetSQLValues($this->m_aCurrValues[$sAttCode]); foreach($aAttColumns as $sColumn => $sValue) { - $aFieldsToWrite[] = $sColumn; + $aFieldsToWrite[] = "`$sColumn`"; $aValuesToWrite[] = CMDBSource::Quote($sValue); } } @@ -803,7 +803,9 @@ abstract class DBObject // Change the state before proceeding to the actions, this is necessary because an action might // trigger another stimuli (alternative: push the stimuli into a queue) - $this->Set($sStateAttCode, $aTransitionDef['target_state']); + $sPreviousState = $this->Get($sStateAttCode); + $sNewState = $aTransitionDef['target_state']; + $this->Set($sStateAttCode, $sNewState); // $aTransitionDef is an // array('target_state'=>..., 'actions'=>array of handlers procs, 'user_restriction'=>TBD @@ -824,9 +826,39 @@ abstract class DBObject if (!$bRet) $bSuccess = false; } + // Change state triggers... + $sClass = get_class($this); + $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateLeave AS t WHERE t.target_class='$sClass' AND t.state='$sPreviousState'")); + while ($oTrigger = $oSet->Fetch()) + { + $oTrigger->DoActivate($this->ToArgs('this')); + } + + $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateEnter AS t WHERE t.target_class='$sClass' AND t.state='$sNewState'")); + while ($oTrigger = $oSet->Fetch()) + { + $oTrigger->DoActivate($this->ToArgs('this')); + } + return $bSuccess; } + // Make standard context arguments + public function ToArgs($sArgName) + { + $aScalarArgs = array(); + $aScalarArgs[$sArgName] = $this->GetKey(); + $aScalarArgs[$sArgName.'->id'] = $this->GetKey(); + + $sClass = get_class($this); + foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) + { + $aScalarArgs[$sArgName.'->'.$sAttCode] = $this->Get($sAttCode); + } + return $aScalarArgs; + } + + // Return an empty set for the parent of all public static function GetRelationQueries($sRelCode) { diff --git a/core/metamodel.class.php b/core/metamodel.class.php index c40bc220b..c54e828f9 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -1222,14 +1222,7 @@ abstract class MetaModel { if (self::IsValidObject($value)) { - $aScalarArgs[$sArgName] = $value->GetKey(); - $aScalarArgs[$sArgName.'->id'] = $value->GetKey(); - - $sClass = get_class($value); - foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) - { - $aScalarArgs[$sArgName.'->'.$sAttCode] = $value->Get($sAttCode); - } + $aScalarArgs = array_merge($aScalarArgs, $value->ToArgs($sArgName)); } else { @@ -2849,6 +2842,21 @@ abstract class MetaModel return self::GetLabel($sLinkClass, $sAttCode); } + /** + * Replaces all the parameters by the values passed in the hash array + */ + static public function ApplyParams($aInput, $aParams) + { + $aSearches = array(); + $aReplacements = array(); + foreach($aParams as $sSearch => $sReplace) + { + $aSearches[] = '$'.$sSearch.'$'; + $aReplacements[] = $sReplace; + } + return str_replace($aSearches, $aReplacements, $aInput); + } + } // class MetaModel diff --git a/pages/schema.php b/pages/schema.php index b7162f5f4..1162f1ecd 100644 --- a/pages/schema.php +++ b/pages/schema.php @@ -231,6 +231,16 @@ function DisplayLifecycle($oPage, $sClass) } +/** + * Helper for the trigger + */ +function DisplayTriggers($oPage, $sClass) +{ + $oSet = new CMDBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateChange WHERE target_class = '$sClass'")); + cmdbAbstractObject::DisplaySet($oPage, $oSet); +} + + /** * Display the list of classes from the business model */ @@ -402,6 +412,9 @@ function DisplayClassDetails($oPage, $sClass) $oPage->SetCurrentTab('Lifecycle'); DisplayLifecycle($oPage, $sClass); + $oPage->SetCurrentTab('Triggers'); + DisplayTriggers($oPage, $sClass); + $oPage->SetCurrentTab(); $oPage->SetCurrentTabContainer(); } diff --git a/setup/data/structure/1.menus.xml b/setup/data/structure/1.menus.xml index df61e6cb1..7c78a33e0 100644 --- a/setup/data/structure/1.menus.xml +++ b/setup/data/structure/1.menus.xml @@ -918,4 +918,83 @@ text-align:left; 0 0 + +Customization + +UI.php + + +administrator +2 +1 +0 + + +Triggers - entering + +UI.php +../images/std_view.gif + +administrator +2 +500 +0 + + +Triggers - leaving + +UI.php +../images/std_view.gif + +administrator +2 +500 +0 + + +Actions + +UI.php +../images/std_view.gif + +administrator +2 +500 +0 + + +Application log + +UI.php +../images/std_view.gif + +administrator +2 +1 +0 +