mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-16 08:54:12 +01:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf646b772e | ||
|
|
735cd28dfd | ||
|
|
12d0c865c2 | ||
|
|
071f268a59 | ||
|
|
d8905c63b8 | ||
|
|
f454ebf4b5 | ||
|
|
5b4057aebb | ||
|
|
e2524d28d7 | ||
|
|
5a09dc6e2b | ||
|
|
10fa31807b | ||
|
|
22a0030a62 | ||
|
|
5f91c8ccc0 |
@@ -455,8 +455,7 @@ abstract class cmdbAbstractObject extends CMDBObject
|
||||
{
|
||||
$aHeader[] = MetaModel::GetLabel($sClassName, $sAttCode);
|
||||
}
|
||||
$sHtml = '#'.$oSet->GetFilter()->ToOQL()."\n";
|
||||
$sHtml .= implode($sSeparator, $aHeader)."\n";
|
||||
$sHtml = implode($sSeparator, $aHeader)."\n";
|
||||
$oSet->Seek(0);
|
||||
while ($oObj = $oSet->Fetch())
|
||||
{
|
||||
@@ -464,7 +463,7 @@ abstract class cmdbAbstractObject extends CMDBObject
|
||||
$aRow[] = $oObj->GetKey();
|
||||
foreach($aList as $sAttCode)
|
||||
{
|
||||
$aRow[] = $oObj->GetAsCSV($sAttCode, $sSeparator, '\\');
|
||||
$aRow[] = $oObj->GetAsCSV($sAttCode, $sSeparator, $sTextQualifier);
|
||||
}
|
||||
$sHtml .= implode($sSeparator, $aRow)."\n";
|
||||
}
|
||||
|
||||
@@ -296,10 +296,12 @@ class DisplayBlock
|
||||
{
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
$aGroupBy = array();
|
||||
$sLabels = array();
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
{
|
||||
$sValue = $oObj->GetAsHtml($sGroupByField);
|
||||
$sValue = $oObj->Get($sGroupByField);
|
||||
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
|
||||
$sLabels[$sValue] = $oObj->GetAsHtml($sGroupByField);
|
||||
}
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
$aData = array();
|
||||
@@ -307,7 +309,7 @@ class DisplayBlock
|
||||
$sParams = $oAppContext->GetForLink();
|
||||
foreach($aGroupBy as $sValue => $iCount)
|
||||
{
|
||||
$aData[] = array ( 'group' => $sValue,
|
||||
$aData[] = array ( 'group' => $sLabels[$sValue],
|
||||
'value' => "<a href=\"./UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter&$sGroupByField=".urlencode($sValue)."\">$iCount</a>"); // TO DO: add the context information
|
||||
}
|
||||
$sHtml .= $oPage->GetTable(array('group' => array('label' => MetaModel::GetLabel($this->m_oFilter->GetClass(), $sGroupByField), 'description' => ''), 'value' => array('label'=>'Count', 'description' => 'Number of elements')), $aData);
|
||||
|
||||
@@ -53,7 +53,7 @@ class NiceWebPage extends WebPage
|
||||
foreach($aChoices as $sKey => $sValue)
|
||||
{
|
||||
$sSelected = ($sKey == $sDefaultValue) ? " SELECTED" : "";
|
||||
$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"$sKey\"$sSelected>$sValue</option>");
|
||||
$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"".htmlspecialchars($sKey)."\"$sSelected>".htmlentities($sValue)."</option>");
|
||||
}
|
||||
$this->add("</select>");
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ class UILinksWizard
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sFieldCode);
|
||||
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sClass, $sFieldCode, $oAttDef, '' /* TO DO/ call GetDefaultValue */, '' /* DisplayValue */, '' /* id */, $sNameSuffix);
|
||||
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sClass, $sFieldCode, $oAttDef, '' /* TO DO/ call GetDefaultValue($oObject->ToArgs()) */, '' /* DisplayValue */, '' /* id */, $sNameSuffix);
|
||||
}
|
||||
}
|
||||
foreach(MetaModel::GetZListItems($this->m_sLinkedClass, 'list') as $sFieldCode)
|
||||
|
||||
@@ -58,8 +58,8 @@ class UIWizard
|
||||
$aOptions[] = 'Prerequisites: '.implode(', ', $aPrerequisites);
|
||||
}
|
||||
|
||||
$sFieldFlag = ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) ? ' <span class="hilite">*</span>' : '';
|
||||
$oDefaultValuesSet = $oAttDef->GetDefaultValue(); // @@@ TO DO: get the object's current value if the object exists
|
||||
$sFieldFlag = (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) || (!$oAttDef->IsNullAllowed()) )? ' <span class="hilite">*</span>' : '';
|
||||
$oDefaultValuesSet = $oAttDef->GetDefaultValue(/* $oObject->ToArgs() */); // @@@ TO DO: get the object's current value if the object exists
|
||||
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId", '', $iOptions, $aArgs);
|
||||
$aFieldsMap[$iMaxInputId] = $sAttCode;
|
||||
$aDetails[] = array('label' => $oAttDef->GetLabel().$sFieldFlag, 'value' => "<div id=\"field_$iMaxInputId\">$sHTMLValue</div>");
|
||||
@@ -145,46 +145,52 @@ $sJSHandlerCode
|
||||
$aFieldsDone = array(); // Store all the fields that are already covered by a previous step of the wizard
|
||||
|
||||
$aStates = MetaModel::EnumStates($this->m_sClass);
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
|
||||
|
||||
$aMandatoryAttributes = array();
|
||||
// Some attributes are always mandatory independently of the state machine (if any)
|
||||
foreach(MetaModel::GetAttributesList($this->m_sClass) as $sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed())
|
||||
if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() &&
|
||||
($sAttCode != 'finalclass') && ($sAttCode != $sStateAttCode) )
|
||||
{
|
||||
$aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY;
|
||||
}
|
||||
}
|
||||
|
||||
// Now check the attributes that are mandatory in the specified state
|
||||
if ( (!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0) )
|
||||
if ( (!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0) )
|
||||
{
|
||||
// Check all the fields that *must* be included in the wizard for this
|
||||
// particular target state
|
||||
$aFields = array();
|
||||
foreach($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions)
|
||||
{
|
||||
if (isset($aMandatoryAttributes[$sAttCode]))
|
||||
{
|
||||
$aMandatoryAttributes[$sAttCode] |= $iOptions;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aMandatoryAttributes[$sAttCode] = $iOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check all the fields that *must* be included in the wizard
|
||||
if ( (isset($aMandatoryAttributes[$sAttCode])) &&
|
||||
($aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) )
|
||||
{
|
||||
$aMandatoryAttributes[$sAttCode] |= $iOptions;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aMandatoryAttributes[$sAttCode] = $iOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check all the fields that *must* be included in the wizard
|
||||
// i.e. all mandatory, must-change or must-prompt fields that are
|
||||
// not also read-only or hidden.
|
||||
// Some fields may be required (null not allowed) from the database
|
||||
// perspective, but hidden or read-only from the user interface perspective
|
||||
$aFields = array();
|
||||
foreach($aMandatoryAttributes as $sAttCode => $iOptions)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
$sAttLabel = $oAttDef->GetLabel();
|
||||
|
||||
if ( ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) )
|
||||
if ( ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) &&
|
||||
!($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN)) )
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
|
||||
$aFields[$sAttCode] = array();
|
||||
foreach($aPrerequisites as $sCode)
|
||||
@@ -227,7 +233,6 @@ $sJSHandlerCode
|
||||
|
||||
|
||||
// Now computes the steps to fill the optional fields
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
|
||||
$aFields = array(); // reset
|
||||
foreach(MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
@@ -279,7 +284,7 @@ $sJSHandlerCode
|
||||
if (count($aCurrentStep) == 0)
|
||||
{
|
||||
// This step of the wizard would contain NO field !
|
||||
$oPage->add("<strong>Error:</strong> Circular reference in the dependencies between the fields.");
|
||||
$this->m_oPage->add("<strong>Error:</strong> Circular reference in the dependencies between the fields.");
|
||||
print_r($aFields);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -42,26 +42,26 @@ class bizIncidentTicket extends cmdbAbstractObject
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("label"=>"Ticket Ref", "description"=>"Refence number ofr this incident", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("title", array("label"=>"Title", "description"=>"Overview of the Incident", "allowed_values"=>null, "sql"=>"title", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("type", array("label"=>"Type", "description"=>"Type of the Incident", "allowed_values"=>new ValueSetEnum("Network,Server,Desktop,Application"), "sql"=>"type", "default_value"=>"Server", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("org_id", array("targetclass"=>"bizOrganization", "label"=>"Customer", "description"=>"who is impacted by the ticket", "allowed_values"=>null, "sql"=>"customer", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("type", array("label"=>"Type", "description"=>"Type of the Incident", "allowed_values"=>new ValueSetEnum("Network,Server,Desktop,Application"), "sql"=>"type", "default_value"=>"Server", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("org_id", array("targetclass"=>"bizOrganization", "label"=>"Customer", "description"=>"who is impacted by the ticket", "allowed_values"=>null, "sql"=>"customer", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("customer_name", array("label"=>"Customer", "description"=>"Name of the customer impacted by this ticket", "allowed_values"=>null, "extkey_attcode"=> 'org_id', "target_attcode"=>"name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("ticket_status", array("label"=>"Status", "description"=>"Status of the ticket", "allowed_values"=>new ValueSetEnum("New, Assigned, WorkInProgress, Resolved, Closed"), "sql"=>"ticket_status", "default_value"=>"New", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
// SetPossibleValues("status",array("Open","Monitored","Closed"));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("initial_situation", array("label"=>"Initial Situation", "description"=>"Initial situation of the Incident", "allowed_values"=>null, "sql"=>"initial_situation", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("current_situation", array("label"=>"Current Situation", "description"=>"Current situation of the Incident", "allowed_values"=>null, "sql"=>"current_situation", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDate("start_date", array("label"=>"Starting date", "description"=>"Incident starting date", "allowed_values"=>null, "sql"=>"start_date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
// définir une date de défaut à maintenant, alias creation ou modification du ticket
|
||||
// définir une date de défaut à maintenant, alias creation ou modification du ticket
|
||||
MetaModel::Init_AddAttribute(new AttributeDate("last_update", array("label"=>"Last update", "description"=>"last time the Ticket was modified", "allowed_values"=>null, "sql"=>"last_update", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDate("next_update", array("label"=>"Next update", "description"=>"next time the Ticket is expected to be modified", "allowed_values"=>null, "sql"=>"next_update", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDate("next_update", array("label"=>"Next update", "description"=>"next time the Ticket is expected to be modified", "allowed_values"=>null, "sql"=>"next_update", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeDate("end_date", array("label"=>"Closure Date", "description"=>"Date when the Ticket was closed", "allowed_values"=>null, "sql"=>"closed_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("caller_id", array("targetclass"=>"bizPerson", "jointype"=> "", "label"=>"Caller", "description"=>"person that trigger incident", "allowed_values"=>new ValueSetObjects('SELECT bizPerson AS p WHERE p.org_id = :this->org_id'), "sql"=>"caller_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array("org_id"))));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("caller_id", array("targetclass"=>"bizPerson", "jointype"=> "", "label"=>"Caller", "description"=>"person that trigger incident", "allowed_values"=>new ValueSetObjects('SELECT bizPerson AS p WHERE p.org_id = :this->org_id'), "sql"=>"caller_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array("org_id"))));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("caller_mail", array("label"=>"Caller", "description"=>"Person that trigger this incident", "allowed_values"=>null, "extkey_attcode"=> 'caller_id', "target_attcode"=>"email")));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("impact", array("label"=>"Impact", "description"=>"Impact of the Incident", "allowed_values"=>null, "sql"=>"impact", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("workgroup_id", array("targetclass"=>"bizWorkgroup", "jointype"=> "", "label"=>"Workgroup", "description"=>"which workgroup is owning ticket", "allowed_values"=>null, "sql"=>"workgroup_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("impact", array("label"=>"Impact", "description"=>"Impact of the Incident", "allowed_values"=>null, "sql"=>"impact", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("workgroup_id", array("targetclass"=>"bizWorkgroup", "jointype"=> "", "label"=>"Workgroup", "description"=>"which workgroup is owning ticket", "allowed_values"=>null, "sql"=>"workgroup_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("workgroup_name", array("label"=>"Workgroup", "description"=>"name of workgroup managing the Ticket", "allowed_values"=>null, "extkey_attcode"=> 'workgroup_id', "target_attcode"=>"name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("agent_id", array("targetclass"=>"bizPerson", "jointype"=> "", "label"=>"Agent", "description"=>"who is managing the ticket", "allowed_values"=>new ValueSetObjects('SELECT bizPerson AS p JOIN lnkContactTeam AS l ON l.contact_id=p.id JOIN bizTeam AS t ON l.team_id=t.id JOIN bizWorkgroup AS w ON w.team_id=t.id WHERE w.id = :this->workgroup_id'), "sql"=>"agent_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array('workgroup_id'))));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("agent_id", array("targetclass"=>"bizPerson", "jointype"=> "", "label"=>"Agent", "description"=>"who is managing the ticket", "allowed_values"=>new ValueSetObjects('SELECT bizPerson AS p JOIN lnkContactTeam AS l ON l.contact_id=p.id JOIN bizTeam AS t ON l.team_id=t.id JOIN bizWorkgroup AS w ON w.team_id=t.id WHERE w.id = :this->workgroup_id'), "sql"=>"agent_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array('workgroup_id'))));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("agent_mail", array("label"=>"Agent", "description"=>"mail of agent managing the Ticket", "allowed_values"=>null, "extkey_attcode"=> 'agent_id', "target_attcode"=>"email")));
|
||||
// Comment afficher le first + last name de l'agent ? Est-ce utile d'ajouter ce champ?
|
||||
MetaModel::Init_AddAttribute(new AttributeText("action_log", array("label"=>"Action Logs", "description"=>"List all action performed during the incident", "allowed_values"=>null, "sql"=>"action_log", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
@@ -61,6 +61,7 @@ abstract class AttributeDefinition
|
||||
private $m_aParams = array();
|
||||
private $m_sHostClass = array();
|
||||
protected function Get($sParamName) {return $this->m_aParams[$sParamName];}
|
||||
protected function IsParam($sParamName) {return (array_key_exists($sParamName, $this->m_aParams));}
|
||||
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
@@ -129,6 +130,7 @@ abstract class AttributeDefinition
|
||||
public function IsExternalField() {return false;}
|
||||
public function IsWritable() {return false;}
|
||||
public function IsNullAllowed() {return true;}
|
||||
public function GetNullValue() {return null;}
|
||||
public function GetCode() {return $this->m_sCode;}
|
||||
public function GetLabel() {return $this->Get("label");}
|
||||
public function GetDescription() {return $this->Get("description");}
|
||||
@@ -194,9 +196,9 @@ abstract class AttributeDefinition
|
||||
return Str::pure2xml((string)$sValue);
|
||||
}
|
||||
|
||||
public function GetAsCSV($sValue, $sSeparator = ';', $sSepEscape = ',')
|
||||
public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"')
|
||||
{
|
||||
return str_replace($sSeparator, $sSepEscape, (string)$sValue);
|
||||
return (string)$sValue;
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sBeginsWith = '')
|
||||
@@ -233,7 +235,22 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
|
||||
public function GetValuesDef() {return $this->Get("allowed_values");}
|
||||
public function GetPrerequisiteAttributes() {return $this->Get("depends_on");}
|
||||
public function GetDefaultValue() {return DBObjectSet::FromScratch($this->Get('linked_class'));}
|
||||
public function GetDefaultValue($aArgs = array())
|
||||
{
|
||||
// Note: so far, this feature is a prototype,
|
||||
// later, the argument 'this' should always be present in the arguments
|
||||
//
|
||||
if (($this->IsParam('default_value')) && array_key_exists('this', $aArgs))
|
||||
{
|
||||
$aValues = $this->Get('default_value')->GetValues($aArgs);
|
||||
$oSet = DBObjectSet::FromArray($this->Get('linked_class'), $aValues);
|
||||
return $oSet;
|
||||
}
|
||||
else
|
||||
{
|
||||
return DBObjectSet::FromScratch($this->Get('linked_class'));
|
||||
}
|
||||
}
|
||||
|
||||
public function GetLinkedClass() {return $this->Get('linked_class');}
|
||||
public function GetExtKeyToMe() {return $this->Get('ext_key_to_me');}
|
||||
@@ -252,7 +269,7 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
return "ERROR: LIST OF OBJECTS";
|
||||
}
|
||||
|
||||
public function GetAsCSV($sValue, $sSeparator = ';', $sSepEscape = ',')
|
||||
public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"')
|
||||
{
|
||||
return "ERROR: LIST OF OBJECTS";
|
||||
}
|
||||
@@ -312,7 +329,6 @@ class AttributeDBFieldVoid extends AttributeDefinition
|
||||
public function IsNullAllowed() {return false;}
|
||||
|
||||
protected function ScalarToSQL($value) {return $value;} // format value as a valuable SQL literal (quoted outside)
|
||||
protected function SQLToScalar($value) {return $value;} // take the result of a fetch... and make it a PHP variable
|
||||
|
||||
public function GetSQLExpressions()
|
||||
{
|
||||
@@ -467,12 +483,6 @@ class AttributeInteger extends AttributeDBField
|
||||
assert(is_numeric($value));
|
||||
return $value; // supposed to be an int
|
||||
}
|
||||
public function SQLToScalar($value)
|
||||
{
|
||||
// Use cast (int) or intval() ?
|
||||
return (int)$value;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -509,11 +519,6 @@ class AttributeBoolean extends AttributeInteger
|
||||
if ($value) return 1;
|
||||
return 0;
|
||||
}
|
||||
public function SQLToScalar($value)
|
||||
{
|
||||
// Use cast (int) or intval() ?
|
||||
return (int)$value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -594,9 +599,13 @@ class AttributeString extends AttributeDBField
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
public function SQLToScalar($value)
|
||||
|
||||
public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"')
|
||||
{
|
||||
return $value;
|
||||
$sFrom = array("\r\n", $sTextQualifier);
|
||||
$sTo = array("\n", $sTextQualifier.$sTextQualifier);
|
||||
$sEscaped = str_replace($sFrom, $sTo, (string)$sValue);
|
||||
return '"'.$sEscaped.'"';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,11 +687,6 @@ class AttributeText extends AttributeString
|
||||
{
|
||||
return Str::pure2xml($value);
|
||||
}
|
||||
|
||||
public function GetAsCSV($value, $sSeparator = ';', $sSepEscape = ',')
|
||||
{
|
||||
return str_replace("\n", "[newline]", parent::GetAsCSV($sValue, $sSeparator, $sSepEscape));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -967,10 +971,6 @@ class AttributeDate extends AttributeDBField
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
public function SQLToScalar($value)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function GetAsHTML($value)
|
||||
{
|
||||
@@ -982,9 +982,12 @@ class AttributeDate extends AttributeDBField
|
||||
return Str::pure2xml($value);
|
||||
}
|
||||
|
||||
public function GetAsCSV($value, $sSeparator = ';', $sSepEscape = ',')
|
||||
public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"')
|
||||
{
|
||||
return str_replace($sSeparator, $sSepEscape, $value);
|
||||
$sFrom = array("\r\n", $sTextQualifier);
|
||||
$sTo = array("\n", $sTextQualifier.$sTextQualifier);
|
||||
$sEscaped = str_replace($sFrom, $sTo, (string)$sValue);
|
||||
return '"'.$sEscaped.'"';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1025,6 +1028,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
|
||||
public function GetDefaultValue() {return 0;}
|
||||
public function IsNullAllowed() {return $this->Get("is_null_allowed");}
|
||||
public function GetNullValue() {return 0;}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
@@ -1071,6 +1075,11 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
{
|
||||
return $this->Get("on_target_delete");
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue)
|
||||
{
|
||||
return (int)$proposedValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1204,11 +1213,6 @@ class AttributeExternalField extends AttributeDefinition
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
return $oExtAttDef->ScalarToSQL($value);
|
||||
}
|
||||
public function SQLToScalar($value)
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
return $oExtAttDef->SQLToScalar($value);
|
||||
}
|
||||
|
||||
|
||||
// Do not overload GetSQLExpression here because this is handled in the joins
|
||||
@@ -1231,10 +1235,10 @@ class AttributeExternalField extends AttributeDefinition
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
return $oExtAttDef->GetAsXML($value);
|
||||
}
|
||||
public function GetAsCSV($value, $sSeparator = ';', $sSepEscape = ',')
|
||||
public function GetAsCSV($value, $sSeparator = ',', $sTestQualifier = '"')
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
return $oExtAttDef->GetAsCSV($value);
|
||||
return $oExtAttDef->GetAsCSV($value, $sSeparator, $sTestQualifier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1394,7 +1398,7 @@ class AttributeBlob extends AttributeDefinition
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAsCSV($sValue, $sSeparator = ';', $sSepEscape = ',')
|
||||
public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"')
|
||||
{
|
||||
return ''; // Not exportable in CSV !
|
||||
}
|
||||
|
||||
@@ -244,15 +244,16 @@ class BulkChange
|
||||
|
||||
static protected function MakeSpecObject($sClass, $iId)
|
||||
{
|
||||
$oObj = MetaModel::GetObject($sClass, $iId);
|
||||
if (is_null($oObj))
|
||||
try
|
||||
{
|
||||
$oObj = MetaModel::GetObject($sClass, $iId);
|
||||
}
|
||||
catch(CoreException $e)
|
||||
{
|
||||
// in case an ext key is 0 (which is currently acceptable)
|
||||
return $iId;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $oObj;
|
||||
}
|
||||
return $oObj;
|
||||
}
|
||||
|
||||
protected function PrepareObject(&$oTargetObj, $aRowData, &$aErrors)
|
||||
@@ -276,18 +277,33 @@ class BulkChange
|
||||
switch($oExtObjects->Count())
|
||||
{
|
||||
case 0:
|
||||
$aErrors[$sAttCode] = "Object not found";
|
||||
$aResults[$sAttCode]= new CellChangeSpec_Issue(null, $oTargetObj->Get($sAttCode), 'Object not found - check the spelling (no space before/after)');
|
||||
if ($oExtKey->IsNullAllowed())
|
||||
{
|
||||
$oTargetObj->Set($sAttCode, $oExtKey->GetNullValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
$aErrors[$sAttCode] = "Object not found";
|
||||
$aResults[$sAttCode]= new CellChangeSpec_Issue(null, $oTargetObj->Get($sAttCode), 'Object not found - check the spelling (no space before/after)');
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// Do change the external key attribute
|
||||
$oForeignObj = $oExtObjects->Fetch();
|
||||
$oTargetObj->Set($sAttCode, $oForeignObj->GetKey());
|
||||
|
||||
// Report it
|
||||
break;
|
||||
default:
|
||||
$aErrors[$sAttCode] = "Found ".$oExtObjects->Count()." matches";
|
||||
$previousValue = self::MakeSpecObject($oExtKey->GetTargetClass(), $oTargetObj->Get($sAttCode));
|
||||
$aResults[$sAttCode]= new CellChangeSpec_Issue(null, $previousValue, "Found ".$oExtObjects->Count()." matches");
|
||||
}
|
||||
|
||||
// Report
|
||||
if (!array_key_exists($sAttCode, $aResults))
|
||||
{
|
||||
$oForeignObj = $oTargetObj->Get($sAttCode);
|
||||
if (array_key_exists($sAttCode, $oTargetObj->ListChanges()))
|
||||
{
|
||||
|
||||
if ($oTargetObj->IsNew())
|
||||
{
|
||||
$aResults[$sAttCode]= new CellChangeSpec_Init($oForeignObj);
|
||||
@@ -302,11 +318,6 @@ class BulkChange
|
||||
{
|
||||
$aResults[$sAttCode]= new CellChangeSpec_Unchanged($oForeignObj);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$aErrors[$sAttCode] = "Found ".$oExtObjects->Count()." matches";
|
||||
$previousValue = self::MakeSpecObject($oExtKey->GetTargetClass(), $oTargetObj->Get($sAttCode));
|
||||
$aResults[$sAttCode]= new CellChangeSpec_Issue(null, $previousValue, "Found ".$oExtObjects->Count()." matches");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ class CMDBSource
|
||||
$value = stripslashes($value);
|
||||
}
|
||||
// Quote if not a number or a numeric string
|
||||
if ($bAlways || !is_numeric($value))
|
||||
if ($bAlways || is_string($value))
|
||||
{
|
||||
$value = $cQuoteStyle . mysql_real_escape_string($value, self::$m_resDBLink) . $cQuoteStyle;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CSVParser
|
||||
* CSV interpreter helper, optionaly tries to guess column mapping and the separator, check the consistency
|
||||
* CSV interpreter helper
|
||||
*
|
||||
* @package iTopORM
|
||||
* @author Romain Quetiez <romainquetiez@yahoo.fr>
|
||||
@@ -19,6 +18,16 @@ class CSVParserException extends CoreException
|
||||
|
||||
|
||||
|
||||
define('stSTARTING', 1); //grey zone: the type is undetermined
|
||||
define('stRAW', 2); //building a non-qualified string
|
||||
define('stQUALIFIED', 3); //building qualified string
|
||||
define('stESCAPED', 4); //just encountered an escape char
|
||||
|
||||
define('evSEPARATOR', 1);
|
||||
define('evNEWLINE', 2);
|
||||
define('evTEXTQUAL', 3); // used for escaping as well
|
||||
define('evOTHERCHAR', 4);
|
||||
|
||||
|
||||
/**
|
||||
* CSVParser
|
||||
@@ -34,157 +43,154 @@ class CSVParser
|
||||
{
|
||||
private $m_sCSVData;
|
||||
private $m_sSep;
|
||||
private $m_iSkip;
|
||||
private $m_sTextQualifier;
|
||||
|
||||
public function __construct($sTxt)
|
||||
{
|
||||
$this->m_sCSVData = $sTxt;
|
||||
}
|
||||
|
||||
public function SetSeparator($sSep)
|
||||
public function __construct($sTxt, $sSep = ',', $sTextQualifier = '"')
|
||||
{
|
||||
$this->m_sCSVData = str_replace("\r\n", "\n", $sTxt);
|
||||
$this->m_sSep = $sSep;
|
||||
}
|
||||
public function GetSeparator()
|
||||
{
|
||||
return $this->m_sSep;
|
||||
$this->m_sTextQualifier = $sTextQualifier;
|
||||
}
|
||||
|
||||
public function SetSkipLines($iSkip)
|
||||
{
|
||||
$this->m_iSkip = $iSkip;
|
||||
}
|
||||
public function GetSkipLines()
|
||||
{
|
||||
return $this->m_iSkip;
|
||||
}
|
||||
protected $m_sCurrCell = '';
|
||||
protected $m_aCurrRow = array();
|
||||
protected $m_iToSkip = 0;
|
||||
protected $m_aDataSet = array();
|
||||
|
||||
public function GuessSeparator()
|
||||
protected function __AddChar($c)
|
||||
{
|
||||
// Note: skip the first line anyway
|
||||
|
||||
$aKnownSeps = array(';', ',', "\t"); // Use double quote for special chars!!!
|
||||
$aStatsBySeparator = array();
|
||||
foreach ($aKnownSeps as $sSep)
|
||||
$this->m_sCurrCell .= $c;
|
||||
}
|
||||
protected function __ClearCell()
|
||||
{
|
||||
$this->m_sCurrCell = '';
|
||||
}
|
||||
protected function __AddCell($c = null, $aFieldMap = null)
|
||||
{
|
||||
if (!is_null($aFieldMap))
|
||||
{
|
||||
$aStatsBySeparator[$sSep] = array();
|
||||
$iNextCol = count($this->m_aCurrRow);
|
||||
$iNextName = $aFieldMap[$iNextCol];
|
||||
$this->m_aCurrRow[$iNextName] = $this->m_sCurrCell;
|
||||
}
|
||||
|
||||
foreach(explode("\n", $this->m_sCSVData) as $sLine)
|
||||
else
|
||||
{
|
||||
$sLine = trim($sLine);
|
||||
if (substr($sLine, 0, 1) == '#') continue;
|
||||
if (empty($sLine)) continue;
|
||||
|
||||
$aLineCharsCount = count_chars($sLine, 0);
|
||||
foreach ($aKnownSeps as $sSep)
|
||||
$this->m_aCurrRow[] = $this->m_sCurrCell;
|
||||
}
|
||||
$this->m_sCurrCell = '';
|
||||
}
|
||||
protected function __AddRow($c = null, $aFieldMap = null)
|
||||
{
|
||||
$this->__AddCell($c, $aFieldMap);
|
||||
|
||||
if ($this->m_iToSkip > 0)
|
||||
{
|
||||
$this->m_iToSkip--;
|
||||
}
|
||||
elseif (count($this->m_aCurrRow) > 1)
|
||||
{
|
||||
$this->m_aDataSet[] = $this->m_aCurrRow;
|
||||
}
|
||||
elseif (count($this->m_aCurrRow) == 1)
|
||||
{
|
||||
// Get the unique value
|
||||
$aValues = array_values($this->m_aCurrRow);
|
||||
$sValue = $aValues[0];
|
||||
if (strlen($sValue) > 0)
|
||||
{
|
||||
$aStatsBySeparator[$sSep][] = $aLineCharsCount[ord($sSep)];
|
||||
$this->m_aDataSet[] = $this->m_aCurrRow;
|
||||
}
|
||||
}
|
||||
|
||||
// Default to ','
|
||||
$this->SetSeparator(",");
|
||||
|
||||
foreach ($aKnownSeps as $sSep)
|
||||
else
|
||||
{
|
||||
// Note: this function is NOT available :-(
|
||||
// stats_variance($aStatsBySeparator[$sSep]);
|
||||
$iMin = min($aStatsBySeparator[$sSep]);
|
||||
$iMax = max($aStatsBySeparator[$sSep]);
|
||||
if (($iMin == $iMax) && ($iMax > 0))
|
||||
{
|
||||
$this->SetSeparator($sSep);
|
||||
break;
|
||||
}
|
||||
// blank line, skip silently
|
||||
}
|
||||
return $this->GetSeparator();
|
||||
$this->m_aCurrRow = array();
|
||||
}
|
||||
|
||||
public function GuessSkipLines()
|
||||
function ToArray($iToSkip = 1, $aFieldMap = null, $iMax = 0)
|
||||
{
|
||||
// Take the FIRST -valuable- LINE ONLY
|
||||
// If there is a number, then for sure this is not a header line
|
||||
// Otherwise, we may consider that there is one line to skip
|
||||
foreach(explode("\n", $this->m_sCSVData) as $sLine)
|
||||
$aTransitions = array();
|
||||
|
||||
$aTransitions[stSTARTING][evSEPARATOR] = array('__AddCell', stSTARTING);
|
||||
$aTransitions[stSTARTING][evNEWLINE] = array('__AddRow', stSTARTING);
|
||||
$aTransitions[stSTARTING][evTEXTQUAL] = array('', stQUALIFIED);
|
||||
$aTransitions[stSTARTING][evOTHERCHAR] = array('__AddChar', stRAW);
|
||||
|
||||
$aTransitions[stRAW][evSEPARATOR] = array('__AddCell', stSTARTING);
|
||||
$aTransitions[stRAW][evNEWLINE] = array('__AddRow', stSTARTING);
|
||||
$aTransitions[stRAW][evTEXTQUAL] = array('__AddChar', stRAW);
|
||||
$aTransitions[stRAW][evOTHERCHAR] = array('__AddChar', stRAW);
|
||||
|
||||
$aTransitions[stQUALIFIED][evSEPARATOR] = array('__AddChar', stQUALIFIED);
|
||||
$aTransitions[stQUALIFIED][evNEWLINE] = array('__AddChar', stQUALIFIED);
|
||||
$aTransitions[stQUALIFIED][evTEXTQUAL] = array('', stESCAPED);
|
||||
$aTransitions[stQUALIFIED][evOTHERCHAR] = array('__AddChar', stQUALIFIED);
|
||||
|
||||
$aTransitions[stESCAPED][evSEPARATOR] = array('__AddCell', stSTARTING);
|
||||
$aTransitions[stESCAPED][evNEWLINE] = array('__AddRow', stSTARTING);
|
||||
$aTransitions[stESCAPED][evTEXTQUAL] = array('__AddChar', stQUALIFIED);
|
||||
$aTransitions[stESCAPED][evOTHERCHAR] = array('__AddChar', stSTARTING);
|
||||
|
||||
// Reset parser variables
|
||||
$this->m_sCurrCell = '';
|
||||
$this->m_aCurrRow = array();
|
||||
$this->m_iToSkip = $iToSkip;
|
||||
$this->m_aDataSet = array();
|
||||
|
||||
$iState = stSTARTING;
|
||||
for($i = 0; $i < strlen($this->m_sCSVData) ; $i++)
|
||||
{
|
||||
$sLine = trim($sLine);
|
||||
if (substr($sLine, 0, 1) == '#') continue;
|
||||
if (empty($sLine)) continue;
|
||||
|
||||
foreach (explode($this->m_sSep, $sLine) as $value)
|
||||
$c = $this->m_sCSVData[$i];
|
||||
|
||||
// // Note: I did that because the unit test was not working fine (file edited with notepad: \n chars padded :-(
|
||||
// if (ord($c) == 0) continue;
|
||||
|
||||
if ($c == $this->m_sSep)
|
||||
{
|
||||
if (is_numeric($value))
|
||||
$iEvent = evSEPARATOR;
|
||||
}
|
||||
elseif ($c == "\n")
|
||||
{
|
||||
$iEvent = evNEWLINE;
|
||||
}
|
||||
elseif ($c == $this->m_sTextQualifier)
|
||||
{
|
||||
$iEvent = evTEXTQUAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iEvent = evOTHERCHAR;
|
||||
}
|
||||
|
||||
$sAction = $aTransitions[$iState][$iEvent][0];
|
||||
$iState = $aTransitions[$iState][$iEvent][1];
|
||||
|
||||
if (!empty($sAction))
|
||||
{
|
||||
$aCallSpec = array($this, $sAction);
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$this->SetSkipLines(0);
|
||||
return 0;
|
||||
call_user_func($aCallSpec, $c, $aFieldMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new CSVParserException("CSVParser: unknown verb '$sAction'");
|
||||
}
|
||||
}
|
||||
$this->SetSkipLines(1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
function ToArray($aFieldMap = null, $iMax = 0)
|
||||
{
|
||||
// $aFieldMap is an array of col_index=>col_name
|
||||
// $iMax is to limit the count of rows computed
|
||||
$aRes = array();
|
||||
|
||||
$iCount = 0;
|
||||
$iSkipped = 0;
|
||||
foreach(explode("\n", $this->m_sCSVData) as $sLine)
|
||||
{
|
||||
$sLine = trim($sLine);
|
||||
if (substr($sLine, 0, 1) == '#') continue;
|
||||
if (empty($sLine)) continue;
|
||||
|
||||
if ($iSkipped < $this->m_iSkip)
|
||||
{
|
||||
$iSkipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (explode($this->m_sSep, $sLine) as $iCol=>$sValue)
|
||||
{
|
||||
if (is_array($aFieldMap)) $sColRef = $aFieldMap[$iCol];
|
||||
else $sColRef = $iCol;
|
||||
$aRes[$iCount][$sColRef] = $sValue;
|
||||
}
|
||||
|
||||
$iCount++;
|
||||
if (($iMax > 0) && ($iCount >= $iMax)) break;
|
||||
$iLineCount = count($this->m_aDataSet);
|
||||
if (($iMax > 0) && ($iLineCount >= $iMax)) break;
|
||||
}
|
||||
return $aRes;
|
||||
// Close the final line
|
||||
$this->__AddRow(null, $aFieldMap);
|
||||
return $this->m_aDataSet;
|
||||
}
|
||||
|
||||
public function ListFields()
|
||||
{
|
||||
// Take the first valuable line
|
||||
foreach(explode("\n", $this->m_sCSVData) as $sLine)
|
||||
{
|
||||
$sLine = trim($sLine);
|
||||
if (substr($sLine, 0, 1) == '#') continue;
|
||||
if (empty($sLine)) continue;
|
||||
// We've got the first valuable line, that's it!
|
||||
break;
|
||||
}
|
||||
|
||||
$aRet = array();
|
||||
foreach (explode($this->m_sSep, $sLine) as $iCol=>$value)
|
||||
{
|
||||
if ($this->m_iSkip == 0)
|
||||
{
|
||||
// No header to help us
|
||||
$sLabel = "field $iCol";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLabel = "$value";
|
||||
}
|
||||
$aRet[] = $sLabel;
|
||||
}
|
||||
return $aRet;
|
||||
$aHeader = $this->ToArray(0, null, 1);
|
||||
return $aHeader[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -381,10 +381,10 @@ abstract class DBObject
|
||||
return $oAtt->GetAsXML($this->Get($sAttCode));
|
||||
}
|
||||
|
||||
public function GetAsCSV($sAttCode, $sSeparator = ';', $sSepEscape = ',')
|
||||
public function GetAsCSV($sAttCode, $sSeparator = ',', $sTextQualifier = '"')
|
||||
{
|
||||
$oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
return $oAtt->GetAsCSV($this->Get($sAttCode), $sSeparator, $sSepEscape);
|
||||
return $oAtt->GetAsCSV($this->Get($sAttCode), $sSeparator, $sTextQualifier);
|
||||
}
|
||||
|
||||
protected static function MakeHyperLink($sObjClass, $sObjKey, $aAvailableFields)
|
||||
@@ -568,10 +568,32 @@ abstract class DBObject
|
||||
$aDelta = array();
|
||||
foreach ($aProposal as $sAtt => $proposedValue)
|
||||
{
|
||||
if (!array_key_exists($sAtt, $this->m_aOrigValues) || ($this->m_aOrigValues[$sAtt] != $proposedValue))
|
||||
if (!array_key_exists($sAtt, $this->m_aOrigValues))
|
||||
{
|
||||
// The value was not set
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
elseif(is_object($proposedValue))
|
||||
{
|
||||
// The value is an object, the comparison is not strict
|
||||
// #@# todo - should be even less strict => add verb on AttributeDefinition: Compare($a, $b)
|
||||
if ($this->m_aOrigValues[$sAtt] != $proposedValue)
|
||||
{
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The value is a scalar, the comparison must be 100% strict
|
||||
if($this->m_aOrigValues[$sAtt] !== $proposedValue)
|
||||
{
|
||||
//echo "$sAtt:<pre>\n";
|
||||
//var_dump($this->m_aOrigValues[$sAtt]);
|
||||
//var_dump($proposedValue);
|
||||
//echo "</pre>\n";
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aDelta;
|
||||
}
|
||||
@@ -665,6 +687,11 @@ abstract class DBObject
|
||||
}
|
||||
return $this->m_iKey;
|
||||
}
|
||||
|
||||
// To be optionaly overloaded
|
||||
public function OnInsert()
|
||||
{
|
||||
}
|
||||
|
||||
// Insert of record for the new object into the database
|
||||
// Returns the key of the newly created object
|
||||
@@ -680,6 +707,7 @@ abstract class DBObject
|
||||
|
||||
// Ensure the update of the values (we are accessing the data directly)
|
||||
$this->ComputeFields();
|
||||
$this->OnInsert();
|
||||
|
||||
if ($this->m_iKey < 0)
|
||||
{
|
||||
@@ -878,11 +906,12 @@ abstract class DBObject
|
||||
}
|
||||
|
||||
// Make standard context arguments
|
||||
public function ToArgs($sArgName)
|
||||
public function ToArgs($sArgName = 'this')
|
||||
{
|
||||
$aScalarArgs = array();
|
||||
$aScalarArgs[$sArgName] = $this->GetKey();
|
||||
$aScalarArgs[$sArgName.'->id'] = $this->GetKey();
|
||||
$aScalarArgs[$sArgName.'->object()'] = $this;
|
||||
$aScalarArgs[$sArgName.'->hyperlink()'] = $this->GetHyperlink();
|
||||
$aScalarArgs[$sArgName.'->name()'] = $this->GetName();
|
||||
|
||||
@@ -912,8 +941,8 @@ abstract class DBObject
|
||||
|
||||
$iDepth = $bPropagate ? $iMaxDepth - 1 : 0;
|
||||
|
||||
$oFlt = DBObjectSearch::FromSibusQL($sQuery, array(), $this);
|
||||
$oObjSet = new DBObjectSet($oFlt);
|
||||
$oFlt = DBObjectSearch::FromOQL($sQuery);
|
||||
$oObjSet = new DBObjectSet($oFlt, array(), $this->ToArgs());
|
||||
while ($oObj = $oObjSet->Fetch())
|
||||
{
|
||||
$sRootClass = MetaModel::GetRootClass(get_class($oObj));
|
||||
|
||||
@@ -933,7 +933,7 @@ class DBObjectSearch
|
||||
|
||||
if (preg_match('@^\\s*SELECT@', $sQuery))
|
||||
{
|
||||
return self::FromOQL($sQuery, $aParams, $oObject);
|
||||
return self::FromOQL($sQuery);
|
||||
}
|
||||
|
||||
$iSepPos = strpos($sQuery, ":");
|
||||
|
||||
@@ -81,6 +81,22 @@ class DBObjectSet
|
||||
return $oRetSet;
|
||||
}
|
||||
|
||||
static public function FromLinkSet($oObject, $sLinkSetAttCode, $sExtKeyToRemote)
|
||||
{
|
||||
$oLinkAttCode = MetaModel::GetAttributeDef(get_class($oObject), $sLinkSetAttCode);
|
||||
$oExtKeyAttDef = MetaModel::GetAttributeDef($oLinkAttCode->GetLinkedClass(), $sExtKeyToRemote);
|
||||
$sTargetClass = $oExtKeyAttDef->GetTargetClass();
|
||||
|
||||
$oLinkSet = $oObject->Get($sLinkSetAttCode);
|
||||
$aTargets = array();
|
||||
while ($oLink = $oLinkSet->Fetch())
|
||||
{
|
||||
$aTargets[] = MetaModel::GetObject($sTargetClass, $oLink->Get($sExtKeyToRemote));
|
||||
}
|
||||
|
||||
return self::FromArray($sTargetClass, $aTargets);
|
||||
}
|
||||
|
||||
public function ToArray($bWithId = true)
|
||||
{
|
||||
$aRet = array();
|
||||
@@ -198,6 +214,7 @@ class DBObjectSet
|
||||
|
||||
public function AddObjectArray($aObjects)
|
||||
{
|
||||
// #@# todo - add a check on the object class ?
|
||||
foreach ($aObjects as $oObj)
|
||||
{
|
||||
$this->AddObject($oObj);
|
||||
@@ -263,11 +280,14 @@ class DBObjectSet
|
||||
|
||||
public function GetRelatedObjects($sRelCode, $iMaxDepth = 99)
|
||||
{
|
||||
$aRelatedObjs = array();
|
||||
|
||||
$aVisited = array(); // optimization for consecutive calls of MetaModel::GetRelatedObjects
|
||||
$this->Seek(0);
|
||||
while ($oObject = $this->Fetch())
|
||||
{
|
||||
$aRelatedObjs = $oObject->GetRelatedObjects($sRelCode, $iMaxDepth, $aVisited);
|
||||
// #@# todo - actually merge !
|
||||
$aRelatedObjs = array_merge_recursive($aRelatedObjs, $oObject->GetRelatedObjects($sRelCode, $iMaxDepth, $aVisited));
|
||||
}
|
||||
return $aRelatedObjs;
|
||||
}
|
||||
|
||||
@@ -458,6 +458,19 @@ abstract class MetaModel
|
||||
return $aExtKeys;
|
||||
}
|
||||
|
||||
final static public function GetLinkedSets($sClass)
|
||||
{
|
||||
$aLinkedSets = array();
|
||||
foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAtt)
|
||||
{
|
||||
if (is_subclass_of($oAtt, 'AttributeLinkedSet'))
|
||||
{
|
||||
$aLinkedSets[$sAttCode] = $oAtt;
|
||||
}
|
||||
}
|
||||
return $aLinkedSets;
|
||||
}
|
||||
|
||||
final static public function GetExternalFields($sClass, $sKeyAttCode)
|
||||
{
|
||||
$aExtFields = array();
|
||||
@@ -2039,13 +2052,16 @@ abstract class MetaModel
|
||||
list($aErrors, $aSugFix) = self::DBCheckFormat();
|
||||
|
||||
$aSQL = array();
|
||||
foreach ($aSugFix as $sClass => $aQueries)
|
||||
foreach ($aSugFix as $sClass => $aTarget)
|
||||
{
|
||||
foreach ($aQueries as $sQuery)
|
||||
foreach ($aTarget as $aQueries)
|
||||
{
|
||||
//$aSQL[] = $sQuery;
|
||||
// forces a refresh of cached information
|
||||
CMDBSource::CreateTable($sQuery);
|
||||
foreach ($aQueries as $sQuery)
|
||||
{
|
||||
//$aSQL[] = $sQuery;
|
||||
// forces a refresh of cached information
|
||||
CMDBSource::CreateTable($sQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
// does not work -how to have multiple statements in a single query?
|
||||
@@ -2078,15 +2094,15 @@ abstract class MetaModel
|
||||
$sAutoIncrement = (self::IsAutoIncrementKey($sClass) ? "AUTO_INCREMENT" : "");
|
||||
if (!CMDBSource::IsTable($sTable))
|
||||
{
|
||||
$aErrors[$sClass][] = "table '$sTable' could not be found into the DB";
|
||||
$aSugFix[$sClass][] = "CREATE TABLE `$sTable` (`$sKeyField` INT(11) NOT NULL $sAutoIncrement PRIMARY KEY) ENGINE = innodb CHARACTER SET utf8 COLLATE utf8_unicode_ci";
|
||||
$aErrors[$sClass]['*'][] = "table '$sTable' could not be found into the DB";
|
||||
$aSugFix[$sClass]['*'][] = "CREATE TABLE `$sTable` (`$sKeyField` INT(11) NOT NULL $sAutoIncrement PRIMARY KEY) ENGINE = innodb CHARACTER SET utf8 COLLATE utf8_unicode_ci";
|
||||
}
|
||||
// Check that the key field exists
|
||||
//
|
||||
elseif (!CMDBSource::IsField($sTable, $sKeyField))
|
||||
{
|
||||
$aErrors[$sClass][] = "key '$sKeyField' (table $sTable) could not be found";
|
||||
$aSugFix[$sClass][] = "ALTER TABLE `$sTable` ADD `$sKeyField` INT(11) NOT NULL $sAutoIncrement PRIMARY KEY";
|
||||
$aErrors[$sClass]['id'][] = "key '$sKeyField' (table $sTable) could not be found";
|
||||
$aSugFix[$sClass]['id'][] = "ALTER TABLE `$sTable` ADD `$sKeyField` INT(11) NOT NULL $sAutoIncrement PRIMARY KEY";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2094,13 +2110,13 @@ abstract class MetaModel
|
||||
//
|
||||
if (!CMDBSource::IsKey($sTable, $sKeyField))
|
||||
{
|
||||
$aErrors[$sClass][] = "key '$sKeyField' is not a key for table '$sTable'";
|
||||
$aSugFix[$sClass][] = "ALTER TABLE `$sTable`, DROP PRIMARY KEY, ADD PRIMARY key(`$sKeyField`)";
|
||||
$aErrors[$sClass]['id'][] = "key '$sKeyField' is not a key for table '$sTable'";
|
||||
$aSugFix[$sClass]['id'][] = "ALTER TABLE `$sTable`, DROP PRIMARY KEY, ADD PRIMARY key(`$sKeyField`)";
|
||||
}
|
||||
if (self::IsAutoIncrementKey($sClass) && !CMDBSource::IsAutoIncrement($sTable, $sKeyField))
|
||||
{
|
||||
$aErrors[$sClass][] = "key '$sKeyField' (table $sTable) is not automatically incremented";
|
||||
$aSugFix[$sClass][] = "ALTER TABLE `$sTable` CHANGE `$sKeyField` `$sKeyField` INT(11) NOT NULL AUTO_INCREMENT";
|
||||
$aErrors[$sClass]['id'][] = "key '$sKeyField' (table $sTable) is not automatically incremented";
|
||||
$aSugFix[$sClass]['id'][] = "ALTER TABLE `$sTable` CHANGE `$sKeyField` `$sKeyField` INT(11) NOT NULL AUTO_INCREMENT";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2118,11 +2134,11 @@ abstract class MetaModel
|
||||
$sFieldSpecs = $oAttDef->IsNullAllowed() ? "$sDBFieldType NULL" : "$sDBFieldType NOT NULL";
|
||||
if (!CMDBSource::IsField($sTable, $sField))
|
||||
{
|
||||
$aErrors[$sClass][] = "field '$sField' could not be found in table '$sTable'";
|
||||
$aSugFix[$sClass][] = "ALTER TABLE `$sTable` ADD `$sField` $sFieldSpecs";
|
||||
$aErrors[$sClass][$sAttCode][] = "field '$sField' could not be found in table '$sTable'";
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD `$sField` $sFieldSpecs";
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$aSugFix[$sClass][] = "ALTER TABLE `$sTable` ADD INDEX (`$sField`)";
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD INDEX (`$sField`)";
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2135,30 +2151,30 @@ abstract class MetaModel
|
||||
$bToBeChanged = true;
|
||||
if ($oAttDef->IsNullAllowed())
|
||||
{
|
||||
$aErrors[$sClass][] = "field '$sField' in table '$sTable' could be NULL";
|
||||
$aErrors[$sClass][$sAttCode][] = "field '$sField' in table '$sTable' could be NULL";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aErrors[$sClass][] = "field '$sField' in table '$sTable' could NOT be NULL";
|
||||
$aErrors[$sClass][$sAttCode][] = "field '$sField' in table '$sTable' could NOT be NULL";
|
||||
}
|
||||
}
|
||||
$sActualFieldType = CMDBSource::GetFieldType($sTable, $sField);
|
||||
if (strcasecmp($sDBFieldType, $sActualFieldType) != 0)
|
||||
{
|
||||
$bToBeChanged = true;
|
||||
$aErrors[$sClass][] = "field '$sField' in table '$sTable' has a wrong type: found '$sActualFieldType' while expecting '$sDBFieldType'";
|
||||
$aErrors[$sClass][$sAttCode][] = "field '$sField' in table '$sTable' has a wrong type: found '$sActualFieldType' while expecting '$sDBFieldType'";
|
||||
}
|
||||
if ($bToBeChanged)
|
||||
{
|
||||
$aSugFix[$sClass][] = "ALTER TABLE `$sTable` CHANGE `$sField` `$sField` $sFieldSpecs";
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` CHANGE `$sField` `$sField` $sFieldSpecs";
|
||||
}
|
||||
|
||||
// Create indexes (external keys only... so far)
|
||||
//
|
||||
if ($oAttDef->IsExternalKey() && !CMDBSource::HasIndex($sTable, $sField))
|
||||
{
|
||||
$aErrors[$sClass][] = "Foreign key '$sField' in table '$sTable' should have an index";
|
||||
$aSugFix[$sClass][] = "ALTER TABLE `$sTable` ADD INDEX (`$sField`)";
|
||||
$aErrors[$sClass][$sAttCode][] = "Foreign key '$sField' in table '$sTable' should have an index";
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD INDEX (`$sField`)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ abstract class ValueSetDefinition
|
||||
}
|
||||
|
||||
|
||||
public function GetValues($aArgs, $sBeginsWith)
|
||||
public function GetValues($aArgs, $sBeginsWith = '')
|
||||
{
|
||||
if (!$this->m_bIsLoaded)
|
||||
{
|
||||
@@ -116,6 +116,85 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set of existing values for a link set attribute, given a relation code
|
||||
*
|
||||
* @package iTopORM
|
||||
* @author Romain Quetiez <romainquetiez@yahoo.fr>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.itop.com
|
||||
* @since 1.0
|
||||
* @version $itopversion$
|
||||
*/
|
||||
class ValueSetRelatedObjectsFromLinkSet extends ValueSetDefinition
|
||||
{
|
||||
protected $m_sLinkSetAttCode;
|
||||
protected $m_sExtKeyToRemote;
|
||||
protected $m_sRelationCode;
|
||||
protected $m_iMaxDepth;
|
||||
protected $m_sTargetClass;
|
||||
protected $m_sTargetExtKey;
|
||||
// protected $m_aOrderBy;
|
||||
|
||||
public function __construct($sLinkSetAttCode, $sExtKeyToRemote, $sRelationCode, $iMaxDepth, $sTargetClass, $sTargetLinkClass, $sTargetExtKey)
|
||||
{
|
||||
$this->m_sLinkSetAttCode = $sLinkSetAttCode;
|
||||
$this->m_sExtKeyToRemote = $sExtKeyToRemote;
|
||||
$this->m_sRelationCode = $sRelationCode;
|
||||
$this->m_iMaxDepth = $iMaxDepth;
|
||||
$this->m_sTargetClass = $sTargetClass;
|
||||
$this->m_sTargetLinkClass = $sTargetLinkClass;
|
||||
$this->m_sTargetExtKey = $sTargetExtKey;
|
||||
// $this->m_aOrderBy = $aOrderBy;
|
||||
}
|
||||
|
||||
protected function LoadValues($aArgs)
|
||||
{
|
||||
$this->m_aValues = array();
|
||||
|
||||
if (!array_key_exists('this', $aArgs))
|
||||
{
|
||||
throw new CoreException("Missing 'this' in arguments", array('args' => $aArgs));
|
||||
}
|
||||
|
||||
$oTarget = $aArgs['this->object()'];
|
||||
|
||||
// Nodes from which we will start the search for neighbourhood
|
||||
$oNodes = DBObjectSet::FromLinkSet($oTarget, $this->m_sLinkSetAttCode, $this->m_sExtKeyToRemote);
|
||||
|
||||
// Neighbours, whatever their class
|
||||
$aRelated = $oNodes->GetRelatedObjects($this->m_sRelationCode, $this->m_iMaxDepth);
|
||||
|
||||
$sRootClass = MetaModel::GetRootClass($this->m_sTargetClass);
|
||||
if (array_key_exists($sRootClass, $aRelated))
|
||||
{
|
||||
$aLinksToCreate = array();
|
||||
foreach($aRelated[$sRootClass] as $iKey => $oObject)
|
||||
{
|
||||
if (MetaModel::IsParentClass($this->m_sTargetClass, get_class($oObject)))
|
||||
{
|
||||
$oNewLink = MetaModel::NewObject($this->m_sTargetLinkClass);
|
||||
$oNewLink->Set($this->m_sTargetExtKey, $iKey);
|
||||
//$oNewLink->Set('role', 'concerned by an impacted CI');
|
||||
|
||||
$aLinksToCreate[] = $oNewLink;
|
||||
}
|
||||
}
|
||||
// #@# or AddObjectArray($aObjects) ?
|
||||
$oSetToCreate = DBObjectSet::FromArray($this->m_sTargetLinkClass, $aLinksToCreate);
|
||||
$this->m_aValues[$oObject->GetKey()] = $oObject->GetAsHTML($oObject->GetName());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetValuesDescription()
|
||||
{
|
||||
return 'Filter: '.$this->m_sFilterExpr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fixed set values (could be hardcoded in the business model)
|
||||
*
|
||||
|
||||
@@ -254,7 +254,7 @@ function DumpDatabase()
|
||||
function printMenu($sConfigFile)
|
||||
{
|
||||
$sClassCount = count(MetaModel::GetClasses());
|
||||
$bHasDB = MetaModel::DBExists();
|
||||
$bHasDB = MetaModel::DBExists(false); // no need to be complete to consider that something already exists
|
||||
$sUrl = "?config=".urlencode($sConfigFile);
|
||||
|
||||
echo "<div style=\"background-color:eeeeee; padding:10px;\">\n";
|
||||
@@ -345,22 +345,25 @@ function DisplayDBFormatIssues($aErrors, $aSugFix, $sRepairUrl = "", $sSQLStatem
|
||||
echo "<div style=\"width:100%;padding:10px;background:#FFAAAA;display:;\">";
|
||||
echo "<h1>Wrong Database format</h1>\n";
|
||||
echo "<p>The current database is not consistent with the given business model. Please investigate.</p>\n";
|
||||
foreach ($aErrors as $sClass => $aMessages)
|
||||
foreach ($aErrors as $sClass => $aTarget)
|
||||
{
|
||||
echo "<p>Wrong declaration (or DB format ?) for class <b>$sClass</b></p>\n";
|
||||
echo "<ul class=\"treeview\">\n";
|
||||
$i = 0;
|
||||
foreach ($aMessages as $sMsg)
|
||||
foreach ($aTarget as $sTarget => $aMessages)
|
||||
{
|
||||
echo "<p>Wrong declaration for attribute <b>$sTarget</b></p>\n";
|
||||
$sMsg = implode(' AND ', $aMessages);
|
||||
if (!empty($sRepairUrl))
|
||||
{
|
||||
$aSQLFixes[] = $aSugFix[$sClass][$i];
|
||||
$sUrl = "$sRepairUrl&$sSQLStatementArgName=".urlencode($aSugFix[$sClass][$i]);
|
||||
echo "<li>$sMsg (<a href=\"$sUrl\" title=\"".$aSugFix[$sClass][$i]."\" target=\"_blank\">fix it now!</a>)</li>\n";
|
||||
$aSQLFixes = array_merge($aSQLFixes, $aSugFix[$sClass][$sTarget]);
|
||||
$sSQLFixes = implode('; ', $aSugFix[$sClass][$sTarget]);
|
||||
$sUrl = "$sRepairUrl&$sSQLStatementArgName=".urlencode($sSQLFixes);
|
||||
echo "<li>$sMsg (<a href=\"$sUrl\" title=\"".htmlentities($sSQLFixes)."\" target=\"_blank\">fix it now!</a>)</li>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<li>$sMsg ({$aSugFix[$sClass][$i]})</li>\n";
|
||||
echo "<li>$sMsg (".htmlentities($sSQLFixes).")</li>\n";
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
2012
pages/UI.php
2012
pages/UI.php
File diff suppressed because it is too large
Load Diff
@@ -226,8 +226,8 @@ function Page3_ViewResults($oPage, $oFilter)
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
$oPage->p("Found ".$oSet->Count()." items");
|
||||
|
||||
$sFilterPhrase = $oFilter->serialize();
|
||||
$oPage->p("<a href=\"/pages/index.php?operation=direct&filter=$sFilterPhrase\">See detailed results</a>");
|
||||
$sFilterPhrase = urlencode($oFilter->serialize());
|
||||
$oPage->p("<a href=\"/pages/index.php?operation=search&filter=$sFilterPhrase\">See detailed results</a>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ function MakeExtFieldSelectValue($sAttCode, $sExtAttCode)
|
||||
|
||||
function ShowTableForm($oPage, $oCSVParser, $sClass)
|
||||
{
|
||||
$aData = $oCSVParser->ToArray(null, 3);
|
||||
$aData = $oCSVParser->ToArray(1, null, 3);
|
||||
$aColToRow = array();
|
||||
foreach($aData as $aRow)
|
||||
{
|
||||
@@ -193,6 +193,10 @@ function ShowTableForm($oPage, $oCSVParser, $sClass)
|
||||
{
|
||||
$aFields["field$iFieldIndex"]["value"] = $aColToRow[$iFieldIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Houston...
|
||||
}
|
||||
}
|
||||
$oPage->details($aFields);
|
||||
}
|
||||
@@ -354,12 +358,24 @@ function Do_Welcome($oPage, $sClass)
|
||||
$sWiztep = "1_welcome";
|
||||
$oPage->p("<h1>Bulk load from CSV data / step 1</h1>");
|
||||
|
||||
// Reload values (in case we are reaching this page from the next one
|
||||
$sCSVData = utils::ReadPostedParam('csvdata');
|
||||
$sSep = utils::ReadPostedParam('separator', ',');
|
||||
$sTQualif = utils::ReadPostedParam('textqualifier', '"');
|
||||
|
||||
$aSeparators = array(',' => ', (coma)', ';' => ';', ';' => ';', '|' => '|', '#' => '#', '@' => '@', ':' => ':');
|
||||
$aTextQualifiers = array('"' => '"', "'" => "'", '`' => '`', '/' => '/');
|
||||
|
||||
$oPage->add("<form method=\"post\" action=\"\">");
|
||||
$oPage->MakeClassesSelect("class", $sClass, 50, UR_ACTION_BULK_MODIFY);
|
||||
$oPage->add("<br/>");
|
||||
$oPage->add("<textarea rows=\"25\" cols=\"100\" name=\"csvdata\" wrap=\"soft\">$sCSVData</textarea>");
|
||||
$oPage->add("<textarea rows=\"25\" cols=\"100\" name=\"csvdata\" wrap=\"soft\">".htmlentities($sCSVData)."</textarea>");
|
||||
$oPage->add("<br/>");
|
||||
$oPage->add("Separator: ");
|
||||
$oPage->add_select($aSeparators, 'separator', $sSep, 50);
|
||||
$oPage->add("<br/>");
|
||||
$oPage->add("Text qualifier: ");
|
||||
$oPage->add_select($aTextQualifiers, 'textqualifier', $sTQualif, 50);
|
||||
$oPage->add("<br/>");
|
||||
$oPage->add("<input type=\"hidden\" name=\"fromwiztep\" value=\"$sWiztep\">");
|
||||
$oPage->add("<input type=\"submit\" name=\"todo\" value=\"Next\"><br/>\n");
|
||||
@@ -415,12 +431,13 @@ function Do_Format($oPage, $sClass)
|
||||
$sWiztep = "2_format";
|
||||
|
||||
$sCSVData = utils::ReadPostedParam('csvdata');
|
||||
$oCSVParser = new CSVParser($sCSVData);
|
||||
$sSep = $oCSVParser->GuessSeparator();
|
||||
$iSkip = $oCSVParser->GuessSkipLines();
|
||||
$sSep = utils::ReadPostedParam('separator');
|
||||
$sTQualif = utils::ReadPostedParam('textqualifier');
|
||||
$oCSVParser = new CSVParser($sCSVData, $sSep, $sTQualif);
|
||||
$iSkip = 1;
|
||||
|
||||
// No data ?
|
||||
$aData = $oCSVParser->ToArray(null);
|
||||
$aData = $oCSVParser->ToArray();
|
||||
$iTarget = count($aData);
|
||||
if ($iTarget == 0)
|
||||
{
|
||||
@@ -429,29 +446,32 @@ function Do_Format($oPage, $sClass)
|
||||
return;
|
||||
}
|
||||
|
||||
// Guess the format :
|
||||
$oPage->p("Guessed separator: '<strong>$sSep</strong>' (ASCII=".ord($sSep).")");
|
||||
$oPage->p("Guessed # of lines to skip: $iSkip");
|
||||
// Expected format - to be improved
|
||||
$oPage->p("Separator: '<strong>$sSep</strong>'");
|
||||
$oPage->p("Text qualifier: '<strong>$sTQualif</strong>'");
|
||||
$oPage->p("The first line will be skipped (considered as being the list of fields)");
|
||||
|
||||
$oPage->p("Target: $iTarget rows");
|
||||
|
||||
$oPage->Add("<form method=\"post\" action=\"\">");
|
||||
$oPage->add("<form method=\"post\" action=\"\">");
|
||||
ShowTableForm($oPage, $oCSVParser, $sClass);
|
||||
$oPage->Add("<input type=\"hidden\" name=\"class\" value=\"$sClass\">");
|
||||
$oPage->Add("<input type=\"hidden\" name=\"csvdata\" value=\"$sCSVData\">");
|
||||
$oPage->Add("<input type=\"hidden\" name=\"separator\" value=\"$sSep\">");
|
||||
$oPage->Add("<input type=\"hidden\" name=\"skiplines\" value=\"$iSkip\">");
|
||||
$oPage->add("<input type=\"hidden\" name=\"class\" value=\"$sClass\">");
|
||||
$oPage->add("<input type=\"hidden\" name=\"csvdata\" value=\"".htmlentities($sCSVData)."\">");
|
||||
$oPage->add("<input type=\"hidden\" name=\"separator\" value=\"".htmlentities($sSep)."\">");
|
||||
$oPage->add("<input type=\"hidden\" name=\"textqualifier\" value=\"".htmlentities($sTQualif)."\">");
|
||||
$oPage->add("<input type=\"hidden\" name=\"skiplines\" value=\"$iSkip\">");
|
||||
|
||||
$oPage->Add("<input type=\"hidden\" name=\"fromwiztep\" value=\"$sWiztep\">");
|
||||
$oPage->add("<input type=\"submit\" name=\"todo\" value=\"Back\">");
|
||||
$oPage->Add("<input type=\"submit\" name=\"todo\" value=\"Next\">");
|
||||
$oPage->Add("</form>");
|
||||
$oPage->add("<input type=\"hidden\" name=\"fromwiztep\" value=\"$sWiztep\">");
|
||||
$oPage->add("<input type=\"submit\" name=\"todo\" value=\"Back\">");
|
||||
$oPage->add("<input type=\"submit\" name=\"todo\" value=\"Next\">");
|
||||
$oPage->add("</form>");
|
||||
}
|
||||
|
||||
function DoProcessOrVerify($oPage, $sClass, CMDBChange $oChange = null)
|
||||
{
|
||||
$sCSVData = utils::ReadPostedParam('csvdata');
|
||||
$sSep = utils::ReadPostedParam('separator');
|
||||
$sTQualif = utils::ReadPostedParam('textqualifier');
|
||||
$iSkip = utils::ReadPostedParam('skiplines');
|
||||
$aFieldMap = utils::ReadPostedParam('fmap');
|
||||
$aIsReconcKey = utils::ReadPostedParam('iskey');
|
||||
@@ -465,16 +485,15 @@ function DoProcessOrVerify($oPage, $sClass, CMDBChange $oChange = null)
|
||||
return;
|
||||
}
|
||||
|
||||
$oCSVParser = new CSVParser($sCSVData);
|
||||
$oCSVParser->SetSeparator($sSep);
|
||||
$oCSVParser->SetSkipLines($iSkip);
|
||||
$aData = $oCSVParser->ToArray(null);
|
||||
$oCSVParser = new CSVParser($sCSVData, $sSep, $sTQualif);
|
||||
$aData = $oCSVParser->ToArray($iSkip, null);
|
||||
$iTarget = count($aData);
|
||||
|
||||
$oPage->p("<h2>Goal summary</h2>");
|
||||
$oPage->p("Target: $iTarget rows");
|
||||
|
||||
$aSampleData = $oCSVParser->ToArray(array_keys($aFieldMap), 5);
|
||||
$aSampleData = $oCSVParser->ToArray($iSkip, array_keys($aFieldMap), 5);
|
||||
|
||||
$aDisplayConfig = array();
|
||||
$aExtKeys = array();
|
||||
foreach ($aFieldMap as $sFieldId=>$sColDesc)
|
||||
@@ -519,6 +538,7 @@ function DoProcessOrVerify($oPage, $sClass, CMDBChange $oChange = null)
|
||||
$aDisplayConfig[$sFieldId] = array("label"=>"-?-?-$sColDesc-?-?-", "description"=>"");
|
||||
}
|
||||
}
|
||||
|
||||
$oPage->table($aDisplayConfig, $aSampleData);
|
||||
|
||||
if ($oChange)
|
||||
@@ -558,8 +578,9 @@ function DoProcessOrVerify($oPage, $sClass, CMDBChange $oChange = null)
|
||||
|
||||
$oPage->add("<form method=\"post\" action=\"\">");
|
||||
$oPage->add("<input type=\"hidden\" name=\"class\" value=\"$sClass\">");
|
||||
$oPage->add("<input type=\"hidden\" name=\"csvdata\" value=\"$sCSVData\">");
|
||||
$oPage->add("<input type=\"hidden\" name=\"separator\" value=\"$sSep\">");
|
||||
$oPage->add("<input type=\"hidden\" name=\"csvdata\" value=\"".htmlentities($sCSVData)."\">");
|
||||
$oPage->add("<input type=\"hidden\" name=\"separator\" value=\"".htmlentities($sSep)."\">");
|
||||
$oPage->add("<input type=\"hidden\" name=\"textqualifier\" value=\"".htmlentities($sTQualif)."\">");
|
||||
$oPage->add("<input type=\"hidden\" name=\"skiplines\" value=\"$iSkip\">");
|
||||
$oPage->add_input_hidden("fmap", $aFieldMap);
|
||||
$oPage->add_input_hidden("iskey", $aIsReconcKey);
|
||||
|
||||
@@ -149,36 +149,6 @@ function DisplayChangesLog(WebPage $oPage, $sClassName, $sKey)
|
||||
$oPage->p("<a href=\"?operation=delete&class=$sClassName&key=$sKey\">Delete this object (no confirmation!)</a>");
|
||||
}
|
||||
|
||||
function DumpObjectsAsCSV(WebPage $oPage, $sClassName, $oSearchFilter = null, $sSeparator = ",")
|
||||
{
|
||||
global $oContext;
|
||||
|
||||
$aHeader = array();
|
||||
$aHeader[] = 'pkey';
|
||||
foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
$aHeader[] = $oAttDef->GetLabel();
|
||||
}
|
||||
$oPage->Add(join($sSeparator, $aHeader)."\n");
|
||||
|
||||
if ($oSearchFilter == null)
|
||||
{
|
||||
$oSearchFilter = $oContext->NewFilter($sClassName);
|
||||
}
|
||||
$oObjectSet = new CMDBObjectSet($oSearchFilter);
|
||||
|
||||
while ($oObj = $oObjectSet->Fetch())
|
||||
{
|
||||
$aRow = array();
|
||||
$aRow[] = $oObj->GetKey();
|
||||
foreach($oObj->GetAttributesList($sClassName) as $sAttCode)
|
||||
{
|
||||
$aRow[] = $oObj->GetAsCSV($sAttCode);
|
||||
}
|
||||
$oPage->Add(join($sSeparator, $aRow)."\n");
|
||||
}
|
||||
}
|
||||
|
||||
function DumpObjects(WebPage $oPage, $sClassName, CMDBSearchFilter $oSearchFilter = null)
|
||||
{
|
||||
global $oContext;
|
||||
@@ -554,32 +524,6 @@ switch($operation)
|
||||
DeleteObject($oPage, $sClass, $sKey);
|
||||
break;
|
||||
|
||||
case 'direct':
|
||||
$sFilter = ReadParam('filter');
|
||||
$sFormat = ReadParam('format', 'html');
|
||||
$oSearchFilter = CMDBSearchFilter::unserialize($sFilter);
|
||||
switch($sFormat)
|
||||
{
|
||||
case 'csv':
|
||||
$oPage->small_p($oSearchFilter->__DescribeHTML());
|
||||
$oPage->Add("<TEXTAREA ROWS=\"30\" COLS=\"100\">");
|
||||
DumpObjectsAsCSV($oPage, $oSearchFilter->GetClass(), $oSearchFilter);
|
||||
$oPage->Add("</TEXTAREA>");
|
||||
break;
|
||||
|
||||
case 'xls':
|
||||
$oPage->add_header('Content-disposition: attachment;filename=served.xls'); // Will fool Excel
|
||||
$oPage->add_header('Content-Type: application/vnd.ms-excel'); // Will fool Excel
|
||||
DumpObjects($oPage, $oSearchFilter->GetClass(), $oSearchFilter);
|
||||
break;
|
||||
|
||||
case 'html':
|
||||
default:
|
||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||
cmdbAbstractObject::DisplaySet($oPage, $oSet);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'addlinks':
|
||||
$sClass = ReadParam('class');
|
||||
$sKey = ReadParam('key');
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,49 +5,64 @@
|
||||
* 'file' string Name of the file to load
|
||||
* 'session_status' string 'start', 'continue' or 'end'
|
||||
* 'percent' integer 0..100 the percentage of completion once the file has been loaded
|
||||
*/
|
||||
*/
|
||||
define('SAFE_MINIMUM_MEMORY', 32*1024*1024);
|
||||
require_once('../application/utils.inc.php');
|
||||
require_once('./setuppage.class.inc.php');
|
||||
|
||||
$iMemoryLimit = utils::ConvertToBytes(ini_get('memory_limit'));
|
||||
if ($iMemoryLimit < SAFE_MINIMUM_MEMORY)
|
||||
{
|
||||
if (ini_set('memory_limit', SAFE_MINIMUM_MEMORY) === FALSE)
|
||||
{
|
||||
SetupWebPage::error("memory_limit is too small: $iMemoryLimit and can not be increased by the script itself.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupWebPage::log("memory_limit increased from $iMemoryLimit to ".SAFE_MINIMUM_MEMORY.".");
|
||||
}
|
||||
}
|
||||
|
||||
function FatalErrorCatcher($sOutput)
|
||||
{
|
||||
if ( preg_match('|<phpfatalerror>.*</phpfatalerror>|s', $sOutput, &$aMatches) )
|
||||
{
|
||||
|
||||
$sMemoryLimit = trim(ini_get('memory_limit'));
|
||||
if (empty($sMemoryLimit))
|
||||
{
|
||||
// On some PHP installations, memory_limit does not exist as a PHP setting!
|
||||
// (encountered on a 5.2.0 under Windows)
|
||||
// In that case, ini_set will not work, let's keep track of this and proceed with the data load
|
||||
SetupWebPage::log_info("No memory limit has been defined in this instance of PHP");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check that the limit will allow us to load the data
|
||||
//
|
||||
$iMemoryLimit = utils::ConvertToBytes($sMemoryLimit);
|
||||
if ($iMemoryLimit < SAFE_MINIMUM_MEMORY)
|
||||
{
|
||||
if (ini_set('memory_limit', SAFE_MINIMUM_MEMORY) === FALSE)
|
||||
{
|
||||
SetupWebPage::log_error("memory_limit is too small: $iMemoryLimit and can not be increased by the script itself.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupWebPage::log_info("memory_limit increased from $iMemoryLimit to ".SAFE_MINIMUM_MEMORY.".");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function FatalErrorCatcher($sOutput)
|
||||
{
|
||||
if ( preg_match('|<phpfatalerror>.*</phpfatalerror>|s', $sOutput, $aMatches) )
|
||||
{
|
||||
header("HTTP/1.0 500 Internal server error.");
|
||||
foreach ($aMatches as $sMatch)
|
||||
{
|
||||
$errors .= strip_tags($sMatch)."\n";
|
||||
}
|
||||
$sOutput = "$errors\n";
|
||||
// Logging to a file does not work if the whole memory is exhausted...
|
||||
//SetupWebPage::error("Fatal error - in $__FILE__ , $errors");
|
||||
}
|
||||
$sOutput = "$errors\n";
|
||||
// Logging to a file does not work if the whole memory is exhausted...
|
||||
//SetupWebPage::log_error("Fatal error - in $__FILE__ , $errors");
|
||||
}
|
||||
return $sOutput;
|
||||
}
|
||||
}
|
||||
|
||||
//Define some bogus, invalid HTML tags that no sane
|
||||
//person would ever put in an actual document and tell
|
||||
//PHP to delimit fatal error warnings with them.
|
||||
//Define some bogus, invalid HTML tags that no sane
|
||||
//person would ever put in an actual document and tell
|
||||
//PHP to delimit fatal error warnings with them.
|
||||
ini_set('error_prepend_string', '<phpfatalerror>');
|
||||
ini_set('error_append_string', '</phpfatalerror>');
|
||||
|
||||
// Starts the capture of the ouput, and sets a filter to capture the fatal errors.
|
||||
ob_start('FatalErrorCatcher'); // Start capturing the output, and pass it through the fatal error catcher
|
||||
|
||||
|
||||
// Starts the capture of the ouput, and sets a filter to capture the fatal errors.
|
||||
ob_start('FatalErrorCatcher'); // Start capturing the output, and pass it through the fatal error catcher
|
||||
|
||||
require_once('../core/config.class.inc.php');
|
||||
require_once('../core/cmdbsource.class.inc.php');
|
||||
require_once('./xmldataloader.class.inc.php');
|
||||
@@ -58,14 +73,14 @@ define('TMP_CONFIG_FILE', '../tmp-config-itop.php');
|
||||
// Never cache this page
|
||||
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
|
||||
header("Expires: Fri, 17 Jul 1970 05:00:00 GMT"); // Date in the past
|
||||
|
||||
|
||||
/**
|
||||
* Main program
|
||||
*/
|
||||
$sFileName = Utils::ReadParam('file', '');
|
||||
$sSessionStatus = Utils::ReadParam('session_status', '');
|
||||
$iPercent = (integer)Utils::ReadParam('percent', 0);
|
||||
SetupWebPage::log("Info - Loading file: $sFileName");
|
||||
SetupWebPage::log_info("Loading file: $sFileName");
|
||||
|
||||
try
|
||||
{
|
||||
@@ -81,30 +96,30 @@ try
|
||||
$oChange->Set("date", time());
|
||||
$oChange->Set("userinfo", "Initialization");
|
||||
$iChangeId = $oChange->DBInsert();
|
||||
SetupWebPage::log("Info - starting data load session");
|
||||
SetupWebPage::log_info("starting data load session");
|
||||
$oDataLoader->StartSession($oChange);
|
||||
}
|
||||
|
||||
$oDataLoader->LoadFile($sFileName);
|
||||
$sResult = sprintf("Info - loading of %s done. (Overall %d %% completed).", basename($sFileName), $iPercent);
|
||||
$sResult = sprintf("loading of %s done. (Overall %d %% completed).", basename($sFileName), $iPercent);
|
||||
echo $sResult;
|
||||
SetupWebPage::log($sResult);
|
||||
SetupWebPage::log_info($sResult);
|
||||
|
||||
if ($sSessionStatus == 'end')
|
||||
{
|
||||
$oDataLoader->EndSession();
|
||||
SetupWebPage::log("Info - ending data load session");
|
||||
SetupWebPage::log_info("ending data load session");
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
echo "<p>An error happened while loading the data</p>\n";
|
||||
echo '<p>'.$e."</p>\n";
|
||||
SetupWebPage::log("Error - An error happened while loading the data. ".$e);
|
||||
}
|
||||
|
||||
if (function_exists('memory_get_peak_usage'))
|
||||
{
|
||||
SetupWebPage::log("Info - loading file '$sFileName', peak memory usage. ".memory_get_peak_usage());
|
||||
SetupWebPage::log_error("An error happened while loading the data. ".$e);
|
||||
}
|
||||
|
||||
if (function_exists('memory_get_peak_usage'))
|
||||
{
|
||||
SetupWebPage::log_info("loading file '$sFileName', peak memory usage. ".memory_get_peak_usage());
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -101,25 +101,25 @@ table.formTable {
|
||||
public function info($sText)
|
||||
{
|
||||
$this->add("<p class=\"info\">$sText</p>\n");
|
||||
$this->log("Info - ".$sText);
|
||||
$this->log_info($sText);
|
||||
}
|
||||
|
||||
public function ok($sText)
|
||||
{
|
||||
$this->add("<p class=\"ok\">$sText</p>\n");
|
||||
$this->log("Ok - ".$sText);
|
||||
$this->log_ok($sText);
|
||||
}
|
||||
|
||||
public function warning($sText)
|
||||
{
|
||||
$this->add("<p class=\"warning\">$sText</p>\n");
|
||||
$this->log("Warning - ".$sText);
|
||||
$this->log_warning($sText);
|
||||
}
|
||||
|
||||
public function error($sText)
|
||||
{
|
||||
$this->add("<p class=\"error\">$sText</p>\n");
|
||||
$this->log("Error - ".$sText);
|
||||
$this->log_error($sText);
|
||||
}
|
||||
|
||||
public function form($aData)
|
||||
@@ -159,6 +159,26 @@ table.formTable {
|
||||
return parent::output();
|
||||
}
|
||||
|
||||
public static function log_error($sText)
|
||||
{
|
||||
self::log("Error - ".$sText);
|
||||
}
|
||||
|
||||
public static function log_warning($sText)
|
||||
{
|
||||
self::log("Warning - ".$sText);
|
||||
}
|
||||
|
||||
public static function log_info($sText)
|
||||
{
|
||||
self::log("Info - ".$sText);
|
||||
}
|
||||
|
||||
public static function log_ok($sText)
|
||||
{
|
||||
self::log("Ok - ".$sText);
|
||||
}
|
||||
|
||||
public static function log($sText)
|
||||
{
|
||||
$hLogFile = @fopen(INSTALL_LOG_FILE, 'a');
|
||||
|
||||
@@ -177,7 +177,7 @@ class XMLDataLoader
|
||||
// tested by Romain, little impact on perf (not significant on the intial setup)
|
||||
if (!$oTargetObj->CheckValue($sAttCode, (string)$oXmlObj->$sAttCode))
|
||||
{
|
||||
SetupWebPage::log("Error - Value not allowed - $sClass/$iSrcId - $sAttCode: '".$oXmlObj->$sAttCode."'");
|
||||
SetupWebPage::log_error("Value not allowed - $sClass/$iSrcId - $sAttCode: '".$oXmlObj->$sAttCode."'");
|
||||
echo "Wrong value for attribute $sAttCode: '".$oXmlObj->$sAttCode."'";
|
||||
}
|
||||
$oTargetObj->Set($sAttCode, (string)$oXmlObj->$sAttCode);
|
||||
@@ -223,7 +223,7 @@ class XMLDataLoader
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
SetupWebPage::log("Error - An object could not be loaded - $sClass/$iSrcId - ".$e->getMessage());
|
||||
SetupWebPage::log_error("An object could not be loaded - $sClass/$iSrcId - ".$e->getMessage());
|
||||
echo $e->GetHtmlDesc();
|
||||
}
|
||||
$aParentClasses = MetaModel::EnumParentClasses($sClass);
|
||||
@@ -257,7 +257,7 @@ class XMLDataLoader
|
||||
if ($iExtKey == 0)
|
||||
{
|
||||
$sMsg = "unresolved extkey in $sClass::".$oTargetObj->GetKey()."(".$oTargetObj->GetName().")::$sAttCode=$sTargetClass::$iTempKey";
|
||||
SetupWebPage::log("Warning - $sMsg");
|
||||
SetupWebPage::log_warning($sMsg);
|
||||
echo "Warning: $sMsg<br/>\n";
|
||||
echo "<pre>aKeys[".$sTargetClass."]:\n";
|
||||
print_r($this->m_aKeys[$sTargetClass]);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// - only external fields attributes could be used as reconciliation keys for external keys
|
||||
// - reconciliation is made on the first column
|
||||
// - no option to force 'always create' or 'never create'
|
||||
// - text qualifier hardcoded to "
|
||||
//
|
||||
// Known issues
|
||||
// - ALMOST impossible to troubleshoot when an externl key has a wrong value
|
||||
@@ -58,11 +59,9 @@ try
|
||||
$sSep = utils::ReadParam('separator', ';');
|
||||
$sCSVData = utils::ReadPostedParam('csvdata');
|
||||
|
||||
$oCSVParser = new CSVParser($sCSVData);
|
||||
$oCSVParser->SetSeparator($sSep);
|
||||
$oCSVParser->SetSkipLines(1);
|
||||
$oCSVParser = new CSVParser($sCSVData, $sSep, $sDelimiter = '"');
|
||||
|
||||
// Limitation: as the attribute list is in the first line, we can not match external key by an third-party attribute
|
||||
// Limitation: as the attribute list is in the first line, we can not match external key by a third-party attribute
|
||||
$sRawFieldList = $oCSVParser->ListFields();
|
||||
$aAttList = array();
|
||||
$aExtKeys = array();
|
||||
@@ -93,9 +92,6 @@ try
|
||||
// Limitation: the reconciliation key is the first attribute
|
||||
$aReconcilKeys = array($sRawFieldList[0]);
|
||||
|
||||
// print_r($oCSVParser->ListFields());
|
||||
// print_r($oCSVParser->ToArray($oCSVParser->ListFields()));
|
||||
|
||||
$aData = $oCSVParser->ToArray();
|
||||
$oBulk = new BulkChange(
|
||||
$sClass,
|
||||
|
||||
Reference in New Issue
Block a user