mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-25 19:48:49 +02:00
@@ -64,39 +64,14 @@ abstract class cmdbAbstractObject extends CMDBObject
|
||||
return $sPage;
|
||||
}
|
||||
|
||||
protected static function MakeHyperLink($sObjClass, $sObjKey, $aAvailableFields)
|
||||
protected static function MakeHyperLink($sObjClass, $sObjKey, $sLabel = '')
|
||||
{
|
||||
if ($sObjKey <= 0) return '<em>'.Dict::S('UI:UndefinedObject').'</em>'; // Objects built in memory have negative IDs
|
||||
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sExtClassNameAtt = MetaModel::GetNameAttributeCode($sObjClass);
|
||||
$sPage = self::ComputeUIPage($sObjClass);
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlPath();
|
||||
|
||||
// Use the "name" of the target class as the label of the hyperlink
|
||||
// unless it's not available in the external attributes...
|
||||
if (isset($aAvailableFields[$sExtClassNameAtt]))
|
||||
{
|
||||
$sLabel = $aAvailableFields[$sExtClassNameAtt];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLabel = implode(' / ', $aAvailableFields);
|
||||
}
|
||||
// Safety belt
|
||||
//
|
||||
if (empty($sLabel))
|
||||
{
|
||||
// Developer's note:
|
||||
// This is doing the job for you, but that is just there in case
|
||||
// the external fields associated to the external key are blanks
|
||||
// The ultimate solution will be to query the name automatically
|
||||
// and independantly from the data model (automatic external field)
|
||||
// AND make the name be a mandatory field
|
||||
//
|
||||
$sObject = MetaModel::GetObject($sObjClass, $sObjKey);
|
||||
$sLabel = $sObject->GetName();
|
||||
}
|
||||
// Safety net
|
||||
//
|
||||
if (empty($sLabel))
|
||||
@@ -365,10 +340,9 @@ abstract class cmdbAbstractObject extends CMDBObject
|
||||
if (!empty($sTemplate))
|
||||
{
|
||||
$oTemplate = new DisplayTemplate($sTemplate);
|
||||
$sNameAttCode = MetaModel::GetNameAttributeCode(get_class($this));
|
||||
// Note: to preserve backward compatibility with home-made templates, the placeholder '$pkey$' has been preserved
|
||||
// but the preferred method is to use '$id$'
|
||||
$oTemplate->Render($oPage, array('class_name'=> MetaModel::GetName(get_class($this)),'class'=> get_class($this), 'pkey'=> $this->GetKey(), 'id'=> $this->GetKey(), 'name' => $this->Get($sNameAttCode)));
|
||||
$oTemplate->Render($oPage, array('class_name'=> MetaModel::GetName(get_class($this)),'class'=> get_class($this), 'pkey'=> $this->GetKey(), 'id'=> $this->GetKey(), 'name' => $this->Get('friendlyname')));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -66,7 +66,7 @@ class UILinksWidget
|
||||
{
|
||||
// State attribute is always hidden from the UI
|
||||
}
|
||||
else if (!$oAttDef->IsExternalField() && ($sAttCode != $sExtKeyToMe) && ($sAttCode != $this->m_sExtKeyToRemote) && ($sAttCode != 'finalclass'))
|
||||
else if ($oAttDef->IsWritable() && ($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) )
|
||||
@@ -239,93 +239,6 @@ EOF
|
||||
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);
|
||||
|
||||
@@ -417,7 +417,7 @@ class AttributeDBFieldVoid extends AttributeDefinition
|
||||
public function GetSQLExpressions()
|
||||
{
|
||||
$aColumns = array();
|
||||
// Note: to optimize things, the existence of the attribute is determine by the existence of one column with an empty suffix
|
||||
// Note: to optimize things, the existence of the attribute is determined by the existence of one column with an empty suffix
|
||||
$aColumns[''] = $this->Get("sql");
|
||||
return $aColumns;
|
||||
}
|
||||
@@ -934,6 +934,7 @@ class AttributeFinalClass extends AttributeString
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Map a varchar column (size < ?) to an attribute that must never be shown to the user
|
||||
*
|
||||
@@ -1753,7 +1754,6 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
{
|
||||
return $this->GetOptional('allow_target_creation', MetaModel::GetConfig()->Get('allow_target_creation'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1776,6 +1776,11 @@ class AttributeExternalField extends AttributeDefinition
|
||||
return $oExtAttDef->GetSQLCol();
|
||||
}
|
||||
|
||||
public function GetSQLExpressions()
|
||||
{
|
||||
return array('' => $this->GetCode());
|
||||
}
|
||||
|
||||
public function GetLabel()
|
||||
{
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
@@ -2377,4 +2382,137 @@ class AttributePropertySet extends AttributeTable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The attribute dedicated to the friendly name automatic attribute (not written)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeComputedFieldVoid extends AttributeDefinition
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array());
|
||||
}
|
||||
|
||||
public function GetEditClass() {return "";}
|
||||
|
||||
public function GetValuesDef() {return null;}
|
||||
public function GetPrerequisiteAttributes() {return $this->Get("depends_on");}
|
||||
|
||||
public function IsDirectField() {return true;}
|
||||
public function IsScalar() {return true;}
|
||||
public function IsWritable() {return false;}
|
||||
public function GetSQLExpr() {return null;}
|
||||
public function GetDefaultValue() {return $this->MakeRealValue("");}
|
||||
public function IsNullAllowed() {return false;}
|
||||
|
||||
//
|
||||
// protected function ScalarToSQL($value) {return $value;} // format value as a valuable SQL literal (quoted outside)
|
||||
|
||||
public function GetSQLExpressions()
|
||||
{
|
||||
return array('' => $this->GetCode());
|
||||
}
|
||||
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public function GetSQLValues($value)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function GetSQLColumns()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function GetFilterDefinitions()
|
||||
{
|
||||
return array($this->GetCode() => new FilterFromAttribute($this));
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return "=";
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
$sQValue = CMDBSource::Quote($value);
|
||||
switch ($sOpCode)
|
||||
{
|
||||
case '!=':
|
||||
return $this->GetSQLExpr()." != $sQValue";
|
||||
break;
|
||||
case '=':
|
||||
default:
|
||||
return $this->GetSQLExpr()." = $sQValue";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The attribute dedicated to the friendly name automatic attribute (not written)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeFriendlyName extends AttributeComputedFieldVoid
|
||||
{
|
||||
public function __construct($sCode, $sExtKeyAttCode)
|
||||
{
|
||||
$this->m_sCode = $sCode;
|
||||
$aParams = array();
|
||||
// $aParams["is_null_allowed"] = false,
|
||||
$aParams["default_value"] = '';
|
||||
$aParams["extkey_attcode"] = $sExtKeyAttCode;
|
||||
parent::__construct($sCode, $aParams);
|
||||
|
||||
$this->m_sValue = $this->Get("default_value");
|
||||
}
|
||||
|
||||
public function GetKeyAttCode() {return $this->Get("extkey_attcode");}
|
||||
|
||||
// n/a, the friendly name is made of a complex expression (see GetNameSpec)
|
||||
protected function GetSQLCol() {return "";}
|
||||
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
$sValue = $aCols[$sPrefix];
|
||||
return $sValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the value before storing it in the database
|
||||
*/
|
||||
public function GetSQLValues($value)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function IsWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function SetFixedValue($sValue)
|
||||
{
|
||||
$this->m_sValue = $sValue;
|
||||
}
|
||||
public function GetDefaultValue()
|
||||
{
|
||||
return $this->m_sValue;
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue)
|
||||
{
|
||||
return Str::pure2html((string)$sValue);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -230,6 +230,7 @@ abstract class DBObject
|
||||
// Take care: the function isset will return false in case the value is null,
|
||||
// which is something that could happen on open joins
|
||||
$sAttRef = $sClassAlias.$sAttCode;
|
||||
|
||||
if (array_key_exists($sAttRef, $aRow))
|
||||
{
|
||||
$value = $oAttDef->FromSQLToValue($aRow, $sAttRef);
|
||||
@@ -390,22 +391,13 @@ abstract class DBObject
|
||||
$sClass = get_class($this);
|
||||
$oAtt = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
|
||||
$aExtKeyFriends = MetaModel::GetExtKeyFriends($sClass, $sAttCode);
|
||||
if (count($aExtKeyFriends) > 0)
|
||||
if ($oAtt->IsExternalKey(EXTKEY_ABSOLUTE))
|
||||
{
|
||||
// This attribute is an ext key (in this class or in another class)
|
||||
// The corresponding value is an id of the remote object
|
||||
// Let's try to use the corresponding external fields for a sexy display
|
||||
|
||||
$aAvailableFields = array();
|
||||
foreach ($aExtKeyFriends as $sDispAttCode => $oExtField)
|
||||
{
|
||||
// $aAvailableFields[$oExtField->GetExtAttCode()] = $oExtField->GetAsHTML($this->Get($oExtField->GetCode()));
|
||||
$aAvailableFields[$oExtField->GetExtAttCode()] = $this->Get($oExtField->GetCode());
|
||||
}
|
||||
|
||||
//return $this->Get($sAttCode.'_friendlyname');
|
||||
$sTargetClass = $oAtt->GetTargetClass(EXTKEY_ABSOLUTE);
|
||||
return $this->MakeHyperLink($sTargetClass, $this->Get($sAttCode), $aAvailableFields);
|
||||
$iTargetKey = $this->Get($sAttCode);
|
||||
$sLabel = $this->Get($sAttCode.'_friendlyname');
|
||||
return $this->MakeHyperLink($sTargetClass, $iTargetKey, $sLabel);
|
||||
}
|
||||
|
||||
// That's a standard attribute (might be an ext field or a direct field, etc.)
|
||||
@@ -437,23 +429,7 @@ abstract class DBObject
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAvailableFields = array();
|
||||
// retrieve the "external fields" linked to this external key
|
||||
foreach (MetaModel::GetExternalFields(get_class($this), $sAttCode) as $oExtField)
|
||||
{
|
||||
$aAvailableFields[$oExtField->GetExtAttCode()] = $oExtField->GetAsHTML($this->Get($oExtField->GetCode()));
|
||||
}
|
||||
// Use the "name" of the target class as the label of the hyperlink
|
||||
// unless it's not available in the external fields...
|
||||
$sExtClassNameAtt = MetaModel::GetNameAttributeCode($sTargetClass);
|
||||
if (isset($aAvailableFields[$sExtClassNameAtt]))
|
||||
{
|
||||
$sEditValue = $aAvailableFields[$sExtClassNameAtt];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sEditValue = implode(' / ', $aAvailableFields);
|
||||
}
|
||||
$sEditValue = $this->Get($sAttCode.'_friendlyname');
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -475,7 +451,7 @@ abstract class DBObject
|
||||
return $oAtt->GetAsCSV($this->Get($sAttCode), $sSeparator, $sTextQualifier);
|
||||
}
|
||||
|
||||
protected static function MakeHyperLink($sObjClass, $sObjKey, $aAvailableFields)
|
||||
protected static function MakeHyperLink($sObjClass, $sObjKey, $sLabel = '')
|
||||
{
|
||||
if ($sObjKey == 0) return '<em>undefined</em>';
|
||||
|
||||
@@ -484,8 +460,7 @@ abstract class DBObject
|
||||
|
||||
public function GetHyperlink()
|
||||
{
|
||||
$aAvailableFields[MetaModel::GetNameAttributeCode(get_class($this))] = $this->GetName();
|
||||
return $this->MakeHyperLink(get_class($this), $this->GetKey(), $aAvailableFields);
|
||||
return $this->MakeHyperLink(get_class($this), $this->GetKey(), $this->GetName());
|
||||
}
|
||||
|
||||
|
||||
@@ -524,16 +499,24 @@ abstract class DBObject
|
||||
|
||||
public function GetName()
|
||||
{
|
||||
$sNameAttCode = MetaModel::GetNameAttributeCode(get_class($this));
|
||||
if (empty($sNameAttCode))
|
||||
$aNameSpec = MetaModel::GetNameSpec(get_class($this));
|
||||
$sFormat = $aNameSpec[0];
|
||||
$aAttributes = $aNameSpec[1];
|
||||
|
||||
$aValues = array();
|
||||
foreach ($aAttributes as $sAttCode)
|
||||
{
|
||||
return $this->m_iKey;
|
||||
if (empty($sAttCode))
|
||||
{
|
||||
$aValues[] = $this->m_iKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->Get($sNameAttCode);
|
||||
$aValues[] = $this->Get($sAttCode);
|
||||
}
|
||||
}
|
||||
return vsprintf($sFormat, $aValues);
|
||||
}
|
||||
|
||||
public function GetState()
|
||||
{
|
||||
|
||||
@@ -226,6 +226,14 @@ class DBObjectSearch
|
||||
$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()));
|
||||
|
||||
@@ -30,6 +30,7 @@ class MissingQueryArgument extends CoreException
|
||||
abstract class Expression
|
||||
{
|
||||
// recursive translation of identifiers
|
||||
abstract public function GetUnresolvedFields($sAlias, &$aUnresolved);
|
||||
abstract public function Translate($aTranslationData, $bMatchAll = true);
|
||||
|
||||
// recursive rendering (aArgs used as input by default, or used as output if bRetrofitParams set to True
|
||||
@@ -66,6 +67,12 @@ 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;
|
||||
@@ -79,6 +86,42 @@ abstract class Expression
|
||||
}
|
||||
}
|
||||
|
||||
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 GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true)
|
||||
{
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
public function ListRequiredFields()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class BinaryExpression extends Expression
|
||||
{
|
||||
@@ -143,6 +186,12 @@ class BinaryExpression extends Expression
|
||||
return "($sLeft $sOperator $sRight)";
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
$this->GetLeftExpr()->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
$this->GetRightExpr()->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true)
|
||||
{
|
||||
$oLeft = $this->GetLeftExpr()->Translate($aTranslationData, $bMatchAll);
|
||||
@@ -194,6 +243,10 @@ class UnaryExpression extends Expression
|
||||
}
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true)
|
||||
{
|
||||
return clone $this;
|
||||
@@ -275,6 +328,20 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true)
|
||||
{
|
||||
if (!array_key_exists($this->m_sParent, $aTranslationData))
|
||||
@@ -292,21 +359,28 @@ class FieldExpression extends UnaryExpression
|
||||
}
|
||||
$sNewParent = $aTranslationData[$this->m_sParent]['*'];
|
||||
$sNewName = $this->m_sName;
|
||||
$oRet = new FieldExpressionResolved($sNewName, $sNewParent);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sNewParent = $aTranslationData[$this->m_sParent][$this->m_sName][0];
|
||||
$sNewName = $aTranslationData[$this->m_sParent][$this->m_sName][1];
|
||||
$oRet = $aTranslationData[$this->m_sParent][$this->m_sName];
|
||||
}
|
||||
return new FieldExpression($sNewName, $sNewParent);
|
||||
}
|
||||
|
||||
public function ListRequiredFields()
|
||||
{
|
||||
return array($this->m_sParent.'.'.$this->m_sName);
|
||||
return $oRet;
|
||||
}
|
||||
}
|
||||
|
||||
// Has been resolved into an SQL expression
|
||||
class FieldExpressionResolved extends FieldExpression
|
||||
{
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true)
|
||||
{
|
||||
return clone $this;
|
||||
}
|
||||
}
|
||||
|
||||
class VariableExpression extends UnaryExpression
|
||||
{
|
||||
@@ -393,6 +467,14 @@ class ListExpression extends Expression
|
||||
return '('.implode(', ', $aRes).')';
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
{
|
||||
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
}
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true)
|
||||
{
|
||||
$aRes = array();
|
||||
@@ -453,6 +535,14 @@ class FunctionExpression extends Expression
|
||||
return $this->m_sVerb.'('.implode(', ', $aRes).')';
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
foreach ($this->m_aArgs as $oExpr)
|
||||
{
|
||||
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
}
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true)
|
||||
{
|
||||
$aRes = array();
|
||||
@@ -507,6 +597,11 @@ class IntervalExpression extends Expression
|
||||
return 'INTERVAL '.$this->m_oValue->Render($aArgs, $bRetrofitParams).' '.$this->m_sUnit;
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
$this->m_oValue->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true)
|
||||
{
|
||||
return new IntervalExpression($this->m_oValue->Translate($aTranslationData, $bMatchAll), $this->m_sUnit);
|
||||
@@ -551,6 +646,14 @@ class CharConcatExpression extends Expression
|
||||
return "CAST(CONCAT(".implode(', ', $aRes).") AS CHAR)";
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
{
|
||||
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
}
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true)
|
||||
{
|
||||
$aRes = array();
|
||||
@@ -572,4 +675,75 @@ class CharConcatExpression extends Expression
|
||||
}
|
||||
}
|
||||
|
||||
class QueryBuilderExpressions
|
||||
{
|
||||
protected $m_oConditionExpr;
|
||||
protected $m_aSelectExpr;
|
||||
protected $m_aJoinFields;
|
||||
|
||||
public function __construct($aSelect, $oCondition)
|
||||
{
|
||||
$this->m_oConditionExpr = $oCondition;
|
||||
$this->m_aSelectExpr = $aSelect;
|
||||
$this->m_aJoinFields = array();
|
||||
}
|
||||
|
||||
public function GetSelect()
|
||||
{
|
||||
return $this->m_aSelectExpr;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
foreach($this->m_aJoinFields as $oExpression)
|
||||
{
|
||||
$oExpression->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
}
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true)
|
||||
{
|
||||
$this->m_oConditionExpr = $this->m_oConditionExpr->Translate($aTranslationData, $bMatchAll);
|
||||
foreach($this->m_aSelectExpr as $sColAlias => $oExpr)
|
||||
{
|
||||
$this->m_aSelectExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll);
|
||||
}
|
||||
foreach($this->m_aJoinFields as $index => $oExpression)
|
||||
{
|
||||
$this->m_aJoinFields[$index] = $oExpression->Translate($aTranslationData, $bMatchAll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -345,11 +345,84 @@ abstract class MetaModel
|
||||
self::_check_subclass($sClass);
|
||||
return (self::$m_aClassParams[$sClass]["key_type"] == "autoincrement");
|
||||
}
|
||||
final static public function GetNameAttributeCode($sClass)
|
||||
final static public function GetNameSpec($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
return self::$m_aClassParams[$sClass]["name_attcode"];
|
||||
$nameRawSpec = self::$m_aClassParams[$sClass]["name_attcode"];
|
||||
if (is_array($nameRawSpec))
|
||||
{
|
||||
$sFormat = Dict::S("Class:$sClass/Name", '');
|
||||
if (strlen($sFormat) == 0)
|
||||
{
|
||||
// Default to "%1$s %2$s..."
|
||||
for($i = 1 ; $i <= count($nameRawSpec) ; $i++)
|
||||
{
|
||||
if (empty($sFormat))
|
||||
{
|
||||
$sFormat .= '%'.$i.'$s';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sFormat .= ' %'.$i.'$s';
|
||||
}
|
||||
}
|
||||
}
|
||||
return array($sFormat, $nameRawSpec);
|
||||
}
|
||||
elseif (empty($nameRawSpec))
|
||||
{
|
||||
//return array($sClass.' %s', array('id'));
|
||||
return array($sClass, array());
|
||||
}
|
||||
else
|
||||
{
|
||||
// string -> attcode
|
||||
return array('%1$s', array($nameRawSpec));
|
||||
}
|
||||
}
|
||||
final static public function GetNameExpression($sClass, $sClassAlias)
|
||||
{
|
||||
$aNameSpec = self::GetNameSpec($sClass);
|
||||
$sFormat = $aNameSpec[0];
|
||||
$aAttributes = $aNameSpec[1];
|
||||
|
||||
$aPieces = preg_split('/%([0-9])\\$s/', $sFormat, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
//echo "<pre>\n";
|
||||
//print_r($aPieces);
|
||||
//echo "</pre>\n";
|
||||
$aExpressions = array();
|
||||
foreach($aPieces as $i => $sPiece)
|
||||
{
|
||||
if ($i & 1)
|
||||
{
|
||||
// $i is ODD - sPiece is a delimiter
|
||||
//
|
||||
$iReplacement = (int)$sPiece - 1;
|
||||
|
||||
if (isset($aAttributes[$iReplacement]))
|
||||
{
|
||||
$sAtt = $aAttributes[$iReplacement];
|
||||
$aExpressions[] = new FieldExpression($sAtt, $sClassAlias);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// $i is EVEN - sPiece is a literal
|
||||
//
|
||||
if (strlen($sPiece) > 0)
|
||||
{
|
||||
$aExpressions[] = new ScalarExpression($sPiece);
|
||||
}
|
||||
}
|
||||
}
|
||||
//echo "<pre>\n";
|
||||
//print_r($aExpressions);
|
||||
//echo "</pre>\n";
|
||||
|
||||
$oNameExpr = new CharConcatExpression($aExpressions);
|
||||
return $oNameExpr;
|
||||
}
|
||||
|
||||
final static public function GetStateAttributeCode($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
@@ -1023,6 +1096,16 @@ abstract class MetaModel
|
||||
//
|
||||
foreach (self::GetClasses() as $sClass)
|
||||
{
|
||||
// Create the friendly name attribute
|
||||
$sFriendlyNameAttCode = 'friendlyname';
|
||||
$oFriendlyName = new AttributeFriendlyName($sFriendlyNameAttCode, 'id');
|
||||
$oFriendlyName->SetHostClass($sClass);
|
||||
self::$m_aAttribDefs[$sClass][$sFriendlyNameAttCode] = $oFriendlyName;
|
||||
self::$m_aAttribOrigins[$sClass][$sFriendlyNameAttCode] = $sClass;
|
||||
$oFriendlyNameFlt = new FilterFromAttribute($oFriendlyName);
|
||||
self::$m_aFilterDefs[$sClass][$sFriendlyNameAttCode] = $oFriendlyNameFlt;
|
||||
self::$m_aFilterOrigins[$sClass][$sFriendlyNameAttCode] = $sClass;
|
||||
|
||||
self::$m_aExtKeyFriends[$sClass] = array();
|
||||
foreach (self::$m_aAttribDefs[$sClass] as $sAttCode => $oAttDef)
|
||||
{
|
||||
@@ -1052,10 +1135,36 @@ abstract class MetaModel
|
||||
// - an external KEY / FIELD (direct),
|
||||
// - an external field pointing to an external KEY / FIELD
|
||||
// - an external field pointing to an external field pointing to....
|
||||
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sRemoteClass = $oAttDef->GetTargetClass();
|
||||
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
// This is a key, but the value comes from elsewhere
|
||||
// Create an external field pointing to the remote friendly name attribute
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$sRemoteAttCode = $oAttDef->GetExtAttCode()."_friendlyname";
|
||||
$sFriendlyNameAttCode = $sAttCode.'_friendlyname';
|
||||
// propagate "is_null_allowed" ?
|
||||
$oFriendlyName = new AttributeExternalField($sFriendlyNameAttCode, array("allowed_values"=>null, "extkey_attcode"=>$sKeyAttCode, "target_attcode"=>$sRemoteAttCode, "is_null_allowed"=>true, "depends_on"=>array()));
|
||||
$oFriendlyName->SetHostClass($sClass);
|
||||
self::$m_aAttribDefs[$sClass][$sFriendlyNameAttCode] = $oFriendlyName;
|
||||
self::$m_aAttribOrigins[$sClass][$sFriendlyNameAttCode] = $sRemoteClass;
|
||||
$oFriendlyNameFlt = new FilterFromAttribute($oFriendlyName);
|
||||
self::$m_aFilterDefs[$sClass][$sFriendlyNameAttCode] = $oFriendlyNameFlt;
|
||||
self::$m_aFilterOrigins[$sClass][$sFriendlyNameAttCode] = $sRemoteClass;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create the friendly name attribute
|
||||
$sFriendlyNameAttCode = $sAttCode.'_friendlyname';
|
||||
$oFriendlyName = new AttributeFriendlyName($sFriendlyNameAttCode, $sAttCode);
|
||||
$oFriendlyName->SetHostClass($sClass);
|
||||
self::$m_aAttribDefs[$sClass][$sFriendlyNameAttCode] = $oFriendlyName;
|
||||
self::$m_aAttribOrigins[$sClass][$sFriendlyNameAttCode] = $sRemoteClass;
|
||||
$oFriendlyNameFlt = new FilterFromAttribute($oFriendlyName);
|
||||
self::$m_aFilterDefs[$sClass][$sFriendlyNameAttCode] = $oFriendlyNameFlt;
|
||||
self::$m_aFilterOrigins[$sClass][$sFriendlyNameAttCode] = $sRemoteClass;
|
||||
|
||||
if (self::HasChildrenClasses($sRemoteClass))
|
||||
{
|
||||
// First, create an external field attribute, that gets the final class
|
||||
@@ -1168,7 +1277,7 @@ abstract class MetaModel
|
||||
$aMandatParams = array(
|
||||
"category" => "group classes by modules defining their visibility in the UI",
|
||||
"key_type" => "autoincrement | string",
|
||||
"name_attcode" => "define wich attribute is the class name, may be an inherited attribute",
|
||||
"name_attcode" => "define wich attribute is the class name, may be an array of attributes (format specified in the dictionary as 'Class:myclass/Name' => '%1\$s %2\$s...'",
|
||||
"state_attcode" => "define wich attribute is representing the state (object lifecycle)",
|
||||
"reconc_keys" => "define the attributes that will 'almost uniquely' identify an object in batch processes",
|
||||
"db_table" => "database table",
|
||||
@@ -1295,6 +1404,10 @@ abstract class MetaModel
|
||||
|
||||
public static function Init_AddAttribute(AttributeDefinition $oAtt)
|
||||
{
|
||||
$sAttCode = $oAtt->GetCode();
|
||||
if ($sAttCode == 'finalclass') throw new Exception('Using a reserved keyword in metamodel declaration: '.$sAttCode);
|
||||
if ($sAttCode == 'friendlyname') throw new Exception('Using a reserved keyword in metamodel declaration: '.$sAttCode);
|
||||
|
||||
$sTargetClass = self::GetCallersPHPClass("Init");
|
||||
|
||||
// Some attributes could refer to a class
|
||||
@@ -1642,13 +1755,12 @@ abstract class MetaModel
|
||||
|
||||
if (!isset($oSelect))
|
||||
{
|
||||
$aTranslation = array();
|
||||
$aClassAliases = array();
|
||||
$aTableAliases = array();
|
||||
$oConditionTree = $oFilter->GetCriteria();
|
||||
$oQBExpr = new QueryBuilderExpressions(array(), $oFilter->GetCriteria());
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oFilter, array(), array(), true /* main query */);
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, array(), true /* main query */);
|
||||
$oKPI->ComputeStats('MakeQuery (select)', $sOqlQuery);
|
||||
|
||||
self::$m_aQueryStructCache[$sOqlId] = clone $oSelect;
|
||||
@@ -1672,12 +1784,8 @@ abstract class MetaModel
|
||||
{
|
||||
foreach ($oFilter->GetSelectedClasses() as $sSelectedAlias => $sSelectedClass)
|
||||
{
|
||||
$sNameAttCode = self::GetNameAttributeCode($sSelectedClass);
|
||||
if (!empty($sNameAttCode))
|
||||
{
|
||||
// By default, simply order on the "name" attribute, ascending
|
||||
$aOrderSpec[$sSelectedAlias.$sNameAttCode] = true;
|
||||
}
|
||||
// By default, simply order on the "friendlyname" attribute, ascending
|
||||
$aOrderSpec[$sSelectedAlias."friendlyname"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1759,11 +1867,10 @@ abstract class MetaModel
|
||||
|
||||
public static function MakeDeleteQuery(DBObjectSearch $oFilter, $aArgs = array())
|
||||
{
|
||||
$aTranslation = array();
|
||||
$aClassAliases = array();
|
||||
$aTableAliases = array();
|
||||
$oConditionTree = $oFilter->GetCriteria();
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oFilter, array(), array(), true /* main query */);
|
||||
$oQBExpr = new QueryBuilderExpressions(array(), $oFilter->GetCriteria());
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, array(), true /* main query */);
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
return $oSelect->RenderDelete($aScalarArgs);
|
||||
}
|
||||
@@ -1771,20 +1878,18 @@ abstract class MetaModel
|
||||
public static function MakeUpdateQuery(DBObjectSearch $oFilter, $aValues, $aArgs = array())
|
||||
{
|
||||
// $aValues is an array of $sAttCode => $value
|
||||
$aTranslation = array();
|
||||
$aClassAliases = array();
|
||||
$aTableAliases = array();
|
||||
$oConditionTree = $oFilter->GetCriteria();
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oFilter, array(), $aValues, true /* main query */);
|
||||
$oQBExpr = new QueryBuilderExpressions(array(), $oFilter->GetCriteria());
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, $aValues, true /* main query */);
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
return $oSelect->RenderUpdate($aScalarArgs);
|
||||
}
|
||||
|
||||
private static function MakeQuery($aSelectedClasses, &$oConditionTree, &$aClassAliases, &$aTableAliases, &$aTranslation, DBObjectSearch $oFilter, $aExpectedAtts = array(), $aValues = array(), $bIsMainQuery = false)
|
||||
private static function MakeQuery($aSelectedClasses, &$oQBExpr, &$aClassAliases, &$aTableAliases, DBObjectSearch $oFilter, $aValues = array(), $bIsMainQuery = false)
|
||||
{
|
||||
// Note: query class might be different than the class of the filter
|
||||
// -> this occurs when we are linking our class to an external class (referenced by, or pointing to)
|
||||
// $aExpectedAtts is an array of sAttCode=>array of columns
|
||||
$sClass = $oFilter->GetFirstJoinedClass();
|
||||
$sClassAlias = $oFilter->GetFirstJoinedClassAlias();
|
||||
|
||||
@@ -1794,7 +1899,7 @@ abstract class MetaModel
|
||||
$aClassAliases = array_merge($aClassAliases, $oFilter->GetJoinedClasses());
|
||||
}
|
||||
|
||||
self::DbgTrace("Entering: ".$oFilter->ToOQL().", ".($bIsOnQueriedClass ? "MAIN" : "SECONDARY").", expectedatts=".count($aExpectedAtts).": ".implode(",", array_keys($aExpectedAtts)));
|
||||
self::DbgTrace("Entering: ".$oFilter->ToOQL().", ".($bIsOnQueriedClass ? "MAIN" : "SECONDARY"));
|
||||
|
||||
$sRootClass = self::GetRootClass($sClass);
|
||||
$sKeyField = self::DBGetKey($sClass);
|
||||
@@ -1802,23 +1907,32 @@ abstract class MetaModel
|
||||
if ($bIsOnQueriedClass)
|
||||
{
|
||||
// default to the whole list of attributes + the very std id/finalclass
|
||||
$aExpectedAtts['id'][] = $sClassAlias.'id';
|
||||
foreach (self::GetAttributesList($sClass) as $sAttCode)
|
||||
$oQBExpr->AddSelect($sClassAlias.'id', new FieldExpression('id', $sClassAlias));
|
||||
|
||||
foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
$aExpectedAtts[$sAttCode][] = $sClassAlias.$sAttCode; // alias == class and attcode
|
||||
if (!$oAttDef->IsScalar()) continue;
|
||||
|
||||
foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr)
|
||||
{
|
||||
$oQBExpr->AddSelect($sClassAlias.$sAttCode.$sColId, new FieldExpression($sAttCode.$sColId, $sClassAlias));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute a clear view of external keys, and external attributes
|
||||
$aExpectedAtts = array(); // array of (attcode => fieldexpression)
|
||||
$oQBExpr->GetUnresolvedFields($sClassAlias, $aExpectedAtts);
|
||||
|
||||
// Compute a clear view of required joins (from the current class)
|
||||
// Build the list of external keys:
|
||||
// -> ext keys required by a closed join ???
|
||||
// -> ext keys required by an explicit join
|
||||
// -> ext keys mentionned in a 'pointing to' condition
|
||||
// -> ext keys required for an external field
|
||||
// -> ext keys required for a friendly name
|
||||
//
|
||||
$aExtKeys = array(); // array of sTableClass => array of (sAttCode (keys) => array of (sAttCode (fields)=> oAttDef))
|
||||
//
|
||||
// Optimization: could be computed once for all (cached)
|
||||
// Could be done in MakeQuerySingleTable ???
|
||||
// Optimization: could be partially computed once for all (cached) ?
|
||||
//
|
||||
|
||||
if ($bIsOnQueriedClass)
|
||||
@@ -1836,13 +1950,39 @@ abstract class MetaModel
|
||||
$sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sKeyAttCode];
|
||||
$aExtKeys[$sKeyTableClass][$sKeyAttCode] = array();
|
||||
}
|
||||
|
||||
if (array_key_exists('friendlyname', $aExpectedAtts))
|
||||
{
|
||||
$aTranslateNow = array();
|
||||
$aTranslateNow[$sClassAlias]['friendlyname'] = self::GetNameExpression($sClass, $sClassAlias);
|
||||
$oQBExpr->Translate($aTranslateNow, false);
|
||||
|
||||
$aNameSpec = self::GetNameSpec($sClass);
|
||||
foreach($aNameSpec[1] as $i => $sAttCode)
|
||||
{
|
||||
$oAttDef = self::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sAttCode];
|
||||
$aExtKeys[$sKeyTableClass][$sAttCode] = array();
|
||||
}
|
||||
elseif ($oAttDef->IsExternalField() || ($oAttDef instanceof AttributeFriendlyName))
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sKeyAttCode];
|
||||
$aExtKeys[$sKeyTableClass][$sKeyAttCode][$sAttCode] = $oAttDef;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add the ext fields used in the select (eventually adds an external key)
|
||||
foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
if ($oAttDef->IsExternalField())
|
||||
if ($oAttDef->IsExternalField() || ($oAttDef instanceof AttributeFriendlyName))
|
||||
{
|
||||
if (array_key_exists($sAttCode, $aExpectedAtts))
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
if (array_key_exists($sAttCode, $aExpectedAtts) || $oConditionTree->RequiresField($sClassAlias, $sAttCode))
|
||||
if ($sKeyAttCode != 'id')
|
||||
{
|
||||
// Add the external attribute
|
||||
$sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sKeyAttCode];
|
||||
@@ -1850,13 +1990,14 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First query built upon on the leaf (ie current) class
|
||||
//
|
||||
self::DbgTrace("Main (=leaf) class, call MakeQuerySingleTable()");
|
||||
if (self::HasTable($sClass))
|
||||
{
|
||||
$oSelectBase = self::MakeQuerySingleTable($aSelectedClasses, $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oFilter, $sClass, $aExpectedAtts, $aExtKeys, $aValues);
|
||||
$oSelectBase = self::MakeQuerySingleTable($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, $sClass, $aExtKeys, $aValues);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1865,7 +2006,7 @@ abstract class MetaModel
|
||||
// As the join will not filter on the expected classes, we have to specify it explicitely
|
||||
$sExpectedClasses = implode("', '", self::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
|
||||
$oFinalClassRestriction = Expression::FromOQL("`$sClassAlias`.finalclass IN ('$sExpectedClasses')");
|
||||
$oConditionTree = $oConditionTree->LogAnd($oFinalClassRestriction);
|
||||
$oQBExpr->AddCondition($oFinalClassRestriction);
|
||||
}
|
||||
|
||||
// Then we join the queries of the eventual parent classes (compound model)
|
||||
@@ -1873,7 +2014,7 @@ abstract class MetaModel
|
||||
{
|
||||
if (!self::HasTable($sParentClass)) continue;
|
||||
self::DbgTrace("Parent class: $sParentClass... let's call MakeQuerySingleTable()");
|
||||
$oSelectParentTable = self::MakeQuerySingleTable($aSelectedClasses, $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oFilter, $sParentClass, $aExpectedAtts, $aExtKeys, $aValues);
|
||||
$oSelectParentTable = self::MakeQuerySingleTable($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, $sParentClass, $aExtKeys, $aValues);
|
||||
if (is_null($oSelectBase))
|
||||
{
|
||||
$oSelectBase = $oSelectParentTable;
|
||||
@@ -1891,19 +2032,20 @@ abstract class MetaModel
|
||||
{
|
||||
$oForeignKeyAttDef = self::GetAttributeDef($sForeignClass, $sForeignKeyAttCode);
|
||||
|
||||
// We don't want any attribute from the foreign class, just filter on an inner join
|
||||
$aExpAtts = array();
|
||||
|
||||
self::DbgTrace("Referenced by foreign key: $sForeignKeyAttCode... let's call MakeQuery()");
|
||||
//self::DbgTrace($oForeignFilter);
|
||||
//self::DbgTrace($oForeignFilter->ToOQL());
|
||||
//self::DbgTrace($oSelectForeign);
|
||||
//self::DbgTrace($oSelectForeign->RenderSelect(array()));
|
||||
$oSelectForeign = self::MakeQuery($aSelectedClasses, $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oForeignFilter, $aExpAtts);
|
||||
|
||||
$sForeignClassAlias = $oForeignFilter->GetFirstJoinedClassAlias();
|
||||
$sForeignKeyTable = $aTranslation[$sForeignClassAlias][$sForeignKeyAttCode][0];
|
||||
$sForeignKeyColumn = $aTranslation[$sForeignClassAlias][$sForeignKeyAttCode][1];
|
||||
$oQBExpr->PushJoinField(new FieldExpression($sForeignKeyAttCode, $sForeignClassAlias));
|
||||
|
||||
$oSelectForeign = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oForeignFilter);
|
||||
|
||||
$oJoinExpr = $oQBExpr->PopJoinField();
|
||||
$sForeignKeyTable = $oJoinExpr->GetParent();
|
||||
$sForeignKeyColumn = $oJoinExpr->GetName();
|
||||
$oSelectBase->AddInnerJoin($oSelectForeign, $sKeyField, $sForeignKeyColumn, $sForeignKeyTable);
|
||||
}
|
||||
}
|
||||
@@ -1940,8 +2082,8 @@ abstract class MetaModel
|
||||
//
|
||||
if ($bIsMainQuery)
|
||||
{
|
||||
$oConditionTranslated = $oConditionTree->Translate($aTranslation);
|
||||
$oSelectBase->SetCondition($oConditionTranslated);
|
||||
$oSelectBase->SetCondition($oQBExpr->GetCondition());
|
||||
$oSelectBase->SetSelect($oQBExpr->GetSelect());
|
||||
}
|
||||
|
||||
// That's all... cross fingers and we'll get some working query
|
||||
@@ -1952,9 +2094,8 @@ abstract class MetaModel
|
||||
return $oSelectBase;
|
||||
}
|
||||
|
||||
protected static function MakeQuerySingleTable($aSelectedClasses, &$oConditionTree, &$aClassAliases, &$aTableAliases, &$aTranslation, $oFilter, $sTableClass, $aExpectedAtts, $aExtKeys, $aValues)
|
||||
protected static function MakeQuerySingleTable($aSelectedClasses, &$oQBExpr, &$aClassAliases, &$aTableAliases, $oFilter, $sTableClass, $aExtKeys, $aValues)
|
||||
{
|
||||
// $aExpectedAtts is an array of sAttCode=>sAlias
|
||||
// $aExtKeys is an array of sTableClass => array of (sAttCode (keys) => array of sAttCode (fields))
|
||||
|
||||
// Prepare the query for a single table (compound objects)
|
||||
@@ -1968,29 +2109,28 @@ abstract class MetaModel
|
||||
$sTable = self::DBGetTable($sTableClass);
|
||||
$sTableAlias = self::GenerateUniqueAlias($aTableAliases, $sTargetAlias.'_'.$sTable, $sTable);
|
||||
|
||||
$aTranslation = array();
|
||||
$aExpectedAtts = array();
|
||||
$oQBExpr->GetUnresolvedFields($sTargetAlias, $aExpectedAtts);
|
||||
|
||||
$bIsOnQueriedClass = array_key_exists($sTargetAlias, $aSelectedClasses);
|
||||
|
||||
self::DbgTrace("Entering: tableclass=$sTableClass, filter=".$oFilter->ToOQL().", ".($bIsOnQueriedClass ? "MAIN" : "SECONDARY").", expectedatts=".count($aExpectedAtts).": ".implode(",", array_keys($aExpectedAtts)));
|
||||
self::DbgTrace("Entering: tableclass=$sTableClass, filter=".$oFilter->ToOQL().", ".($bIsOnQueriedClass ? "MAIN" : "SECONDARY"));
|
||||
|
||||
// 1 - SELECT and UPDATE
|
||||
//
|
||||
// Note: no need for any values nor fields for foreign Classes (ie not the queried Class)
|
||||
//
|
||||
$aSelect = array();
|
||||
$aUpdateValues = array();
|
||||
|
||||
// 1/a - Get the key
|
||||
// 1/a - Get the key and friendly name
|
||||
//
|
||||
if ($bIsOnQueriedClass)
|
||||
{
|
||||
$aSelect[$aExpectedAtts['id'][0]] = new FieldExpression(self::DBGetKey($sTableClass), $sTableAlias);
|
||||
}
|
||||
// We need one pkey to be the key, let's take the one corresponding to the root class
|
||||
// (used to be based on the leaf, but it may happen that this one has no table defined)
|
||||
$sRootClass = self::GetRootClass($sTargetClass);
|
||||
if ($sTableClass == $sRootClass)
|
||||
{
|
||||
$aTranslation[$sTargetAlias]['id'] = array($sTableAlias, self::DBGetKey($sTableClass));
|
||||
$aTranslation[$sTargetAlias]['id'] = new FieldExpressionResolved(self::DBGetKey($sTableClass), $sTableAlias);
|
||||
}
|
||||
|
||||
// 1/b - Get the other attributes
|
||||
@@ -2000,7 +2140,7 @@ abstract class MetaModel
|
||||
// Skip this attribute if not defined in this table
|
||||
if (self::$m_aAttribOrigins[$sTargetClass][$sAttCode] != $sTableClass) continue;
|
||||
|
||||
// Skip this attribute if not writable (means that it does not correspond
|
||||
// Skip this attribute if not made of SQL columns
|
||||
if (count($oAttDef->GetSQLExpressions()) == 0) continue;
|
||||
|
||||
// Update...
|
||||
@@ -2016,12 +2156,9 @@ abstract class MetaModel
|
||||
|
||||
// Select...
|
||||
//
|
||||
// Skip, if a list of fields has been specified and it is not there
|
||||
if (!array_key_exists($sAttCode, $aExpectedAtts)) continue;
|
||||
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
// skip, this will be handled in the joined tables
|
||||
// skip, this will be handled in the joined tables (done hereabove)
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2029,32 +2166,16 @@ abstract class MetaModel
|
||||
// add it to the output
|
||||
foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr)
|
||||
{
|
||||
foreach ($aExpectedAtts[$sAttCode] as $sAttAlias)
|
||||
if (array_key_exists($sAttCode, $aExpectedAtts))
|
||||
{
|
||||
$aSelect[$sAttAlias.$sColId] = new FieldExpression($sSQLExpr, $sTableAlias);
|
||||
$aTranslation[$sTargetAlias][$sAttCode.$sColId] = new FieldExpressionResolved($sSQLExpr, $sTableAlias);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2 - WHERE
|
||||
//
|
||||
foreach(self::$m_aFilterDefs[$sTargetClass] as $sFltCode => $oFltAtt)
|
||||
{
|
||||
// Skip this filter if not defined in this table
|
||||
if (self::$m_aFilterOrigins[$sTargetClass][$sFltCode] != $sTableClass) continue;
|
||||
|
||||
// #@# todo - aller plus loin... a savoir que la table de translation doit contenir une "Expression"
|
||||
foreach($oFltAtt->GetSQLExpressions() as $sColID => $sFltExpr)
|
||||
{
|
||||
// Note: I did not test it with filters relying on several expressions...
|
||||
// as long as sColdID is empty, this is working, otherwise... ?
|
||||
$aTranslation[$sTargetAlias][$sFltCode.$sColID] = array($sTableAlias, $sFltExpr);
|
||||
}
|
||||
}
|
||||
|
||||
// #@# todo - See what a full text search condition should be
|
||||
// 2' - WHERE / Full text search condition
|
||||
// 2 - WHERE / Full text search condition
|
||||
//
|
||||
if ($bIsOnQueriedClass)
|
||||
{
|
||||
@@ -2068,7 +2189,7 @@ abstract class MetaModel
|
||||
|
||||
// 3 - The whole stuff, for this table only
|
||||
//
|
||||
$oSelectBase = new SQLQuery($sTable, $sTableAlias, $aSelect, null, $aFullText, $bIsOnQueriedClass, $aUpdateValues);
|
||||
$oSelectBase = new SQLQuery($sTable, $sTableAlias, array(), $aFullText, $bIsOnQueriedClass, $aUpdateValues);
|
||||
|
||||
// 4 - The external keys -> joins...
|
||||
//
|
||||
@@ -2099,45 +2220,59 @@ abstract class MetaModel
|
||||
|
||||
// Specify expected attributes for the target class query
|
||||
// ... and use the current alias !
|
||||
$aExpAtts = array();
|
||||
$aIntermediateTranslation = array();
|
||||
$aTranslateNow = array(); // Translation for external fields - must be performed before the join is done (recursion...)
|
||||
foreach($aExtFields as $sAttCode => $oAtt)
|
||||
{
|
||||
|
||||
$sExtAttCode = $oAtt->GetExtAttCode();
|
||||
if (array_key_exists($sAttCode, $aExpectedAtts))
|
||||
if ($oAtt instanceof AttributeFriendlyName)
|
||||
{
|
||||
// Request this attribute... transmit the alias !
|
||||
$aExpAtts[$sExtAttCode] = $aExpectedAtts[$sAttCode];
|
||||
// Note: for a given ext key, there is one single attribute "friendly name"
|
||||
$aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sExtAttCode = $oAtt->GetExtAttCode();
|
||||
// Translate mainclass.extfield => remoteclassalias.remotefieldcode
|
||||
$oRemoteAttDef = self::GetAttributeDef($sKeyClass, $sExtAttCode);
|
||||
foreach ($oRemoteAttDef->GetSQLExpressions() as $sColID => $sRemoteAttExpr)
|
||||
{
|
||||
$aIntermediateTranslation[$sTargetAlias.$sColID][$sAttCode] = array($sKeyClassAlias, $sRemoteAttExpr);
|
||||
$aTranslateNow[$sTargetAlias][$sAttCode.$sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);
|
||||
}
|
||||
//#@# debug - echo "<p>$sTargetAlias.$sAttCode to $sKeyClassAlias.$sRemoteAttExpr (class: $sKeyClass)</p>\n";
|
||||
}
|
||||
$oConditionTree = $oConditionTree->Translate($aIntermediateTranslation, false);
|
||||
}
|
||||
// Translate prior to recursing
|
||||
//
|
||||
$oQBExpr->Translate($aTranslateNow, false);
|
||||
|
||||
self::DbgTrace("External key $sKeyAttCode (class: $sKeyClass), call MakeQuery()");
|
||||
$oSelectExtKey = self::MakeQuery($aSelectedClasses, $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oExtFilter, $aExpAtts);
|
||||
|
||||
$oQBExpr->PushJoinField(new FieldExpression('id', $sKeyClassAlias));
|
||||
|
||||
$oSelectExtKey = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oExtFilter);
|
||||
|
||||
$oJoinExpr = $oQBExpr->PopJoinField();
|
||||
$sExternalKeyTable = $oJoinExpr->GetParent();
|
||||
$sExternalKeyField = $oJoinExpr->GetName();
|
||||
|
||||
$aCols = $oKeyAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc())
|
||||
$sLocalKeyField = current($aCols); // get the first column for an external key
|
||||
$sExternalKeyField = self::DBGetKey($sKeyClass);
|
||||
|
||||
self::DbgTrace("External key $sKeyAttCode, Join on $sLocalKeyField = $sExternalKeyField");
|
||||
if ($oKeyAttDef->IsNullAllowed())
|
||||
{
|
||||
$oSelectBase->AddLeftJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField);
|
||||
$oSelectBase->AddLeftJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSelectBase->AddInnerJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField);
|
||||
$oSelectBase->AddInnerJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Translate the selected columns
|
||||
//
|
||||
$oQBExpr->Translate($aTranslation, false);
|
||||
|
||||
//MyHelpers::var_dump_html($oSelectBase->RenderSelect());
|
||||
return $oSelectBase;
|
||||
}
|
||||
@@ -2174,18 +2309,15 @@ abstract class MetaModel
|
||||
$aSugFix = array();
|
||||
foreach (self::GetClasses() as $sClass)
|
||||
{
|
||||
$sNameAttCode = self::GetNameAttributeCode($sClass);
|
||||
if (empty($sNameAttCode))
|
||||
$aNameSpec = self::GetNameSpec($sClass);
|
||||
foreach($aNameSpec[1] as $i => $sAttCode)
|
||||
{
|
||||
// let's try this !!!
|
||||
// $aErrors[$sClass][] = "Missing value for name definition: the framework will (should...) replace it by the id";
|
||||
// $aSugFix[$sClass][] = "Expecting a value in ".implode(", ", self::GetAttributesList($sClass));
|
||||
}
|
||||
else if(!self::IsValidAttCode($sClass, $sNameAttCode))
|
||||
if(!self::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
$aErrors[$sClass][] = "Unkown attribute code '".$sNameAttCode."' for the name definition";
|
||||
$aErrors[$sClass][] = "Unkown attribute code '".$sAttCode."' for the name definition";
|
||||
$aSugFix[$sClass][] = "Expecting a value in ".implode(", ", self::GetAttributesList($sClass));
|
||||
}
|
||||
}
|
||||
|
||||
foreach(self::GetReconcKeys($sClass) as $sReconcKeyAttCode)
|
||||
{
|
||||
@@ -3555,6 +3687,22 @@ abstract class MetaModel
|
||||
return self::GetObjectByRow($sClass, $aRow);
|
||||
}
|
||||
|
||||
public static function GetObjectByName($sClass, $sName, $bMustBeFound = true)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
|
||||
$oObjSearch = new DBObjectSearch($sClass);
|
||||
$oObjSearch->AddNameCondition($sName);
|
||||
$oSet = new DBObjectSet($oObjSearch);
|
||||
if ($oSet->Count() != 1)
|
||||
{
|
||||
if ($bMustBeFound) throw new CoreException('Failed to get an object by its name', array('class'=>$sClass, 'name'=>$sName));
|
||||
return null;
|
||||
}
|
||||
$oObj = $oSet->fetch();
|
||||
return $oObj;
|
||||
}
|
||||
|
||||
public static function GetObjectFromOQL($sQuery, $aParams = null, $bAllowAllData = false)
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($sQuery, $aParams);
|
||||
|
||||
@@ -35,24 +35,6 @@
|
||||
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_sTable = '';
|
||||
@@ -64,7 +46,7 @@ class SQLQuery
|
||||
private $m_aValues = array(); // Values to set in case of an update query
|
||||
private $m_aJoinSelects = array();
|
||||
|
||||
public function __construct($sTable, $sTableAlias, $aFields, $oConditionExpr, $aFullTextNeedles, $bToDelete = true, $aValues = array())
|
||||
public function __construct($sTable, $sTableAlias, $aFields, $aFullTextNeedles, $bToDelete = true, $aValues = array())
|
||||
{
|
||||
// This check is not needed but for developping purposes
|
||||
//if (!CMDBSource::IsTable($sTable))
|
||||
@@ -79,15 +61,7 @@ class SQLQuery
|
||||
$this->m_sTable = $sTable;
|
||||
$this->m_sTableAlias = $sTableAlias;
|
||||
$this->m_aFields = $aFields;
|
||||
$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_oConditionExpr = null;
|
||||
$this->m_aFullTextNeedles = $aFullTextNeedles;
|
||||
$this->m_bToDelete = $bToDelete;
|
||||
$this->m_aValues = $aValues;
|
||||
@@ -146,15 +120,27 @@ class SQLQuery
|
||||
echo "</pre>";
|
||||
}
|
||||
|
||||
public function SetSelect($aExpressions)
|
||||
{
|
||||
$this->m_aFields = $aExpressions;
|
||||
}
|
||||
|
||||
public function SetCondition($oConditionExpr)
|
||||
{
|
||||
$this->m_oConditionExpr = $oConditionExpr;
|
||||
}
|
||||
|
||||
public function AddCondition($oConditionExpr)
|
||||
{
|
||||
if (is_null($this->m_oConditionExpr))
|
||||
{
|
||||
$this->m_oConditionExpr = $oConditionExpr;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_oConditionExpr->LogAnd($oConditionExpr);
|
||||
}
|
||||
}
|
||||
|
||||
private function AddJoin($sJoinType, $oSQLQuery, $sLeftField, $sRightField, $sRightTableAlias = '')
|
||||
{
|
||||
@@ -216,9 +202,16 @@ 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";
|
||||
}
|
||||
}
|
||||
|
||||
// Interface, build the SQL query
|
||||
public function RenderUpdate($aArgs = array())
|
||||
@@ -337,9 +330,16 @@ class SQLQuery
|
||||
}
|
||||
|
||||
private static function ClauseWhere($oConditionExpr, $aArgs = array())
|
||||
{
|
||||
if (is_null($oConditionExpr))
|
||||
{
|
||||
return '1';
|
||||
}
|
||||
else
|
||||
{
|
||||
return $oConditionExpr->Render($aArgs);
|
||||
}
|
||||
}
|
||||
|
||||
private static function ClauseOrderBy($aOrderBy)
|
||||
{
|
||||
@@ -365,26 +365,25 @@ class SQLQuery
|
||||
$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
|
||||
$sFields = implode(', ', $aFields);
|
||||
$oFullTextExpr = Expression::FromSQL("CONCAT_WS(' ', $sFields)");
|
||||
|
||||
// $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%"));
|
||||
if (is_null($oCondition))
|
||||
{
|
||||
$oCondition = $oNewCond;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oCondition = $oCondition->LogAnd($oNewCond);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sTableAlias;
|
||||
}
|
||||
@@ -419,8 +418,6 @@ class SQLQuery
|
||||
//
|
||||
foreach($this->m_aFields as $sAlias => $oExpression)
|
||||
{
|
||||
$sTable = $oExpression->GetParent();
|
||||
$sColumn = $oExpression->GetName();
|
||||
$aFields["`$sAlias`"] = $oExpression->Render();
|
||||
}
|
||||
if ($this->m_bToDelete)
|
||||
|
||||
@@ -391,6 +391,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:Subnet' => 'Subnetz',
|
||||
'Class:Subnet+' => '',
|
||||
'Class:Subnet/Name' => '%1$s / %2$s',
|
||||
//'Class:Subnet/Attribute:name' => 'Name',
|
||||
//'Class:Subnet/Attribute:name+' => '',
|
||||
'Class:Subnet/Attribute:org_id' => 'Organisation',
|
||||
@@ -544,6 +545,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:SoftwareInstance' => 'Software-Instanz',
|
||||
'Class:SoftwareInstance+' => '',
|
||||
'Class:SoftwareInstance/Name' => '%1$s - %2$s',
|
||||
'Class:SoftwareInstance/Attribute:device_id' => 'Gerät',
|
||||
'Class:SoftwareInstance/Attribute:device_id+' => '',
|
||||
'Class:SoftwareInstance/Attribute:device_name' => 'Gerät',
|
||||
@@ -569,6 +571,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:ApplicationInstance' => 'Anwendungsinstanz',
|
||||
'Class:ApplicationInstance+' => '',
|
||||
'Class:ApplicationInstance/Name' => '%1$s - %2$s',
|
||||
'Class:ApplicationInstance/Attribute:software_id' => 'Software',
|
||||
'Class:ApplicationInstance/Attribute:software_id+' => '',
|
||||
'Class:ApplicationInstance/Attribute:software_name' => 'Name',
|
||||
@@ -583,6 +586,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:DBServerInstance' => 'Datenbank-Server-Instanz',
|
||||
'Class:DBServerInstance+' => '',
|
||||
'Class:DBServerInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DBServerInstance/Attribute:software_id' => 'Software',
|
||||
'Class:DBServerInstance/Attribute:software_id+' => '',
|
||||
'Class:DBServerInstance/Attribute:software_name' => 'Software Name',
|
||||
@@ -598,6 +602,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:DatabaseInstance' => 'Datenbank-Instanz',
|
||||
'Class:DatabaseInstance+' => '',
|
||||
'Class:DatabaseInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id' => 'Datenbank-Server',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id+' => '',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_version' => 'Datenbank-Version',
|
||||
@@ -658,6 +663,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:NetworkInterface' => 'Netzwerk-Interface',
|
||||
'Class:NetworkInterface+' => '',
|
||||
'Class:NetworkInterface/Name' => '%1$s - %2$s',
|
||||
'Class:NetworkInterface/Attribute:device_id' => 'Gerät',
|
||||
'Class:NetworkInterface/Attribute:device_id+' => '',
|
||||
'Class:NetworkInterface/Attribute:device_name' => 'Gerät',
|
||||
|
||||
@@ -393,6 +393,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:Subnet' => 'Subnet',
|
||||
'Class:Subnet+' => '',
|
||||
'Class:Subnet/Name' => '%1$s / %2$s',
|
||||
//'Class:Subnet/Attribute:name' => 'Name',
|
||||
//'Class:Subnet/Attribute:name+' => '',
|
||||
'Class:Subnet/Attribute:org_id' => 'Owner organization',
|
||||
@@ -546,6 +547,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:SoftwareInstance' => 'Software Instance',
|
||||
'Class:SoftwareInstance+' => '',
|
||||
'Class:SoftwareInstance/Name' => '%1$s - %2$s',
|
||||
'Class:SoftwareInstance/Attribute:device_id' => 'Device',
|
||||
'Class:SoftwareInstance/Attribute:device_id+' => '',
|
||||
'Class:SoftwareInstance/Attribute:device_name' => 'Device',
|
||||
@@ -569,6 +571,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:ApplicationInstance' => 'Application Instance',
|
||||
'Class:ApplicationInstance+' => '',
|
||||
'Class:ApplicationInstance/Name' => '%1$s - %2$s',
|
||||
'Class:ApplicationInstance/Attribute:software_id' => 'Software',
|
||||
'Class:ApplicationInstance/Attribute:software_id+' => '',
|
||||
'Class:ApplicationInstance/Attribute:software_name' => 'Name',
|
||||
@@ -583,6 +586,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:DBServerInstance' => 'DB Server Instance',
|
||||
'Class:DBServerInstance+' => '',
|
||||
'Class:DBServerInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DBServerInstance/Attribute:software_id' => 'Software',
|
||||
'Class:DBServerInstance/Attribute:software_id+' => '',
|
||||
'Class:DBServerInstance/Attribute:software_name' => 'Software Name',
|
||||
@@ -599,6 +603,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:DatabaseInstance' => 'Database Instance',
|
||||
'Class:DatabaseInstance+' => '',
|
||||
'Class:DatabaseInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id' => 'Database server',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id+' => '',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_version' => 'Database version',
|
||||
@@ -659,6 +664,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:NetworkInterface' => 'Network Interface',
|
||||
'Class:NetworkInterface+' => '',
|
||||
'Class:NetworkInterface/Name' => '%1$s - %2$s',
|
||||
'Class:NetworkInterface/Attribute:device_id' => 'Device',
|
||||
'Class:NetworkInterface/Attribute:device_id+' => '',
|
||||
'Class:NetworkInterface/Attribute:device_name' => 'Device',
|
||||
|
||||
@@ -387,6 +387,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:Subnet' => 'Sub-Red',
|
||||
'Class:Subnet+' => '',
|
||||
'Class:Subnet/Name' => '%1$s / %2$s',
|
||||
//'Class:Subnet/Attribute:name' => 'Nombre',
|
||||
//'Class:Subnet/Attribute:name+' => '',
|
||||
'Class:Subnet/Attribute:org_id' => 'Organización propietaria',
|
||||
@@ -540,6 +541,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:SoftwareInstance' => 'Instancia de Software',
|
||||
'Class:SoftwareInstance+' => '',
|
||||
'Class:SoftwareInstance/Name' => '%1$s - %2$s',
|
||||
'Class:SoftwareInstance/Attribute:device_id' => 'Dispositivo',
|
||||
'Class:SoftwareInstance/Attribute:device_id+' => '',
|
||||
'Class:SoftwareInstance/Attribute:device_name' => 'Dispositivo',
|
||||
@@ -565,6 +567,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:ApplicationInstance' => 'Instancia de aplicación',
|
||||
'Class:ApplicationInstance+' => '',
|
||||
'Class:ApplicationInstance/Name' => '%1$s - %2$s',
|
||||
));
|
||||
|
||||
//
|
||||
@@ -574,6 +577,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:DBServerInstance' => 'Instancia de Servidor de BD',
|
||||
'Class:DBServerInstance+' => '',
|
||||
'Class:DBServerInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DBServerInstance/Attribute:dbinstance_list' => 'Bases de Datos',
|
||||
'Class:DBServerInstance/Attribute:dbinstance_list+' => 'Fuentes de Bases de Datos',
|
||||
));
|
||||
@@ -585,6 +589,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:DatabaseInstance' => 'Instancia de Base de Datos',
|
||||
'Class:DatabaseInstance+' => '',
|
||||
'Class:DatabaseInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id' => 'Servidor de Base de Datos',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id+' => '',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_version' => 'Versión de Base de Datos',
|
||||
@@ -645,6 +650,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:NetworkInterface' => 'Interfase de Red',
|
||||
'Class:NetworkInterface+' => '',
|
||||
'Class:NetworkInterface/Name' => '%1$s - %2$s',
|
||||
'Class:NetworkInterface/Attribute:device_id' => 'Dispositivo',
|
||||
'Class:NetworkInterface/Attribute:device_id+' => '',
|
||||
'Class:NetworkInterface/Attribute:device_name' => 'Dispositivo',
|
||||
|
||||
@@ -385,6 +385,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:Subnet' => 'Sous-réseau',
|
||||
'Class:Subnet+' => '',
|
||||
'Class:Subnet/Name' => '%1$s / %2$s',
|
||||
//'Class:Subnet/Attribute:name' => 'Name',
|
||||
//'Class:Subnet/Attribute:name+' => '',
|
||||
'Class:Subnet/Attribute:org_id' => 'Organisation',
|
||||
@@ -538,6 +539,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:SoftwareInstance' => 'Instance de logiciel',
|
||||
'Class:SoftwareInstance+' => '',
|
||||
'Class:SoftwareInstance/Name' => '%1$s - %2$s',
|
||||
'Class:SoftwareInstance/Attribute:device_id' => 'Equipement',
|
||||
'Class:SoftwareInstance/Attribute:device_id+' => '',
|
||||
'Class:SoftwareInstance/Attribute:device_name' => 'Equipement',
|
||||
@@ -563,6 +565,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:ApplicationInstance' => 'Instance d\'application',
|
||||
'Class:ApplicationInstance+' => '',
|
||||
'Class:ApplicationInstance/Name' => '%1$s - %2$s',
|
||||
));
|
||||
|
||||
//
|
||||
@@ -572,6 +575,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:DBServerInstance' => 'Instance de serveur de base de données',
|
||||
'Class:DBServerInstance+' => '',
|
||||
'Class:DBServerInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DBServerInstance/Attribute:software_id' => 'Logiciel',
|
||||
'Class:DBServerInstance/Attribute:software_name' => 'Logiciel Serveur',
|
||||
'Class:DBServerInstance/Attribute:dbinstance_list' => 'Bases',
|
||||
@@ -585,6 +589,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:DatabaseInstance' => 'Base de données',
|
||||
'Class:DatabaseInstance+' => '',
|
||||
'Class:DatabaseInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id' => 'Serveur de données',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id+' => '',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_version' => 'Version',
|
||||
@@ -645,6 +650,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:NetworkInterface' => 'Interface réseau',
|
||||
'Class:NetworkInterface+' => '',
|
||||
'Class:NetworkInterface/Name' => '%1$s - %2$s',
|
||||
'Class:NetworkInterface/Attribute:device_id' => 'Equipement',
|
||||
'Class:NetworkInterface/Attribute:device_id+' => '',
|
||||
'Class:NetworkInterface/Attribute:device_name' => 'Equipement',
|
||||
|
||||
@@ -148,7 +148,7 @@ class Person extends Contact
|
||||
(
|
||||
"category" => "bizmodel,searchable,structure",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"name_attcode" => array('first_name', 'name'),
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array("name","first_name","org_id","email"),
|
||||
"db_table" => "person",
|
||||
@@ -167,11 +167,6 @@ class Person extends Contact
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'org_id', 'email', 'phone', 'location_id', 'first_name', 'employee_id'));
|
||||
MetaModel::Init_SetZListItems('list', array('first_name','status', 'org_id', 'email', 'phone', 'location_id'));
|
||||
}
|
||||
|
||||
public function GetName()
|
||||
{
|
||||
return $this->Get('first_name').' '.$this->Get('name');
|
||||
}
|
||||
}
|
||||
class Team extends Contact
|
||||
{
|
||||
@@ -421,7 +416,7 @@ class Subnet extends cmdbAbstractObject
|
||||
(
|
||||
"category" => "bizmodel,searchable,configmgmt",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "ip",
|
||||
"name_attcode" => array('ip', 'ip_mask'),
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array("ip", "ip_mask","org_id", "org_name"),
|
||||
"db_table" => "subnet",
|
||||
@@ -445,11 +440,6 @@ class Subnet extends cmdbAbstractObject
|
||||
MetaModel::Init_SetZListItems('list', array('ip', 'ip_mask', 'org_id'));
|
||||
}
|
||||
|
||||
public function GetName()
|
||||
{
|
||||
return $this->Get('ip').' / '.$this->Get('ip_mask');
|
||||
}
|
||||
|
||||
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
@@ -708,7 +698,7 @@ abstract class SoftwareInstance extends FunctionalCI
|
||||
(
|
||||
"category" => "bizmodel,searchable,configmgmt",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"name_attcode" => array('name', 'device_id_friendlyname'),
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array("name", "device_id", "device_name", "org_id", "owner_name"),
|
||||
"db_table" => "softwareinstance",
|
||||
@@ -732,11 +722,6 @@ abstract class SoftwareInstance extends FunctionalCI
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'status', 'org_id', 'importance', 'device_id', 'version'));
|
||||
}
|
||||
|
||||
public function GetName()
|
||||
{
|
||||
return $this->Get('name').' - '.$this->Get('device_name');
|
||||
}
|
||||
|
||||
public function ComputeValues()
|
||||
{
|
||||
}
|
||||
@@ -773,7 +758,7 @@ class DBServerInstance extends SoftwareInstance
|
||||
(
|
||||
"category" => "bizmodel,searchable,configmgmt",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "software_name",
|
||||
"name_attcode" => array('name', 'device_id_friendlyname'),
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array("name","software_id","software_name","device_id","device_name","org_id","owner_name"),
|
||||
"db_table" => "softwareinstance_dbserver",
|
||||
@@ -802,7 +787,7 @@ class ApplicationInstance extends SoftwareInstance
|
||||
(
|
||||
"category" => "bizmodel,searchable,configmgmt",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "software_name",
|
||||
"name_attcode" => array('name', 'device_id_friendlyname'),
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array("name","software_id","software_name","device_id","device_name","org_id","owner_name"),
|
||||
"db_table" => "softwareinstance_application",
|
||||
@@ -832,7 +817,7 @@ class DatabaseInstance extends FunctionalCI
|
||||
(
|
||||
"category" => "bizmodel,searchable,configmgmt",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"name_attcode" => array('name', 'db_server_instance_name'),
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array("name","org_id","owner_name","db_server_instance_id","db_server_instance_name"),
|
||||
"db_table" => "databaseinstance",
|
||||
@@ -854,10 +839,6 @@ class DatabaseInstance extends FunctionalCI
|
||||
MetaModel::Init_SetZListItems('list', array('status', 'org_id', 'importance', 'db_server_instance_id', 'db_server_instance_version'));
|
||||
}
|
||||
|
||||
public function GetName()
|
||||
{
|
||||
return $this->Get('name').' - '.$this->Get('db_server_instance_name');
|
||||
}
|
||||
public static function GetRelationQueries($sRelCode)
|
||||
{
|
||||
switch ($sRelCode)
|
||||
@@ -1081,7 +1062,7 @@ class NetworkInterface extends ConnectableCI
|
||||
(
|
||||
"category" => "bizmodel,searchable,configmgmt",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"name_attcode" => array('device_id_friendlyname', 'name'),
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array("name","device_id","device_name","org_id"),
|
||||
"db_table" => "networkinterface",
|
||||
@@ -1113,13 +1094,6 @@ class NetworkInterface extends ConnectableCI
|
||||
MetaModel::Init_SetZListItems('list', array('status', 'ip_address', 'importance', 'device_id', 'logical_type', 'physical_type', 'link_type', 'connected_if_device_id'));
|
||||
}
|
||||
|
||||
public function GetName()
|
||||
{
|
||||
return $this->Get('device_name').' - '.$this->Get('name');
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static function GetRelationQueries($sRelCode)
|
||||
{
|
||||
switch ($sRelCode)
|
||||
|
||||
@@ -329,6 +329,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:Subnet' => 'Sub-rede',
|
||||
'Class:Subnet+' => '',
|
||||
'Class:Subnet/Name' => '%1$s / %2$s',
|
||||
//'Class:Subnet/Attribute:name' => 'Nome',
|
||||
//'Class:Subnet/Attribute:name+' => '',
|
||||
'Class:Subnet/Attribute:org_id' => 'Organização',
|
||||
@@ -482,6 +483,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:SoftwareInstance' => 'Software Instance',
|
||||
'Class:SoftwareInstance+' => '',
|
||||
'Class:SoftwareInstance/Name' => '%1$s - %2$s',
|
||||
'Class:SoftwareInstance/Attribute:device_id' => 'Dispositivo',
|
||||
'Class:SoftwareInstance/Attribute:device_id+' => '',
|
||||
'Class:SoftwareInstance/Attribute:device_name' => 'Dispositivo',
|
||||
@@ -507,6 +509,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:ApplicationInstance' => 'Instância Aplicação',
|
||||
'Class:ApplicationInstance+' => '',
|
||||
'Class:ApplicationInstance/Name' => '%1$s - %2$s',
|
||||
));
|
||||
|
||||
//
|
||||
@@ -516,6 +519,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:DBServerInstance' => 'Instâncias DB Server',
|
||||
'Class:DBServerInstance+' => '',
|
||||
'Class:DBServerInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DBServerInstance/Attribute:dbinstance_list' => 'Base de Dados',
|
||||
'Class:DBServerInstance/Attribute:dbinstance_list+' => 'Origem Base de dados',
|
||||
));
|
||||
@@ -527,6 +531,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:DatabaseInstance' => 'Instância Base de Dados',
|
||||
'Class:DatabaseInstance+' => '',
|
||||
'Class:DatabaseInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id' => 'Servidor Base de Dados',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id+' => '',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_version' => 'Versão Base de Dados',
|
||||
@@ -587,6 +592,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:NetworkInterface' => 'Interface de rede',
|
||||
'Class:NetworkInterface+' => '',
|
||||
'Class:NetworkInterface/Name' => '%1$s - %2$s',
|
||||
'Class:NetworkInterface/Attribute:device_id' => 'Dispositivo',
|
||||
'Class:NetworkInterface/Attribute:device_id+' => '',
|
||||
'Class:NetworkInterface/Attribute:device_name' => 'Dispositivo',
|
||||
|
||||
@@ -391,6 +391,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'Class:Subnet' => 'Подсеть',
|
||||
'Class:Subnet+' => '',
|
||||
'Class:Subnet/Name' => '%1$s / %2$s',
|
||||
//'Class:Subnet/Attribute:name' => 'Name',
|
||||
//'Class:Subnet/Attribute:name+' => '',
|
||||
'Class:Subnet/Attribute:org_id' => 'Организация-владелец',
|
||||
@@ -544,6 +545,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'Class:SoftwareInstance' => 'Экземпляры ПО',
|
||||
'Class:SoftwareInstance+' => '',
|
||||
'Class:SoftwareInstance/Name' => '%1$s - %2$s',
|
||||
'Class:SoftwareInstance/Attribute:device_id' => 'Устройство',
|
||||
'Class:SoftwareInstance/Attribute:device_id+' => '',
|
||||
'Class:SoftwareInstance/Attribute:device_name' => 'Устройство',
|
||||
@@ -567,6 +569,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'Class:ApplicationInstance' => 'Экземпляры приложений',
|
||||
'Class:ApplicationInstance+' => '',
|
||||
'Class:ApplicationInstance/Name' => '%1$s - %2$s',
|
||||
'Class:ApplicationInstance/Attribute:software_id' => 'ПО',
|
||||
'Class:ApplicationInstance/Attribute:software_id+' => '',
|
||||
'Class:ApplicationInstance/Attribute:software_name' => 'Название',
|
||||
@@ -581,6 +584,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'Class:DBServerInstance' => 'Экземпляры серверов баз данных',
|
||||
'Class:DBServerInstance+' => '',
|
||||
'Class:DBServerInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DBServerInstance/Attribute:software_id' => 'ПО',
|
||||
'Class:DBServerInstance/Attribute:software_id+' => '',
|
||||
'Class:DBServerInstance/Attribute:software_name' => 'Название',
|
||||
@@ -597,6 +601,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'Class:DatabaseInstance' => 'Экземпляры баз данных',
|
||||
'Class:DatabaseInstance+' => '',
|
||||
'Class:DatabaseInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id' => 'Сервер базы данных',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id+' => '',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_version' => 'Версия базы данных',
|
||||
@@ -657,6 +662,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'Class:NetworkInterface' => 'Сетевой интерфейс',
|
||||
'Class:NetworkInterface+' => '',
|
||||
'Class:NetworkInterface/Name' => '%1$s - %2$s',
|
||||
'Class:NetworkInterface/Attribute:device_id' => 'Устройство',
|
||||
'Class:NetworkInterface/Attribute:device_id+' => '',
|
||||
'Class:NetworkInterface/Attribute:device_name' => 'Устройство',
|
||||
|
||||
@@ -391,6 +391,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
'Class:Subnet' => 'Subnet',
|
||||
'Class:Subnet+' => '',
|
||||
'Class:Subnet/Name' => '%1$s / %2$s',
|
||||
//'Class:Subnet/Attribute:name' => 'Adı',
|
||||
//'Class:Subnet/Attribute:name+' => '',
|
||||
'Class:Subnet/Attribute:org_id' => 'Kurum',
|
||||
@@ -544,6 +545,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
'Class:SoftwareInstance' => 'Yazılım Kurulumu',
|
||||
'Class:SoftwareInstance+' => '',
|
||||
'Class:SoftwareInstance/Name' => '%1$s - %2$s',
|
||||
'Class:SoftwareInstance/Attribute:device_id' => 'Cihaz',
|
||||
'Class:SoftwareInstance/Attribute:device_id+' => '',
|
||||
'Class:SoftwareInstance/Attribute:device_name' => 'Cihaz',
|
||||
@@ -567,6 +569,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
'Class:ApplicationInstance' => 'Uygulama Kurulumu',
|
||||
'Class:ApplicationInstance+' => '',
|
||||
'Class:ApplicationInstance/Name' => '%1$s - %2$s',
|
||||
'Class:ApplicationInstance/Attribute:software_id' => 'Yazılım',
|
||||
'Class:ApplicationInstance/Attribute:software_id+' => '',
|
||||
'Class:ApplicationInstance/Attribute:software_name' => 'Adı',
|
||||
@@ -581,6 +584,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
'Class:DBServerInstance' => 'Veritabanı Sunucusu',
|
||||
'Class:DBServerInstance+' => '',
|
||||
'Class:DBServerInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DBServerInstance/Attribute:software_id' => 'Yazılım',
|
||||
'Class:DBServerInstance/Attribute:software_id+' => '',
|
||||
'Class:DBServerInstance/Attribute:software_name' => 'Adı',
|
||||
@@ -597,6 +601,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
'Class:DatabaseInstance' => 'Veritabanı',
|
||||
'Class:DatabaseInstance+' => '',
|
||||
'Class:DatabaseInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id' => 'Veritabanı sunucusu',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id+' => '',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_version' => 'Veritabanı versiyonu',
|
||||
@@ -657,6 +662,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
'Class:NetworkInterface' => 'Network arayüzü',
|
||||
'Class:NetworkInterface+' => '',
|
||||
'Class:NetworkInterface/Name' => '%1$s - %2$s',
|
||||
'Class:NetworkInterface/Attribute:device_id' => 'Cihaz',
|
||||
'Class:NetworkInterface/Attribute:device_id+' => '',
|
||||
'Class:NetworkInterface/Attribute:device_name' => 'Cihaz',
|
||||
|
||||
@@ -393,6 +393,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:Subnet' => '子网',
|
||||
'Class:Subnet+' => '',
|
||||
'Class:Subnet/Name' => '%1$s / %2$s',
|
||||
//'Class:Subnet/Attribute:name' => 'Name',
|
||||
//'Class:Subnet/Attribute:name+' => '',
|
||||
'Class:Subnet/Attribute:org_id' => '拥有者组织',
|
||||
@@ -546,6 +547,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:SoftwareInstance' => '软件实例',
|
||||
'Class:SoftwareInstance+' => '',
|
||||
'Class:SoftwareInstance/Name' => '%1$s - %2$s',
|
||||
'Class:SoftwareInstance/Attribute:device_id' => '设备',
|
||||
'Class:SoftwareInstance/Attribute:device_id+' => '',
|
||||
'Class:SoftwareInstance/Attribute:device_name' => '设备',
|
||||
@@ -569,6 +571,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:ApplicationInstance' => '应用实例',
|
||||
'Class:ApplicationInstance+' => '',
|
||||
'Class:ApplicationInstance/Name' => '%1$s - %2$s',
|
||||
'Class:ApplicationInstance/Attribute:software_id' => '软件',
|
||||
'Class:ApplicationInstance/Attribute:software_id+' => '',
|
||||
'Class:ApplicationInstance/Attribute:software_name' => '名称',
|
||||
@@ -583,6 +586,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:DBServerInstance' => 'DB Server 实例',
|
||||
'Class:DBServerInstance+' => '',
|
||||
'Class:DBServerInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DBServerInstance/Attribute:software_id' => '软件',
|
||||
'Class:DBServerInstance/Attribute:software_id+' => '',
|
||||
'Class:DBServerInstance/Attribute:software_name' => '名称',
|
||||
@@ -599,6 +603,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:DatabaseInstance' => 'Database 实例',
|
||||
'Class:DatabaseInstance+' => '',
|
||||
'Class:DatabaseInstance/Name' => '%1$s - %2$s',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id' => '数据库服务器',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_id+' => '',
|
||||
'Class:DatabaseInstance/Attribute:db_server_instance_version' => '数据库版本',
|
||||
@@ -659,6 +664,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:NetworkInterface' => '网络接口',
|
||||
'Class:NetworkInterface+' => '',
|
||||
'Class:NetworkInterface/Name' => '%1$s - %2$s',
|
||||
'Class:NetworkInterface/Attribute:device_id' => '设备',
|
||||
'Class:NetworkInterface/Attribute:device_id+' => '',
|
||||
'Class:NetworkInterface/Attribute:device_name' => '设备',
|
||||
|
||||
@@ -521,7 +521,14 @@ try
|
||||
throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'id'));
|
||||
}
|
||||
|
||||
if (is_numeric($id))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($sClass, $id, false /* MustBeFound */);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObj = MetaModel::GetObjectByName($sClass, $id, false /* MustBeFound */);
|
||||
}
|
||||
if (is_null($oObj))
|
||||
{
|
||||
$oP->set_title(Dict::S('UI:ErrorPageTitle'));
|
||||
|
||||
@@ -274,30 +274,6 @@ try
|
||||
$oPage->Add("<input type=\"button\" class=\"jqmClose\" value=\" Close \" />\n");
|
||||
break;
|
||||
|
||||
case 'ui.linkswidget':
|
||||
/*
|
||||
$sClass = utils::ReadParam('sclass', 'bizContact');
|
||||
$sAttCode = utils::ReadParam('attCode', 'name');
|
||||
$sOrg = utils::ReadParam('org_id', '');
|
||||
$sName = utils::ReadParam('q', '');
|
||||
$iMaxCount = utils::ReadParam('max', 30);
|
||||
UILinksWidget::Autocomplete($oPage, $sClass, $sAttCode, $sName, $iMaxCount);
|
||||
*/
|
||||
break;
|
||||
|
||||
case 'ui.linkswidget.linkedset':
|
||||
/*
|
||||
$sClass = utils::ReadParam('sclass', 'bizContact');
|
||||
$sJSONSet = stripslashes(utils::ReadParam('sset', ''));
|
||||
$sExtKeyToMe = utils::ReadParam('sextkeytome', '');
|
||||
$sExtKeyToRemote = utils::ReadParam('sextkeytoremote', '');
|
||||
$iObjectId = utils::ReadParam('id', -1);
|
||||
UILinksWidget::RenderSet($oPage, $sClass, $sJSONSet, $sExtKeyToMe, $sExtKeyToRemote, $iObjectId);
|
||||
$iFieldId = utils::ReadParam('myid', '-1');
|
||||
$oPage->add_ready_script("$('#{$iFieldId}').trigger('validate');");
|
||||
*/
|
||||
break;
|
||||
|
||||
case 'autocomplete':
|
||||
$key = utils::ReadParam('id', 0);
|
||||
$sClass = utils::ReadParam('sclass', 'bizContact');
|
||||
|
||||
@@ -50,7 +50,6 @@ class TestSQLQuery extends TestScenarioOnDB
|
||||
$sTable = 'myTable',
|
||||
$sTableAlias = 'myTableAlias',
|
||||
$aFields = array('column1'=>new FieldExpression('column1', 'myTableAlias'), 'column2'=>new FieldExpression('column2', 'myTableAlias')),
|
||||
$oCondition = new BinaryExpression(new FieldExpression('column1', 'myTableAlias'), 'LIKE', new ScalarExpression('trash')),
|
||||
$aFullTextNeedles = array('column1'),
|
||||
$bToDelete = false,
|
||||
$aValues = array()
|
||||
@@ -61,7 +60,6 @@ class TestSQLQuery extends TestScenarioOnDB
|
||||
$sTable = 'myTable1',
|
||||
$sTableAlias = 'myTable1Alias',
|
||||
$aFields = array('column1_1'=>new FieldExpression('column1', 'myTableAlias'), 'column1_2'=>new FieldExpression('column1', 'myTableAlias')),
|
||||
$oCondition = new TrueSQLExpression,
|
||||
$aFullTextNeedles = array(),
|
||||
$bToDelete = false,
|
||||
$aValues = array()
|
||||
@@ -71,7 +69,6 @@ class TestSQLQuery extends TestScenarioOnDB
|
||||
$sTable = 'myTable2',
|
||||
$sTableAlias = 'myTable2Alias',
|
||||
$aFields = array('column2_1'=>new FieldExpression('column2', 'myTableAlias'), 'column2_2'=>new FieldExpression('column2', 'myTableAlias')),
|
||||
$oCondition = new TrueSQLExpression,
|
||||
$aFullTextNeedles = array(),
|
||||
$bToDelete = false,
|
||||
$aValues = array()
|
||||
@@ -1069,7 +1066,7 @@ class TestFullTextSearchOnFarm extends MyFarm
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Benchmark queries
|
||||
// Test queries
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TestItopEfficiency extends TestBizModel
|
||||
@@ -1193,6 +1190,118 @@ class TestItopEfficiency extends TestBizModel
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Benchmark queries
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TestQueries extends TestBizModel
|
||||
{
|
||||
static public function GetName()
|
||||
{
|
||||
return 'Itop - queries';
|
||||
}
|
||||
|
||||
static public function GetDescription()
|
||||
{
|
||||
return 'Try as many queries as possible';
|
||||
}
|
||||
|
||||
static public function GetConfigFile() {return '/config-itop.php';}
|
||||
|
||||
protected function DoBenchmark($sOqlQuery)
|
||||
{
|
||||
echo "<h5>Testing query: $sOqlQuery</h5>";
|
||||
|
||||
$fStart = MyHelpers::getmicrotime();
|
||||
$oFilter = DBObjectSearch::FromOQL($sOqlQuery);
|
||||
$fParsingDuration = MyHelpers::getmicrotime() - $fStart;
|
||||
|
||||
$fStart = MyHelpers::getmicrotime();
|
||||
$sSQL = MetaModel::MakeSelectQuery($oFilter);
|
||||
$fBuildDuration = MyHelpers::getmicrotime() - $fStart;
|
||||
|
||||
$fStart = MyHelpers::getmicrotime();
|
||||
$res = CMDBSource::Query($sSQL);
|
||||
$fQueryDuration = MyHelpers::getmicrotime() - $fStart;
|
||||
|
||||
// The fetch could not be repeated with the same results
|
||||
// But we've seen so far that is was very very quick to exec
|
||||
// So it makes sense to benchmark it a single time
|
||||
$fStart = MyHelpers::getmicrotime();
|
||||
$aRow = CMDBSource::FetchArray($res);
|
||||
$fDuration = MyHelpers::getmicrotime() - $fStart;
|
||||
$fFetchDuration = $fDuration;
|
||||
|
||||
$fStart = MyHelpers::getmicrotime();
|
||||
$sOql = $oFilter->ToOQL();
|
||||
$fToOqlDuration = MyHelpers::getmicrotime() - $fStart;
|
||||
|
||||
if (false)
|
||||
{
|
||||
echo "<ul style=\"font-size:smaller;\">\n";
|
||||
echo "<li>Parsing: $fParsingDuration</li>\n";
|
||||
echo "<li>Build: $fBuildDuration</li>\n";
|
||||
echo "<li>Query: $fQueryDuration</li>\n";
|
||||
echo "<li>Fetch: $fFetchDuration</li>\n";
|
||||
echo "<li>ToOql: $fToOqlDuration</li>\n";
|
||||
echo "</ul>\n";
|
||||
}
|
||||
|
||||
// Everything but the ToOQL (wich is interesting, anyhow)
|
||||
$fTotal = $fParsingDuration + $fBuildDuration + $fQueryDuration + $fFetchDuration;
|
||||
|
||||
return array(
|
||||
'rows' => CMDBSource::NbRows($res),
|
||||
'duration (s)' => round($fTotal, 4),
|
||||
'parsing (%)' => round(100 * $fParsingDuration / $fTotal, 1),
|
||||
'build SQL (%)' => round(100 * $fBuildDuration / $fTotal, 1),
|
||||
'query exec (%)' => round(100 * $fQueryDuration / $fTotal, 1),
|
||||
'fetch (%)' => round(100 * $fFetchDuration / $fTotal, 1),
|
||||
'to OQL (%)' => round(100 * $fToOqlDuration / $fTotal, 1),
|
||||
'parsing+build (%)' => round(100 * ($fParsingDuration + $fBuildDuration) / $fTotal, 1),
|
||||
);
|
||||
}
|
||||
|
||||
protected function DoExecute()
|
||||
{
|
||||
$aQueries = array(
|
||||
'SELECT Person AS PP WHERE PP.friendlyname LIKE "%dali"',
|
||||
'SELECT Person AS PP WHERE PP.location_id_friendlyname LIKE "%ce ch%"',
|
||||
'SELECT Organization AS OO JOIN Person AS PP ON PP.org_id = OO.id',
|
||||
'SELECT lnkTeamToContact AS lnk JOIN Team AS T ON lnk.team_id = T.id',
|
||||
'SELECT lnkTeamToContact AS lnk JOIN Team AS T ON lnk.team_id = T.id JOIN Contact AS C ON lnk.contact_id = C.id',
|
||||
'SELECT Incident JOIN Person ON Incident.agent_id = Person.id WHERE Person.id = 5',
|
||||
// this one is failing...
|
||||
//'SELECT L, P FROM Person AS P JOIN Location AS L ON P.location_id = L.id',
|
||||
);
|
||||
foreach (MetaModel::GetClasses() as $sClass)
|
||||
{
|
||||
$aQueries[] = 'SELECT '.$sClass;
|
||||
$aQueries[] = 'SELECT '.$sClass.' AS zz';
|
||||
$aQueries[] = 'SELECT '.$sClass.' AS zz WHERE id = 1';
|
||||
}
|
||||
$aStats = array();
|
||||
foreach ($aQueries as $sOQL)
|
||||
{
|
||||
$aStats[$sOQL] = $this->DoBenchmark($sOQL);
|
||||
}
|
||||
|
||||
$aData = array();
|
||||
foreach ($aStats as $sOQL => $aResults)
|
||||
{
|
||||
$aValues = array();
|
||||
$aValues['OQL'] = htmlentities($sOQL);
|
||||
|
||||
foreach($aResults as $sDesc => $sInfo)
|
||||
{
|
||||
$aValues[$sDesc] = htmlentities($sInfo);
|
||||
}
|
||||
$aData[] = $aValues;
|
||||
}
|
||||
echo MyHelpers::make_table_from_assoc_array($aData);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Test bulk load API
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user