mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-24 11:08:45 +02:00
Trac #86 - CSV format aligned with standard specifications
Trac #93 - Fixed issue within the setup data load (related to memory_limit) Fixed issues with the consultant toolkit: upgrade an existing DB (add new class/attribute) Developed core services to allow for demonstrating impact computation capability Deprecated option operation=direct on page UI.php SVN:trunk[313]
This commit is contained in:
@@ -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)
|
||||
{
|
||||
@@ -194,9 +195,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 +234,34 @@ 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))
|
||||
{
|
||||
$oSet = $this->Get('default_value');
|
||||
return $oSet->GetValues($aArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DBObjectSet::FromScratch($this->Get('linked_class'));
|
||||
}
|
||||
}
|
||||
|
||||
public function GetSupportedRelations()
|
||||
{
|
||||
if (array_key_exists('supported_relations', $this->m_aParams))
|
||||
{
|
||||
$aSupportedRelations = $this->Get('supported_relations');
|
||||
return $aSupportedRelations;
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
public function GetLinkedClass() {return $this->Get('linked_class');}
|
||||
public function GetExtKeyToMe() {return $this->Get('ext_key_to_me');}
|
||||
@@ -252,7 +280,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";
|
||||
}
|
||||
@@ -598,6 +626,14 @@ class AttributeString extends AttributeDBField
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"')
|
||||
{
|
||||
$sFrom = array("\r\n", $sTextQualifier);
|
||||
$sTo = array("\n", $sTextQualifier.$sTextQualifier);
|
||||
$sEscaped = str_replace($sFrom, $sTo, (string)$sValue);
|
||||
return '"'.$sEscaped.'"';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -678,11 +714,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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -982,9 +1013,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.'"';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1231,10 +1265,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 +1428,7 @@ class AttributeBlob extends AttributeDefinition
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAsCSV($sValue, $sSeparator = ';', $sSepEscape = ',')
|
||||
public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"')
|
||||
{
|
||||
return ''; // Not exportable in CSV !
|
||||
}
|
||||
|
||||
@@ -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,148 @@ 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) && (strlen($this->m_aCurrRow[0]) > 0))
|
||||
{
|
||||
$this->m_aDataSet[] = $this->m_aCurrRow;
|
||||
}
|
||||
else
|
||||
{
|
||||
// blank line, skip silently
|
||||
}
|
||||
$this->m_aCurrRow = array();
|
||||
}
|
||||
|
||||
function ToArray($iToSkip = 1, $aFieldMap = null, $iMax = 0)
|
||||
{
|
||||
$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++)
|
||||
{
|
||||
$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)
|
||||
{
|
||||
$aStatsBySeparator[$sSep][] = $aLineCharsCount[ord($sSep)];
|
||||
$iEvent = evSEPARATOR;
|
||||
}
|
||||
}
|
||||
|
||||
// Default to ','
|
||||
$this->SetSeparator(",");
|
||||
|
||||
foreach ($aKnownSeps as $sSep)
|
||||
{
|
||||
// Note: this function is NOT available :-(
|
||||
// stats_variance($aStatsBySeparator[$sSep]);
|
||||
$iMin = min($aStatsBySeparator[$sSep]);
|
||||
$iMax = max($aStatsBySeparator[$sSep]);
|
||||
if (($iMin == $iMax) && ($iMax > 0))
|
||||
elseif ($c == "\n")
|
||||
{
|
||||
$this->SetSeparator($sSep);
|
||||
break;
|
||||
$iEvent = evNEWLINE;
|
||||
}
|
||||
}
|
||||
return $this->GetSeparator();
|
||||
}
|
||||
|
||||
public function GuessSkipLines()
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
$sLine = trim($sLine);
|
||||
if (substr($sLine, 0, 1) == '#') continue;
|
||||
if (empty($sLine)) continue;
|
||||
|
||||
foreach (explode($this->m_sSep, $sLine) as $value)
|
||||
elseif ($c == $this->m_sTextQualifier)
|
||||
{
|
||||
if (is_numeric($value))
|
||||
$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)
|
||||
@@ -883,6 +883,7 @@ abstract class DBObject
|
||||
$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();
|
||||
|
||||
@@ -903,6 +904,38 @@ abstract class DBObject
|
||||
|
||||
public function GetRelatedObjects($sRelCode, $iMaxDepth = 99, &$aResults = array())
|
||||
{
|
||||
foreach (MetaModel::GetLinkedSets($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
$aSupportedRelations = $oAttDef->GetSupportedRelations();
|
||||
if (!array_key_exists($sRelCode, $aSupportedRelations)) continue; //skip
|
||||
|
||||
$bPropagate = true; // #@# Todo: discuss that setting
|
||||
$iDepth = $bPropagate ? $iMaxDepth - 1 : 0;
|
||||
|
||||
$oNeighbors = $this->Get($sAttCode);
|
||||
while ($oObj = $oObjSet->Fetch())
|
||||
{
|
||||
$sRootClass = MetaModel::GetRootClass(get_class($oObj));
|
||||
$sObjKey = $oObj->GetKey();
|
||||
if (array_key_exists($sRootClass, $aResults))
|
||||
{
|
||||
if (array_key_exists($sObjKey, $aResults[$sRootClass]))
|
||||
{
|
||||
continue; // already visited, skip
|
||||
}
|
||||
}
|
||||
|
||||
$aResults[$sRootClass][$sObjKey] = $oObj;
|
||||
if ($iDepth > 0)
|
||||
{
|
||||
$oObj->GetRelatedObjects($sRelCode, $iDepth, $aResults);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
// #@# todo : Discuss the Relations and the way they are defined (do we deprecate the queries ? what are the properties -e.g. depth- and where do we set them ?)
|
||||
foreach (MetaModel::EnumRelationQueries(get_class($this), $sRelCode) as $sDummy => $aQueryInfo)
|
||||
{
|
||||
MetaModel::DbgTrace("object=".$this->GetKey().", depth=$iMaxDepth, rel=".$aQueryInfo["sQuery"]);
|
||||
|
||||
@@ -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,55 @@ 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 ValueSetRelatedObjects extends ValueSetDefinition
|
||||
{
|
||||
protected $m_sRelationCode;
|
||||
protected $m_iMaxDepth;
|
||||
// protected $m_aOrderBy;
|
||||
|
||||
public function __construct($sRelationCode, $iMaxDepth = 99)
|
||||
{
|
||||
$this->m_sRelationCode = $sRelationCode;
|
||||
$this->m_iMaxDepth = $iMaxDepth;
|
||||
// $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()'];
|
||||
|
||||
$oTargetNeighbors = $oTarget->GetRelatedObjects($this->m_sRelationCode, $this->m_iMaxDepth);
|
||||
while ($oObject = $oTargetNeighbors->Fetch())
|
||||
{
|
||||
$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)
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user