');
- fwrite($fd, '');
+ fwrite($fd, '');
fwrite($fd, '');
fwrite($fd, '');
fwrite($fd, '');
diff --git a/core/bulkexport.class.inc.php b/core/bulkexport.class.inc.php
index 46710d04a..4b54bc73e 100644
--- a/core/bulkexport.class.inc.php
+++ b/core/bulkexport.class.inc.php
@@ -281,9 +281,13 @@ abstract class BulkExport
return array(); // return array('csv' => Dict::S('UI:ExportFormatCSV'));
}
+
+ public function SetHttpHeaders(WebPage $oPage)
+ {
+ }
+
public function GetHeader()
{
-
}
abstract public function GetNextChunk(&$aStatus);
public function GetFooter()
diff --git a/core/csvbulkexport.class.inc.php b/core/csvbulkexport.class.inc.php
index 1a55444c1..672b23729 100644
--- a/core/csvbulkexport.class.inc.php
+++ b/core/csvbulkexport.class.inc.php
@@ -58,7 +58,7 @@ class CSVBulkExport extends TabularBulkExport
}
- protected function SuggestField($aAliases, $sClass, $sAlias, $sAttCode)
+ protected function SuggestField($sClass, $sAttCode)
{
switch($sAttCode)
{
@@ -74,7 +74,7 @@ class CSVBulkExport extends TabularBulkExport
}
}
- return parent::SuggestField($aAliases, $sClass, $sAlias, $sAttCode);
+ return parent::SuggestField($sClass, $sAttCode);
}
public function EnumFormParts()
@@ -170,13 +170,19 @@ class CSVBulkExport extends TabularBulkExport
protected function GetSampleData($oObj, $sAttCode)
{
- if ($oObj)
+ return ''.htmlentities($this->GetValue($oObj, $sAttCode), ENT_QUOTES, 'UTF-8').'
';
+ }
+
+ protected function GetValue($oObj, $sAttCode)
+ {
+ switch($sAttCode)
{
- $sRet = trim($oObj->GetAsCSV($sAttCode), '"');
- }
- else
- {
- $sRet = '';
+ case 'id':
+ $sRet = $oObj->GetKey();
+ break;
+
+ default:
+ $sRet = trim($oObj->GetAsCSV($sAttCode), '"');
}
return $sRet;
}
diff --git a/core/dbsearch.class.php b/core/dbsearch.class.php
index 67ca84e78..28597d1b3 100644
--- a/core/dbsearch.class.php
+++ b/core/dbsearch.class.php
@@ -392,7 +392,7 @@ abstract class DBSearch
$sRes = $oSQLQuery->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount, $bBeautifulSQL);
if ($sClassAlias == '_itop_')
{
- echo $sRes."
\n";
+ IssueLog::Info('SQL Query (_itop_): '.$sRes);
}
}
catch (MissingQueryArgument $e)
diff --git a/core/excelbulkexport.class.inc.php b/core/excelbulkexport.class.inc.php
index 0b7ec92eb..223391bc3 100644
--- a/core/excelbulkexport.class.inc.php
+++ b/core/excelbulkexport.class.inc.php
@@ -67,7 +67,7 @@ class ExcelBulkExport extends TabularBulkExport
}
}
- protected function SuggestField($aAliases, $sClass, $sAlias, $sAttCode)
+ protected function SuggestField($sClass, $sAttCode)
{
switch($sAttCode)
{
@@ -83,7 +83,41 @@ class ExcelBulkExport extends TabularBulkExport
}
}
- return parent::SuggestField($aAliases, $sClass, $sAlias, $sAttCode);
+ return parent::SuggestField($sClass, $sAttCode);
+ }
+
+ protected function GetSampleData($oObj, $sAttCode)
+ {
+ return ''.htmlentities($this->GetValue($oObj, $sAttCode), ENT_QUOTES, 'UTF-8').'
';
+ }
+
+ protected function GetValue($oObj, $sAttCode)
+ {
+ switch($sAttCode)
+ {
+ case 'id':
+ $sRet = $oObj->GetKey();
+ break;
+
+ default:
+ $value = $oObj->Get($sAttCode);
+ if ($value instanceOf ormCaseLog)
+ {
+ // Extract the case log as text and remove the "===" which make Excel think that the cell contains a formula the next time you edit it!
+ $sRet = trim(preg_replace('/========== ([^=]+) ============/', '********** $1 ************', $value->GetText()));
+ }
+ else if ($value instanceOf DBObjectSet)
+ {
+ $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
+ $sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
+ }
+ else
+ {
+ $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
+ $sRet = $oAttDef->GetEditValue($value, $oObj);
+ }
+ }
+ return $sRet;
}
public function GetHeader()
@@ -155,30 +189,7 @@ class ExcelBulkExport extends TabularBulkExport
$sField = '';
if ($oObj)
{
- switch($sAttCode)
- {
- case 'id':
- $sField = $oObj->GetKey();
- break;
-
- default:
- $value = $oObj->Get($sAttCode);
- if ($value instanceOf ormCaseLog)
- {
- // Extract the case log as text and remove the "===" which make Excel think that the cell contains a formula the next time you edit it!
- $sField = trim(preg_replace('/========== ([^=]+) ============/', '********** $1 ************', $value->GetText()));
- }
- else if ($value instanceOf DBObjectSet)
- {
- $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
- $sField = $oAttDef->GetAsCSV($value, '', '', $oObj);
- }
- else
- {
- $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
- $sField = $oAttDef->GetEditValue($value, $oObj);
- }
- }
+ $sField = $this->GetValue($oObj, $sAttCode);
}
$aData[] = $sField;
}
diff --git a/core/htmlbulkexport.class.inc.php b/core/htmlbulkexport.class.inc.php
index d742beb14..9bc92ebda 100644
--- a/core/htmlbulkexport.class.inc.php
+++ b/core/htmlbulkexport.class.inc.php
@@ -51,13 +51,31 @@ class HTMLBulkExport extends TabularBulkExport
protected function GetSampleData($oObj, $sAttCode)
{
- if ($oObj)
+ return $this->GetValue($oObj, $sAttCode);
+ }
+
+ protected function GetValue($oObj, $sAttCode)
+ {
+ switch($sAttCode)
{
- $sRet = $oObj->GetAsHTML($sAttCode);
- }
- else
- {
- $sRet = '';
+ case 'id':
+ $sRet = $oObj->GetHyperlink();
+ break;
+
+ default:
+ $value = $oObj->Get($sAttCode);
+ if ($value instanceof ormCaseLog)
+ {
+ $sRet = $value->GetAsSimpleHtml();
+ }
+ elseif ($value instanceof ormStopWatch)
+ {
+ $sRet = $value->GetTimeSpent();
+ }
+ else
+ {
+ $sRet = $oObj->GetAsHtml($sAttCode);
+ }
}
return $sRet;
}
@@ -125,15 +143,7 @@ class HTMLBulkExport extends TabularBulkExport
$sField = '';
if ($oObj)
{
- switch($sAttCode)
- {
- case 'id':
- $sField = $aRow[$sAlias]->GetHyperlink();
- break;
-
- default:
- $sField = $aRow[$sAlias]->GetAsHtml($sAttCode);
- }
+ $sField = $this->GetValue($oObj, $sAttCode);
}
$sValue = ($sField === '') ? ' ' : $sField;
$sData .= "$sValue | ";
diff --git a/core/metamodel.class.php b/core/metamodel.class.php
index 70a2150f4..8e26c5d6e 100644
--- a/core/metamodel.class.php
+++ b/core/metamodel.class.php
@@ -429,6 +429,25 @@ abstract class MetaModel
return $oNameExpr;
}
+ /**
+ * Returns the friendly name IIF it is equivalent to a single attribute
+ */
+ final static public function GetFriendlyNameAttributeCode($sClass)
+ {
+ $aNameSpec = self::GetNameSpec($sClass);
+ $sFormat = trim($aNameSpec[0]);
+ $aAttributes = $aNameSpec[1];
+ if (($sFormat != '') && ($sFormat != '%1$s'))
+ {
+ return null;
+ }
+ if (count($aAttributes) > 1)
+ {
+ return null;
+ }
+ return reset($aAttributes);
+ }
+
final static public function GetStateAttributeCode($sClass)
{
self::_check_subclass($sClass);
diff --git a/core/ormcaselog.class.inc.php b/core/ormcaselog.class.inc.php
index 9e5ed6c0b..7d7cf46e5 100644
--- a/core/ormcaselog.class.inc.php
+++ b/core/ormcaselog.class.inc.php
@@ -212,6 +212,81 @@ class ormCaseLog {
return $sHtml;
}
+ /**
+ * Produces an HTML representation, aimed at being used to produce a PDF with TCPDF (no table)
+ */
+ public function GetAsSimpleHtml()
+ {
+ $sStyleCaseLogHeader = '';
+ $sStyleCaseLogEntry = '';
+
+ $sHtml = '';
+ return $sHtml;
+ }
+
/**
* Produces an HTML representation, aimed at being used within the iTop framework
*/
diff --git a/core/pdfbulkexport.class.inc.php b/core/pdfbulkexport.class.inc.php
index 54f5feb4e..0b70f32d7 100644
--- a/core/pdfbulkexport.class.inc.php
+++ b/core/pdfbulkexport.class.inc.php
@@ -124,6 +124,9 @@ class PDFBulkExport extends HTMLBulkExport
$sData = parent::GetFooter();
$oPage = new PDFPage(Dict::Format('Core:BulkExportOf_Class', MetaModel::GetName($this->oSearch->GetClass())), $this->aStatusInfo['page_size'], $this->aStatusInfo['page_orientation']);
+ $oPDF = $oPage->get_tcpdf();
+ $oPDF->SetFont('dejavusans', '', 8, '', true);
+
$oPage->add(file_get_contents($this->aStatusInfo['tmp_file']));
$oPage->add($sData);
diff --git a/core/spreadsheetbulkexport.class.inc.php b/core/spreadsheetbulkexport.class.inc.php
index 5b8e1dd33..bc979a1ae 100644
--- a/core/spreadsheetbulkexport.class.inc.php
+++ b/core/spreadsheetbulkexport.class.inc.php
@@ -63,17 +63,57 @@ class SpreadsheetBulkExport extends TabularBulkExport
protected function GetSampleData($oObj, $sAttCode)
{
- if ($oObj)
+ return $this->GetValue($oObj, $sAttCode);
+ }
+
+ protected function GetValue($oObj, $sAttCode)
+ {
+ switch($sAttCode)
{
- $sRet = $oObj->GetAsHTML($sAttCode);
- }
- else
- {
- $sRet = '';
+ case 'id':
+ $sRet = $oObj->GetKey();
+ break;
+
+ default:
+ $value = $oObj->Get($sAttCode);
+ $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
+ if ($value instanceof ormCaseLog)
+ {
+ $sRet = str_replace("\n", "
", htmlentities($value->__toString(), ENT_QUOTES, 'UTF-8'));
+ }
+ elseif ($value instanceof ormStopWatch)
+ {
+ $sRet = $value->GetTimeSpent();
+ }
+ elseif ($oAttDef instanceof AttributeString)
+ {
+ $sRet = $oObj->GetAsHTML($sAttCode);
+ }
+ else
+ {
+ if ($this->bLocalizeOutput)
+ {
+ $sRet = htmlentities($oObj->GetEditValue(), ENT_QUOTES, 'UTF-8');
+ }
+ else
+ {
+ $sRet = htmlentities($value, ENT_QUOTES, 'UTF-8');
+ }
+ }
}
+
return $sRet;
}
+ public function SetHttpHeaders(WebPage $oPage)
+ {
+ // Integration within MS-Excel web queries + HTTPS + IIS:
+ // MS-IIS set these header values with no-cache... while Excel fails to do the job if using HTTPS
+ // Then the fix is to force the reset of header values Pragma and Cache-control
+ $oPage->add_header("Pragma:", true);
+ $oPage->add_header("Cache-control:", true);
+ }
+
public function GetHeader()
{
$oSet = new DBObjectSet($this->oSearch);
@@ -99,8 +139,14 @@ class SpreadsheetBulkExport extends TabularBulkExport
$aData[] = $sColLabel;
}
}
+ else
+ {
+ $aData[] = $sColLabel;
+ }
}
- $sData = "\n";
+ $sData = '';
+ $sData .= ''; // Trick for Excel: keep line breaks inside the same cell !
+ $sData .= "\n";
$sData .= "\n";
foreach($aData as $sLabel)
{
@@ -137,14 +183,14 @@ class SpreadsheetBulkExport extends TabularBulkExport
$oObj = $aRow[$sAlias];
if ($oObj == null)
{
- $sData .= "| $sField | ";
+ $sData .= " | ";
continue;
}
switch($sAttCode)
{
case 'id':
- $sField = $oObj->GetName();
+ $sField = $oObj->GetKey();
$sData .= "$sField | ";
break;
@@ -165,22 +211,14 @@ class SpreadsheetBulkExport extends TabularBulkExport
// Trick for Excel: treat the content as text even if it begins with an equal sign
$sData .= "$sField | ";
}
+ else if($oAttDef instanceof AttributeString)
+ {
+ $sField = $oObj->GetAsHTML($sAttCode);
+ $sData .= "$sField | ";
+ }
else
{
$rawValue = $oObj->Get($sAttCode);
- // Due to custom formatting rules, empty friendlynames may be rendered as non-empty strings
- // let's fix this and make sure we render an empty string if the key == 0
- if ($oAttDef instanceof AttributeFriendlyName)
- {
- $sKeyAttCode = $oAttDef->GetKeyAttCode();
- if ($sKeyAttCode != 'id')
- {
- if ($oObj->Get($sKeyAttCode) == 0)
- {
- $sValue = '';
- }
- }
- }
if ($this->bLocalizeOutput)
{
$sField = htmlentities($oFinalAttDef->GetEditValue($rawValue), ENT_QUOTES, 'UTF-8');
diff --git a/core/tabularbulkexport.class.inc.php b/core/tabularbulkexport.class.inc.php
index 8a90b246e..1dd067f5f 100644
--- a/core/tabularbulkexport.class.inc.php
+++ b/core/tabularbulkexport.class.inc.php
@@ -47,12 +47,13 @@ abstract class TabularBulkExport extends BulkExport
break;
default:
- return parent:: DisplayFormPart($oP, $sPartId);
+ return parent::DisplayFormPart($oP, $sPartId);
}
}
protected function SuggestFields($aSuggestedFields)
{
+ $aRet = array();
// By defaults all fields are Ok, nothing gets translated but
// you can overload this method if some fields are better exported
// (in a given format) by using an alternate field, for example id => friendlyname
@@ -71,20 +72,75 @@ abstract class TabularBulkExport extends BulkExport
$sAttCode = $sField;
$sClass = reset($aAliases);
}
- $aSuggestedFields[$idx] = $this->SuggestField($aAliases, $sClass, $sAlias, $sAttCode);
+ $sMostRelevantField = $this->SuggestField($sClass, $sAttCode);
+ $sAttCodeEx = $this->NormalizeFieldSpec($sClass, $sMostRelevantField);
+ // Remove the aliases (if any) from the field names to make them compatible
+ // with the 'short' notation used in this case by the widget
+ if (count($aAliases) > 1)
+ {
+ $sAttCodeEx = $sAlias.'.'.$sAttCodeEx;
+ }
+ $aRet[] = $sAttCodeEx;
}
- return $aSuggestedFields;
+ return $aRet;
}
- protected function SuggestField($aAliases, $sClass, $sAlias, $sAttCode)
+ protected function SuggestField($sClass, $sAttCode)
{
- // Remove the aliases (if any) from the field names to make them compatible
- // with the 'short' notation used in this case by the widget
- if (count($aAliases) == 1)
+ return $sAttCode;
+ }
+
+ /**
+ * Given a field spec, get the most relevant (unique) representation
+ * Examples for a user request:
+ * - friendlyname => ref
+ * - org_name => org_id->name
+ * - org_id_friendlyname => org_id=>name
+ * - caller_name => caller_id->name
+ * - caller_id_friendlyname => caller_id->friendlyname
+ */
+ protected function NormalizeFieldSpec($sClass, $sField)
+ {
+ $sRet = $sField;
+
+ if ($sField == 'id')
{
- return $sAttCode;
+ $sRet = 'id';
}
- return $sAlias.'.'.$sAttCode;
+ elseif ($sField == 'friendlyname')
+ {
+ $sFriendlyNameAttCode = MetaModel::GetFriendlyNameAttributeCode($sClass);
+ if (!is_null($sFriendlyNameAttCode))
+ {
+ // The friendly name is made of a single attribute
+ $sRet = $sFriendlyNameAttCode;
+ }
+ }
+ else
+ {
+ $oAttDef = MetaModel::GetAttributeDef($sClass, $sField);
+ if ($oAttDef instanceof AttributeFriendlyName)
+ {
+ $oKeyAttDef = MetaModel::GetAttributeDef($sClass, $oAttDef->GetKeyAttCode());
+ $sRemoteClass = $oKeyAttDef->GetTargetClass();
+ $sFriendlyNameAttCode = MetaModel::GetFriendlyNameAttributeCode($sRemoteClass);
+ if (is_null($sFriendlyNameAttCode))
+ {
+ // The friendly name is made of several attributes
+ $sRet = $oAttDef->GetKeyAttCode().'->friendlyname';
+ }
+ else
+ {
+ // The friendly name is made of a single attribute
+ $sRet = $oAttDef->GetKeyAttCode().'->'.$sFriendlyNameAttCode;
+ }
+ }
+ elseif ($oAttDef->IsExternalField())
+ {
+ $sRet = $oAttDef->GetKeyAttCode().'->'.$oAttDef->GetExtAttCode();
+ }
+ }
+ return $sRet;
}
protected function IsSubAttribute($sClass, $sAttCode, $oAttDef)
@@ -99,19 +155,64 @@ abstract class TabularBulkExport extends BulkExport
{
case 'AttributeExternalKey':
case 'AttributeHierarchicalKey':
- $aResult[] = array('code' => $sAttCode, 'unique_label' => $oAttDef->GetLabel(), 'label' => Dict::S('Core:BulkExport:Identifier'), 'attdef' => $oAttDef);
- $aResult[] = array('code' => $sAttCode.'_friendlyname', 'unique_label' => $oAttDef->GetLabel().'->'.Dict::S('Core:FriendlyName-Label'), 'label' => Dict::S('Core:FriendlyName-Label'), 'attdef' => MetaModel::GetAttributeDef($sClass, $sAttCode.'_friendlyname'));
+
+ $bAddFriendlyName = true;
+ $oKeyAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
+ $sRemoteClass = $oKeyAttDef->GetTargetClass();
+ $sFriendlyNameAttCode = MetaModel::GetFriendlyNameAttributeCode($sRemoteClass);
+ if (!is_null($sFriendlyNameAttCode))
+ {
+ // The friendly name is made of a single attribute, check if that attribute is present as an external field
+ foreach(MetaModel::ListAttributeDefs($sClass) as $sSubAttCode => $oSubAttDef)
+ {
+ if ($oSubAttDef instanceof AttributeExternalField)
+ {
+ if (($oSubAttDef->GetKeyAttCode() == $sAttCode) && ($oSubAttDef->GetExtAttCode() == $sFriendlyNameAttCode))
+ {
+ $bAddFriendlyName = false;
+ }
+ }
+ }
+ }
+
+ $aResult[$sAttCode] = array('code' => $sAttCode, 'unique_label' => $oAttDef->GetLabel(), 'label' => Dict::S('UI:CSVImport:idField'), 'attdef' => $oAttDef);
+
+ if ($bAddFriendlyName)
+ {
+ if ($this->IsExportableField($sClass, $sAttCode.'->friendlyname'))
+ {
+ $aResult[$sAttCode.'->friendlyname'] = array('code' => $sAttCode.'->friendlyname', 'unique_label' => $oAttDef->GetLabel().'->'.Dict::S('Core:FriendlyName-Label'), 'label' => Dict::S('Core:FriendlyName-Label'), 'attdef' => MetaModel::GetAttributeDef($sClass, $sAttCode.'_friendlyname'));
+ }
+ }
foreach(MetaModel::ListAttributeDefs($sClass) as $sSubAttCode => $oSubAttDef)
{
if ($oSubAttDef instanceof AttributeExternalField)
{
- if ($oSubAttDef->GetKeyAttCode() == $sAttCode)
+ if ($this->IsExportableField($sClass, $sSubAttCode, $oSubAttDef))
{
- $aResult[] = array('code' => $sSubAttCode, 'unique_label' => $oAttDef->GetLabel().'->'.$oSubAttDef->GetExtAttDef()->GetLabel(), 'label' => $oSubAttDef->GetExtAttDef()->GetLabel(), 'attdef' => $oSubAttDef);
+ if ($oSubAttDef->GetKeyAttCode() == $sAttCode)
+ {
+ $sAttCodeEx = $sAttCode.'->'.$oSubAttDef->GetExtAttCode();
+ $aResult[$sAttCodeEx] = array('code' => $sAttCodeEx, 'unique_label' => $oAttDef->GetLabel().'->'.$oSubAttDef->GetExtAttDef()->GetLabel(), 'label' => MetaModel::GetLabel($sRemoteClass, $oSubAttDef->GetExtAttCode()), 'attdef' => $oSubAttDef);
+ }
}
}
}
+
+ // Add the reconciliation keys
+ foreach(MetaModel::GetReconcKeys($sRemoteClass) as $sRemoteAttCode)
+ {
+ $sAttCodeEx = $sAttCode.'->'.$sRemoteAttCode;
+ if (!array_key_exists($sAttCodeEx, $aResult))
+ {
+ $oRemoteAttDef = MetaModel::GetAttributeDef($sRemoteClass, $sRemoteAttCode);
+ if ($this->IsExportableField($sRemoteClass, $sRemoteAttCode, $oRemoteAttDef))
+ {
+ $aResult[$sAttCodeEx] = array('code' => $sAttCodeEx, 'unique_label' => $oAttDef->GetLabel().'->'.$oRemoteAttDef->GetLabel(), 'label' => MetaModel::GetLabel($sRemoteClass, $sRemoteAttCode), 'attdef' => $oRemoteAttDef);
+ }
+ }
+ }
break;
case 'AttributeStopWatch':
@@ -121,12 +222,14 @@ abstract class TabularBulkExport extends BulkExport
{
if ($oSubAttDef->GetParentAttCode() == $sAttCode)
{
- $aResult[] = array('code' => $sSubAttCode, 'unique_label' => $oSubAttDef->GetLabel(), 'label' => $oSubAttDef->GetLabel(), 'attdef' => $oSubAttDef);
+ if ($this->IsExportableField($sClass, $sSubAttCode, $oSubAttDef))
+ {
+ $aResult[$sSubAttCode] = array('code' => $sSubAttCode, 'unique_label' => $oSubAttDef->GetLabel(), 'label' => $oSubAttDef->GetLabel(), 'attdef' => $oSubAttDef);
+ }
}
}
}
break;
-
}
return $aResult;
}
@@ -144,6 +247,7 @@ abstract class TabularBulkExport extends BulkExport
}
}
$aAllFieldsByAlias = array();
+ $aAllAttCodes = array();
foreach($aAuthorizedClasses as $sAlias => $sClass)
{
$aAllFields = array();
@@ -155,18 +259,29 @@ abstract class TabularBulkExport extends BulkExport
{
$sShortAlias = '';
}
- if ($this->IsValidField($sClass, 'id'))
+ if ($this->IsExportableField($sClass, 'id'))
{
- $aAllFields[] = array('code' => $sShortAlias.'id', 'unique_label' => $sShortAlias.Dict::S('Core:BulkExport:Identifier'), 'label' => $sShortAlias.'id', 'subattr' => array(
- array('code' => $sShortAlias.'id', 'unique_label' => $sShortAlias.Dict::S('Core:BulkExport:Identifier'), 'label' => $sShortAlias.'id'),
- array('code' => $sShortAlias.'friendlyname', 'unique_label' => $sShortAlias.Dict::S('Core:FriendlyName-Label'), 'label' => $sShortAlias.Dict::S('Core:FriendlyName-Label')),
- ));
+ $sFriendlyNameAttCode = MetaModel::GetFriendlyNameAttributeCode($sClass);
+ if (is_null($sFriendlyNameAttCode))
+ {
+ // The friendly name is made of several attribute
+ $aSubAttr = array(
+ array('attcodeex' => 'id', 'code' => $sShortAlias.'id', 'unique_label' => $sShortAlias.Dict::S('UI:CSVImport:idField'), 'label' => $sShortAlias.'id'),
+ array('attcodeex' => 'friendlyname', 'code' => $sShortAlias.'friendlyname', 'unique_label' => $sShortAlias.Dict::S('Core:FriendlyName-Label'), 'label' => $sShortAlias.Dict::S('Core:FriendlyName-Label')),
+ );
}
+ else
+ {
+ // The friendly name has no added value
+ $aSubAttr = array();
+ }
+ $aAllFields[] = array('attcodeex' => 'id', 'code' => $sShortAlias.'id', 'unique_label' => $sShortAlias.Dict::S('UI:CSVImport:idField'), 'label' => Dict::S('UI:CSVImport:idField'), 'subattr' => $aSubAttr);
+ }
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if($this->IsSubAttribute($sClass, $sAttCode, $oAttDef)) continue;
- if ($this->IsValidField($sClass, $sAttCode, $oAttDef))
+ if ($this->IsExportableField($sClass, $sAttCode, $oAttDef))
{
$sShortLabel = $oAttDef->GetLabel();
$sLabel = $sShortAlias.$oAttDef->GetLabel();
@@ -174,12 +289,9 @@ abstract class TabularBulkExport extends BulkExport
$aValidSubAttr = array();
foreach($aSubAttr as $aSubAttDef)
{
- if ($this->IsValidField($sClass, $aSubAttDef['code'], $aSubAttDef['attdef']))
- {
- $aValidSubAttr[] = array('code' => $sShortAlias.$aSubAttDef['code'], 'label' => $aSubAttDef['label'], 'unique_label' => $aSubAttDef['unique_label']);
- }
+ $aValidSubAttr[] = array('attcodeex' => $aSubAttDef['code'], 'code' => $sShortAlias.$aSubAttDef['code'], 'label' => $aSubAttDef['label'], 'unique_label' => $sShortAlias.$aSubAttDef['unique_label']);
}
- $aAllFields[] = array('code' => $sShortAlias.$sAttCode, 'label' => $sShortLabel, 'unique_label' => $sLabel, 'subattr' => $aValidSubAttr);
+ $aAllFields[] = array('attcodeex' => $sAttCode, 'code' => $sShortAlias.$sAttCode, 'label' => $sShortLabel, 'unique_label' => $sLabel, 'subattr' => $aValidSubAttr);
}
}
usort($aAllFields, array(get_class($this), 'SortOnLabel'));
@@ -192,12 +304,36 @@ abstract class TabularBulkExport extends BulkExport
$sKey = MetaModel::GetName($sClass);
}
$aAllFieldsByAlias[$sKey] = $aAllFields;
+
+ foreach ($aAllFields as $aFieldSpec)
+ {
+ $sAttCode = $aFieldSpec['attcodeex'];
+ if (count($aFieldSpec['subattr']) > 0)
+ {
+ foreach ($aFieldSpec['subattr'] as $aSubFieldSpec)
+ {
+ $aAllAttCodes[$sAlias][] = $aSubFieldSpec['attcodeex'];
+ }
+ }
+ else
+ {
+ $aAllAttCodes[$sAlias][] = $sAttCode;
+ }
+ }
}
$oP->add('');
$JSAllFields = json_encode($aAllFieldsByAlias);
+
+ // First, fetch only the ids - the rest will be fetched by an object reload
$oSet = new DBObjectSet($this->oSearch);
$iCount = $oSet->Count();
+
+ foreach ($this->oSearch->GetSelectedClasses() as $sAlias => $sClass)
+ {
+ $aColumns[$sAlias] = array();
+ }
+ $oSet->OptimizeColumnLoad($aColumns);
$iPreviewLimit = 3;
$oSet->SetLimit($iPreviewLimit);
$aSampleData = array();
@@ -215,16 +351,10 @@ abstract class TabularBulkExport extends BulkExport
$sShortAlias = '';
}
- if ($this->IsValidField($sClass, 'id'))
+ foreach ($aAllAttCodes[$sAlias] as $sAttCodeEx)
{
- $aSampleRow[$sShortAlias.'id'] = $this->GetSampleKey($aRow[$sAlias]);
- }
- foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
- {
- if ($this->IsValidField($sClass, $sAttCode, $oAttDef))
- {
- $aSampleRow[$sShortAlias.$sAttCode] = $this->GetSampleData($aRow[$sAlias], $sAttCode);
- }
+ $oObj = $aRow[$sAlias];
+ $aSampleRow[$sShortAlias.$sAttCodeEx] = $oObj ? $this->GetSampleData($oObj, $sAttCodeEx) : '';
}
}
$aSampleData[] = $aSampleRow;
@@ -256,28 +386,26 @@ EOF
* Tells if the specified field can be exported
* @param unknown $sClass
* @param unknown $sAttCode
- * @param AttributeDefinition $oAttDef Can be null when $sAttCode == 'id'
+ * @param AttributeDefinition $oAttDef Can be null in case the attribute definition has not been fetched by the caller
* @return boolean
*/
- protected function IsValidField($sClass, $sAttCode, $oAttDef = null)
+ protected function IsExportableField($sClass, $sAttCode, $oAttDef = null)
{
if ($sAttCode == 'id') return true;
+ if (is_null($oAttDef))
+ {
+ $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
+ }
if ($oAttDef instanceof AttributeLinkedSet) return false;
return true; //$oAttDef->IsScalar();
}
protected function GetSampleData($oObj, $sAttCode)
{
- if ($oObj == null) return '';
+ if ($sAttCode == 'id') return $oObj->GetKey();
return $oObj->GetEditValue($sAttCode);
}
- protected function GetSampleKey($oObj)
- {
- if ($oObj == null) return '';
- return $oObj->GetKey();
- }
-
public function ReadParameters()
{
parent::ReadParameters();
@@ -358,7 +486,7 @@ EOF
catch (Exception $e)
{
throw new Exception("Wrong field specification '$sFieldSpec': ".$e->getMessage());
- }
+ }
}
else
{
diff --git a/core/xmlbulkexport.class.inc.php b/core/xmlbulkexport.class.inc.php
index cdf821da6..353872295 100644
--- a/core/xmlbulkexport.class.inc.php
+++ b/core/xmlbulkexport.class.inc.php
@@ -70,14 +70,7 @@ class XMLBulkExport extends BulkExport
protected function GetSampleData($oObj, $sAttCode)
{
- if ($oObj)
- {
- $sRet = $oObj->GetAsXML($sAttCode);
- }
- else
- {
- $sRet = '';
- }
+ $sRet = ($sAttCode == 'id') ? $oObj->GetKey() : $oObj->GetAsXML($sAttCode);
return $sRet;
}
diff --git a/css/light-grey.css b/css/light-grey.css
index 1e12b6ae5..095d6944d 100644
--- a/css/light-grey.css
+++ b/css/light-grey.css
@@ -1956,6 +1956,9 @@ table.export_parameters td {
.table_preview > table {
border-collapse: collapse;
+ max-height: 150px;
+ overflow: auto;
+ display: block;
}
@@ -1968,11 +1971,21 @@ table.export_parameters td {
}
+.table_preview > table > tbody > tr > td {
+ vertical-align: top;
+}
+
+
.table_preview .drag-handle {
cursor: move;
}
+.table_preview div.text-preview {
+ white-space: pre-wrap;
+}
+
+
.graph_zoom {
display: inline-block;
float: right;
diff --git a/css/light-grey.scss b/css/light-grey.scss
index 283bec7c6..6e1126cc2 100644
--- a/css/light-grey.scss
+++ b/css/light-grey.scss
@@ -1445,8 +1445,12 @@ div.ui-dialog-header {
table.export_parameters td {
padding-right: 2em;
}
+
.table_preview > table {
border-collapse: collapse;
+ max-height: 150px;
+ overflow: auto;
+ display: block;
}
.table_preview > table > thead > tr > th, .table_preview > table > tbody > tr > td {
border: 1px $grey-color solid;
@@ -1455,9 +1459,15 @@ table.export_parameters td {
padding-right: 0.25em;
font-size: 10pt;
}
+.table_preview > table > tbody > tr > td {
+ vertical-align: top;
+}
.table_preview .drag-handle {
cursor: move;
}
+.table_preview div.text-preview {
+ white-space: pre-wrap;
+}
.graph_zoom {
display: inline-block;
float: right;
diff --git a/dictionaries/da.dictionary.itop.core.php b/dictionaries/da.dictionary.itop.core.php
index 9eaf032a3..9e9312fcc 100644
--- a/dictionaries/da.dictionary.itop.core.php
+++ b/dictionaries/da.dictionary.itop.core.php
@@ -2446,7 +2446,6 @@ Operators:
'Core:BulkExport:MissingParameter_Param' => 'Missing parameter \"%1$s\"~~',
'Core:BulkExport:InvalidParameter_Query' => 'Invalid value for the parameter \"query\". There is no Query Phrasebook corresponding to the id: \"%1$s\".~~',
'Core:BulkExport:ExportFormatPrompt' => 'Export format:~~',
- 'Core:BulkExport:Identifier' => 'Identifier~~',
'Core:BulkExportOf_Class' => '%1$s Export~~',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Click here to download %1$s~~',
'Core:BulkExport:ExportResult' => 'Result of the export:~~',
diff --git a/dictionaries/de.dictionary.itop.core.php b/dictionaries/de.dictionary.itop.core.php
index 6cbb2ab38..ff7f88f6e 100644
--- a/dictionaries/de.dictionary.itop.core.php
+++ b/dictionaries/de.dictionary.itop.core.php
@@ -558,7 +558,6 @@ Operatoren:
'Core:BulkExport:MissingParameter_Param' => 'Fehlender Parameter "%1$s"',
'Core:BulkExport:InvalidParameter_Query' => 'ungültiger Wert für den Paramter "query". Es gibt keinen Eintrag in der Query-Bibliothek, der zu der id "%1$s" korrespondiert.',
'Core:BulkExport:ExportFormatPrompt' => 'Exportformat:',
- 'Core:BulkExport:Identifier' => 'Identifikator',
'Core:BulkExportOf_Class' => '%1$s-Export',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Klicken Sie hier um %1$s herunterzuladen',
'Core:BulkExport:ExportResult' => 'Ergebnis ses Exportvorgangs:',
diff --git a/dictionaries/dictionary.itop.core.php b/dictionaries/dictionary.itop.core.php
index f38449c18..26f35be17 100644
--- a/dictionaries/dictionary.itop.core.php
+++ b/dictionaries/dictionary.itop.core.php
@@ -810,7 +810,6 @@ Dict::Add('EN US', 'English', 'English', array(
'Core:BulkExport:MissingParameter_Param' => 'Missing parameter "%1$s"',
'Core:BulkExport:InvalidParameter_Query' => 'Invalid value for the parameter "query". There is no Query Phrasebook corresponding to the id: "%1$s".',
'Core:BulkExport:ExportFormatPrompt' => 'Export format:',
- 'Core:BulkExport:Identifier' => 'Identifier',
'Core:BulkExportOf_Class' => '%1$s Export',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Click here to download %1$s',
'Core:BulkExport:ExportResult' => 'Result of the export:',
diff --git a/dictionaries/es_cr.dictionary.itop.core.php b/dictionaries/es_cr.dictionary.itop.core.php
index d4ed181ee..d6f08b373 100644
--- a/dictionaries/es_cr.dictionary.itop.core.php
+++ b/dictionaries/es_cr.dictionary.itop.core.php
@@ -804,7 +804,6 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Core:BulkExport:MissingParameter_Param' => 'Missing parameter \"%1$s\"~~',
'Core:BulkExport:InvalidParameter_Query' => 'Invalid value for the parameter \"query\". There is no Query Phrasebook corresponding to the id: \"%1$s\".~~',
'Core:BulkExport:ExportFormatPrompt' => 'Export format:~~',
- 'Core:BulkExport:Identifier' => 'Identifier~~',
'Core:BulkExportOf_Class' => '%1$s Export~~',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Click here to download %1$s~~',
'Core:BulkExport:ExportResult' => 'Result of the export:~~',
diff --git a/dictionaries/fr.dictionary.itop.core.php b/dictionaries/fr.dictionary.itop.core.php
index 03bdd00d7..73f60ac99 100644
--- a/dictionaries/fr.dictionary.itop.core.php
+++ b/dictionaries/fr.dictionary.itop.core.php
@@ -667,7 +667,6 @@ Opérateurs :
'Core:BulkExport:MissingParameter_Param' => 'Il manque le paramètre "%1$s"',
'Core:BulkExport:InvalidParameter_Query' => 'Valeur incorrecte pour le paramètre "query". Il n\'existe aucune entrée dans le livre des requêtes pour l\'identifiant: "%1$s"',
'Core:BulkExport:ExportFormatPrompt' => 'Format d\'export:',
- 'Core:BulkExport:Identifier' => 'Identifiant',
'Core:BulkExportOf_Class' => 'Export de: %1$s',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Cliquez ici pour télécharger %1$s',
'Core:BulkExport:ExportResult' => 'Résultat de l\'export:',
diff --git a/dictionaries/hu.dictionary.itop.core.php b/dictionaries/hu.dictionary.itop.core.php
index 37ed27085..e508d63d3 100755
--- a/dictionaries/hu.dictionary.itop.core.php
+++ b/dictionaries/hu.dictionary.itop.core.php
@@ -561,7 +561,6 @@ Operators:
'Core:BulkExport:MissingParameter_Param' => 'Missing parameter \"%1$s\"~~',
'Core:BulkExport:InvalidParameter_Query' => 'Invalid value for the parameter \"query\". There is no Query Phrasebook corresponding to the id: \"%1$s\".~~',
'Core:BulkExport:ExportFormatPrompt' => 'Export format:~~',
- 'Core:BulkExport:Identifier' => 'Identifier~~',
'Core:BulkExportOf_Class' => '%1$s Export~~',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Click here to download %1$s~~',
'Core:BulkExport:ExportResult' => 'Result of the export:~~',
diff --git a/dictionaries/it.dictionary.itop.core.php b/dictionaries/it.dictionary.itop.core.php
index 15c3fa986..2818dd9fb 100644
--- a/dictionaries/it.dictionary.itop.core.php
+++ b/dictionaries/it.dictionary.itop.core.php
@@ -793,7 +793,6 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Core:BulkExport:MissingParameter_Param' => 'Missing parameter \"%1$s\"~~',
'Core:BulkExport:InvalidParameter_Query' => 'Invalid value for the parameter \"query\". There is no Query Phrasebook corresponding to the id: \"%1$s\".~~',
'Core:BulkExport:ExportFormatPrompt' => 'Export format:~~',
- 'Core:BulkExport:Identifier' => 'Identifier~~',
'Core:BulkExportOf_Class' => '%1$s Export~~',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Click here to download %1$s~~',
'Core:BulkExport:ExportResult' => 'Result of the export:~~',
diff --git a/dictionaries/ja.dictionary.itop.core.php b/dictionaries/ja.dictionary.itop.core.php
index 57099f2df..3885587b0 100644
--- a/dictionaries/ja.dictionary.itop.core.php
+++ b/dictionaries/ja.dictionary.itop.core.php
@@ -583,7 +583,6 @@ Operators:
'Core:BulkExport:MissingParameter_Param' => 'Missing parameter \"%1$s\"~~',
'Core:BulkExport:InvalidParameter_Query' => 'Invalid value for the parameter \"query\". There is no Query Phrasebook corresponding to the id: \"%1$s\".~~',
'Core:BulkExport:ExportFormatPrompt' => 'Export format:~~',
- 'Core:BulkExport:Identifier' => 'Identifier~~',
'Core:BulkExportOf_Class' => '%1$s Export~~',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Click here to download %1$s~~',
'Core:BulkExport:ExportResult' => 'Result of the export:~~',
diff --git a/dictionaries/nl.dictionary.itop.core.php b/dictionaries/nl.dictionary.itop.core.php
index 2123a3e04..315561dd8 100644
--- a/dictionaries/nl.dictionary.itop.core.php
+++ b/dictionaries/nl.dictionary.itop.core.php
@@ -813,7 +813,6 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'Core:BulkExport:MissingParameter_Param' => 'Missing parameter \"%1$s\"~~',
'Core:BulkExport:InvalidParameter_Query' => 'Invalid value for the parameter \"query\". There is no Query Phrasebook corresponding to the id: \"%1$s\".~~',
'Core:BulkExport:ExportFormatPrompt' => 'Export format:~~',
- 'Core:BulkExport:Identifier' => 'Identifier~~',
'Core:BulkExportOf_Class' => '%1$s Export~~',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Click here to download %1$s~~',
'Core:BulkExport:ExportResult' => 'Result of the export:~~',
diff --git a/dictionaries/pt_br.dictionary.itop.core.php b/dictionaries/pt_br.dictionary.itop.core.php
index daea98b1d..729c0b393 100644
--- a/dictionaries/pt_br.dictionary.itop.core.php
+++ b/dictionaries/pt_br.dictionary.itop.core.php
@@ -806,7 +806,6 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Core:BulkExport:MissingParameter_Param' => 'Missing parameter \"%1$s\"~~',
'Core:BulkExport:InvalidParameter_Query' => 'Invalid value for the parameter \"query\". There is no Query Phrasebook corresponding to the id: \"%1$s\".~~',
'Core:BulkExport:ExportFormatPrompt' => 'Export format:~~',
- 'Core:BulkExport:Identifier' => 'Identifier~~',
'Core:BulkExportOf_Class' => '%1$s Export~~',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Click here to download %1$s~~',
'Core:BulkExport:ExportResult' => 'Result of the export:~~',
diff --git a/dictionaries/ru.dictionary.itop.core.php b/dictionaries/ru.dictionary.itop.core.php
index 1934278e2..2108c883d 100644
--- a/dictionaries/ru.dictionary.itop.core.php
+++ b/dictionaries/ru.dictionary.itop.core.php
@@ -801,7 +801,6 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Core:BulkExport:MissingParameter_Param' => 'Missing parameter \"%1$s\"~~',
'Core:BulkExport:InvalidParameter_Query' => 'Invalid value for the parameter \"query\". There is no Query Phrasebook corresponding to the id: \"%1$s\".~~',
'Core:BulkExport:ExportFormatPrompt' => 'Export format:~~',
- 'Core:BulkExport:Identifier' => 'Identifier~~',
'Core:BulkExportOf_Class' => '%1$s Export~~',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Click here to download %1$s~~',
'Core:BulkExport:ExportResult' => 'Result of the export:~~',
diff --git a/dictionaries/tr.dictionary.itop.core.php b/dictionaries/tr.dictionary.itop.core.php
index df4ec632d..0e9eb1310 100644
--- a/dictionaries/tr.dictionary.itop.core.php
+++ b/dictionaries/tr.dictionary.itop.core.php
@@ -733,7 +733,6 @@ Operators:
'Core:BulkExport:MissingParameter_Param' => 'Missing parameter \"%1$s\"~~',
'Core:BulkExport:InvalidParameter_Query' => 'Invalid value for the parameter \"query\". There is no Query Phrasebook corresponding to the id: \"%1$s\".~~',
'Core:BulkExport:ExportFormatPrompt' => 'Export format:~~',
- 'Core:BulkExport:Identifier' => 'Identifier~~',
'Core:BulkExportOf_Class' => '%1$s Export~~',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Click here to download %1$s~~',
'Core:BulkExport:ExportResult' => 'Result of the export:~~',
diff --git a/dictionaries/zh.dictionary.itop.core.php b/dictionaries/zh.dictionary.itop.core.php
index 0b836efd9..6f1315724 100644
--- a/dictionaries/zh.dictionary.itop.core.php
+++ b/dictionaries/zh.dictionary.itop.core.php
@@ -732,7 +732,6 @@ Operators:
'Core:BulkExport:MissingParameter_Param' => 'Missing parameter \"%1$s\"~~',
'Core:BulkExport:InvalidParameter_Query' => 'Invalid value for the parameter \"query\". There is no Query Phrasebook corresponding to the id: \"%1$s\".~~',
'Core:BulkExport:ExportFormatPrompt' => 'Export format:~~',
- 'Core:BulkExport:Identifier' => 'Identifier~~',
'Core:BulkExportOf_Class' => '%1$s Export~~',
'Core:BulkExport:ClickHereToDownload_FileName' => 'Click here to download %1$s~~',
'Core:BulkExport:ExportResult' => 'Result of the export:~~',
diff --git a/webservices/export-v2.php b/webservices/export-v2.php
index 19769e2b6..c59dc4d8b 100644
--- a/webservices/export-v2.php
+++ b/webservices/export-v2.php
@@ -489,6 +489,7 @@ function CheckParameters($sExpression, $sQueryId, $sFormat)
function DoExport(Page $oP, BulkExport $oExporter, $bInteractive = false)
{
+ $oExporter->SetHttpHeaders($oP);
$exportResult = $oExporter->GetHeader();
$aStatus = array();
do
diff --git a/webservices/itoprest.examples.php b/webservices/itoprest.examples.php
index 076e3d798..2480e647f 100644
--- a/webservices/itoprest.examples.php
+++ b/webservices/itoprest.examples.php
@@ -185,10 +185,15 @@ $aOperations = array(
);
$aOperations = array(
array(
- 'operation' => 'core/get', // operation code
- 'class' => 'PhysicalDevice',
- 'key' => 'SELECT PhysicalDevice WHERE id < 3',
- 'output_fields' => '*+', // list of fields to show in the results (* or a,b,c)
+ 'operation' => 'core/update', // operation code
+ 'comment' => 'Synchronization from blah...', // comment recorded in the change tracking log
+ 'class' => 'Server',
+ 'key' => 'SELECT Server WHERE name="Server1"',
+ 'output_fields' => 'id, friendlyname, description', // list of fields to show in the results (* or a,b,c)
+ // Values for the object to create
+ 'fields' => array(
+ 'description' => 'Issue #'.time(),
+ ),
),
);
$aOperations = array(
@@ -213,6 +218,15 @@ $aXXXOperations = array(
'password' => 'admin',
),
);
+$aOperations = array(
+ array(
+ 'operation' => 'core/delete', // operation code
+ 'comment' => 'Cleanup for synchro with...', // comment recorded in the change tracking log
+ 'class' => 'Server',
+ 'key' => 'SELECT Server',
+ 'simulate' => false,
+ ),
+);
if (false)
{
@@ -225,8 +239,11 @@ else
}
$aData = array();
-$aData['auth_user'] = 'admin';
-$aData['auth_pwd'] = 'admin';
+$aData['auth_user'] = 'no-export';
+$aData['auth_pwd'] = 'no-export';
+//$aData['auth_user'] = 'admin';
+//$aData['auth_pwd'] = 'admin';
+
foreach ($aOperations as $iOp => $aOperation)
{