mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-23 18:48:51 +02:00
N°2250 - DisplayObject with ormLinkSet ignore Removed
This commit is contained in:
@@ -2367,6 +2367,7 @@ EOF
|
||||
$sHTMLValue = ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oTagSetBlock);
|
||||
} else {
|
||||
$sInputType = self::ENUM_INPUT_TYPE_LINKEDSET;
|
||||
$oObj = $aArgs['this'] ?? null;
|
||||
if ($oAttDef->IsIndirect()) {
|
||||
$oWidget = new UILinksWidget($sClass, $sAttCode, $iId, $sNameSuffix,
|
||||
$oAttDef->DuplicatesAllowed());
|
||||
@@ -2375,7 +2376,6 @@ EOF
|
||||
}
|
||||
$aEventsList[] = 'validate';
|
||||
$aEventsList[] = 'change';
|
||||
$oObj = $aArgs['this'] ?? null;
|
||||
$sHTMLValue = $oWidget->Display($oPage, $value, array(), $sFormPrefix, $oObj);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -845,6 +845,11 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
}
|
||||
$oLinkSearch->SetSelectedClasses([self::LINK_ALIAS, self::REMOTE_ALIAS]);
|
||||
}
|
||||
if (count($this->aRemoved) !== 0) {
|
||||
$sConditionExpr = '`'.self::LINK_ALIAS.'`.id NOT IN ('.implode(',', $this->aRemoved).')';
|
||||
$oRemovedExpression = Expression::FromOQL($sConditionExpr);
|
||||
$oLinkSearch->AddConditionExpression($oRemovedExpression);
|
||||
}
|
||||
$oLinkSet = new DBObjectSet($oLinkSearch);
|
||||
$oLinkSet->SetShowObsoleteData($bShowObsolete);
|
||||
if ($this->HasDelta()) {
|
||||
@@ -873,4 +878,12 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DBObjectSet|null
|
||||
*/
|
||||
public function GetOriginalSet(): ?DBObjectSet
|
||||
{
|
||||
return $this->oOriginalSet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,6 @@ Selectize.define("combodo_update_operations", function (aOptions) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
@@ -81,6 +81,8 @@ class Set extends AbstractInput
|
||||
/** @var bool $bHasError Error flag */
|
||||
private bool $bHasError;
|
||||
|
||||
private ?string $sInitialValue = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@@ -424,4 +426,23 @@ class Set extends AbstractInput
|
||||
{
|
||||
return $this->bHasError;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetInitialValue(): string
|
||||
{
|
||||
if (is_null($this->sInitialValue)) {
|
||||
return $this->GetValue();
|
||||
}
|
||||
return $this->sInitialValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sInitialValue
|
||||
*/
|
||||
public function SetInitialValue(string $sInitialValue): void
|
||||
{
|
||||
$this->sInitialValue = $sInitialValue;
|
||||
}
|
||||
}
|
||||
@@ -8,19 +8,17 @@ namespace Combodo\iTop\Application\UI\Links\Indirect;
|
||||
|
||||
use AttributeLinkedSetIndirect;
|
||||
use cmdbAbstractObject;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Service\Links\LinkSetModel;
|
||||
use ConfigException;
|
||||
use CoreException;
|
||||
use DBObject;
|
||||
use Exception;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
use UILinksWidget;
|
||||
use utils;
|
||||
@@ -60,7 +58,7 @@ class BlockIndirectLinkSetEditTable extends UIContentBlock
|
||||
/** @var int */
|
||||
public int $iMaxAddedId = 0;
|
||||
|
||||
/** @var array */
|
||||
/** @var array List of removed links id used by twig template */
|
||||
public array $aRemoved = [];
|
||||
|
||||
/** @var string */
|
||||
@@ -131,7 +129,7 @@ class BlockIndirectLinkSetEditTable extends UIContentBlock
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
*/
|
||||
public function InitTable(\WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $aTableConfig)
|
||||
public function InitTable(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $aTableConfig)
|
||||
{
|
||||
$this->sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oValue->Rewind();
|
||||
@@ -139,29 +137,48 @@ class BlockIndirectLinkSetEditTable extends UIContentBlock
|
||||
$aForm = array();
|
||||
$iMaxAddedId = 0;
|
||||
$iAddedId = -1; // Unique id for new links
|
||||
$this->aRemoved = json_decode(\utils::ReadPostedParam("attr_{$sFormPrefix}{$this->oUILinksWidget->GetAttCode()}_tbd", '[]', 'raw_data'));
|
||||
$this->aRemoved = json_decode(\utils::ReadPostedParam("attr_{$sFormPrefix}{$this->oUILinksWidget->GetAttCode()}_tbd", '[]', 'raw_data'), true);
|
||||
$aModified = json_decode(\utils::ReadPostedParam("attr_{$sFormPrefix}{$this->oUILinksWidget->GetAttCode()}_tbm", '[]', 'raw_data'), true);
|
||||
while ($oCurrentLink = $oValue->Fetch()) {
|
||||
// We try to retrieve the remote object as usual
|
||||
if (!in_array($oCurrentLink->GetKey(), $this->aRemoved)) {
|
||||
$oLinkedObj = MetaModel::GetObject($this->oUILinksWidget->GetRemoteClass(), $oCurrentLink->Get($this->oUILinksWidget->GetExternalKeyToRemote()), false /* Must not be found */);
|
||||
// If successful, it means that we can edit its link
|
||||
if ($oLinkedObj !== null) {
|
||||
$bReadOnly = false;
|
||||
} // Else we retrieve it without restrictions (silos) and will display its link as readonly
|
||||
else {
|
||||
$bReadOnly = true;
|
||||
$oLinkedObj = MetaModel::GetObject($this->oUILinksWidget->GetRemoteClass(), $oCurrentLink->Get($this->oUILinksWidget->GetExternalKeyToRemote()), false /* Must not be found */, true);
|
||||
}
|
||||
|
||||
if ($oCurrentLink->IsNew()) {
|
||||
$key = $iAddedId--;
|
||||
} else {
|
||||
$key = $oCurrentLink->GetKey();
|
||||
}
|
||||
|
||||
$iMaxAddedId = max($iMaxAddedId, $key);
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly, $bAllowRemoteExtKeyEdit);
|
||||
$sCurrentLinkId = $oCurrentLink->GetKey();
|
||||
if ($oCurrentLink->IsNew()) {
|
||||
$key = $iAddedId--;
|
||||
} else {
|
||||
$key = $oCurrentLink->GetKey();
|
||||
}
|
||||
|
||||
if (isset($aModified[$sCurrentLinkId])) {
|
||||
// Apply the modifications to the current link
|
||||
$aModifications = $aModified[$sCurrentLinkId];
|
||||
$sPrefix = 'attr_'.$aModifications['formPrefix'];
|
||||
foreach ($aModifications as $sName => $sValue) {
|
||||
if (!utils::StartsWith($sName, $sPrefix)) {
|
||||
continue;
|
||||
}
|
||||
$sAttCode = substr($sName, strlen($sPrefix));
|
||||
$oCurrentLink->Set($sAttCode, $sValue);
|
||||
$sEscapedValue = addslashes($sValue);
|
||||
$oPage->add_ready_script(<<<EOF
|
||||
oWidget{$this->oUILinksWidget->GetInputId()}.OnValueChange($sCurrentLinkId, $iAddedId, "$sAttCode", "$sEscapedValue");
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
$oLinkedObj = MetaModel::GetObject($this->oUILinksWidget->GetRemoteClass(), $oCurrentLink->Get($this->oUILinksWidget->GetExternalKeyToRemote()), false /* Must not be found */);
|
||||
// If successful, it means that we can edit its link
|
||||
if ($oLinkedObj !== null) {
|
||||
$bReadOnly = false;
|
||||
} // Else we retrieve it without restrictions (silos) and will display its link as readonly
|
||||
else {
|
||||
$bReadOnly = true;
|
||||
$oLinkedObj = MetaModel::GetObject($this->oUILinksWidget->GetRemoteClass(), $oCurrentLink->Get($this->oUILinksWidget->GetExternalKeyToRemote()), false /* Must not be found */, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
$iMaxAddedId = max($iMaxAddedId, $key);
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly, $bAllowRemoteExtKeyEdit);
|
||||
}
|
||||
$this->iMaxAddedId = (int)$iMaxAddedId;
|
||||
|
||||
|
||||
@@ -89,7 +89,9 @@ class BlockLinkSetDisplayAsProperty extends UIContentBlock
|
||||
$sTargetField = LinkSetModel::GetTargetField($this->oAttribute);
|
||||
|
||||
// Get objects from linked data
|
||||
$this->aObjectsData = LinkSetRepository::LinksDbSetToTargetObjectArray($this->oValue, $this->sTargetClass, $sTargetField);
|
||||
$aObjectsData = [];
|
||||
LinkSetRepository::LinksDbSetToTargetObjectArray($this->oValue, false, $aObjectsData, $this->sTargetClass, $sTargetField);
|
||||
$this->aObjectsData = array_values($aObjectsData);
|
||||
|
||||
// Twig environment
|
||||
$this->oTwigEnv = TwigHelper::GetTwigEnvironment(TwigHelper::ENUM_TEMPLATES_BASE_PATH_BACKOFFICE);
|
||||
|
||||
@@ -69,13 +69,19 @@ class LinkSetUIBlockFactory extends SetUIBlockFactory
|
||||
|
||||
// Current value
|
||||
$aCurrentValues = LinkSetDataTransformer::Decode($oDbObjectSet, $sTargetClass, $sTargetField);
|
||||
// Some operations can have been done in case of reload after an error
|
||||
$aInitialValues = LinkSetDataTransformer::Decode($oDbObjectSet->GetOriginalSet(), $sTargetClass, $sTargetField);
|
||||
|
||||
// Initial options data
|
||||
$aInitialOptions = LinkSetRepository::LinksDbSetToTargetObjectArray($oDbObjectSet, $sTargetClass, $sTargetField);
|
||||
$aInitialOptions = [];
|
||||
LinkSetRepository::LinksDbSetToTargetObjectArray($oDbObjectSet, false, $aInitialOptions, $sTargetClass, $sTargetField);
|
||||
// Register also original values in case of reload after an error. In order to remember the operations, use the "bForce" flag
|
||||
LinkSetRepository::LinksDbSetToTargetObjectArray($oDbObjectSet->GetOriginalSet(), true, $aInitialOptions, $sTargetClass, $sTargetField);
|
||||
if ($aInitialOptions !== null) {
|
||||
$oSetUIBlock->GetDataProvider()->SetOptions($aInitialOptions);
|
||||
$oSetUIBlock->GetDataProvider()->SetOptions(array_values($aInitialOptions));
|
||||
// Set value
|
||||
$oSetUIBlock->SetValue(json_encode($aCurrentValues));
|
||||
$oSetUIBlock->SetInitialValue(json_encode($aInitialValues));
|
||||
} else {
|
||||
$oSetUIBlock->SetHasError(true);
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ class LinkSetDataTransformer
|
||||
catch (Exception $e) {
|
||||
|
||||
ExceptionLog::LogException($e);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,15 +26,17 @@ class LinkSetRepository
|
||||
{
|
||||
|
||||
/**
|
||||
* LinksDbSetToTargetObjectArray.
|
||||
* Get list of remote objects information based on a linkSet
|
||||
*
|
||||
* @param iDBObjectSetIterator $oDbObjectSet Db object set
|
||||
* @param bool $bForce options with force flag will be kept event if they don't be part of the current value of set
|
||||
* @param array $aInitialOptions
|
||||
* @param string $sTargetClass Target class name
|
||||
* @param string|null $sTargetField Target field
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
static public function LinksDbSetToTargetObjectArray(iDBObjectSetIterator $oDbObjectSet, string $sTargetClass, string $sTargetField = null): ?array
|
||||
static public function LinksDbSetToTargetObjectArray(iDBObjectSetIterator $oDbObjectSet, bool $bForce, array &$aInitialOptions, string $sTargetClass, string $sTargetField = null): ?array
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -52,9 +54,6 @@ class LinkSetRepository
|
||||
$sTargetClass => $aFieldsToLoad,
|
||||
]);
|
||||
|
||||
// Prepare result
|
||||
$aResult = [];
|
||||
|
||||
// Iterate throw objects...
|
||||
$oDbObjectSet->Rewind();
|
||||
while ($oObject = $oDbObjectSet->Fetch()) {
|
||||
@@ -78,16 +77,19 @@ class LinkSetRepository
|
||||
// Remote key
|
||||
$aObjectData['key'] = $oObject->GetKey();
|
||||
|
||||
// force option
|
||||
$aObjectData['force'] = $bForce;
|
||||
|
||||
// Fill loaded columns...
|
||||
foreach ($aFieldsToLoad as $sField) {
|
||||
$aObjectData[$sField] = $oObject->Get($sField);
|
||||
}
|
||||
|
||||
// Compute others data
|
||||
$aResult[] = ObjectRepository::ComputeOthersData($oObject, $sTargetClass, $aObjectData, $aComplementAttributeSpec, $sObjectImageAttCode);
|
||||
$aInitialOptions[$oObject->GetKey()] = ObjectRepository::ComputeOthersData($oObject, $sTargetClass, $aObjectData, $aComplementAttributeSpec, $sObjectImageAttCode);
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
return $aInitialOptions;
|
||||
}
|
||||
catch (Exception $e) {
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ let oWidget{{ oUIBlock.GetId() }} = $('#{{ oUIBlock.GetId() }}').selectize({
|
||||
plugins: {
|
||||
{# PLUGIN update operations #}
|
||||
'combodo_update_operations' : {
|
||||
initial: {{ oUIBlock.GetValue()|raw }},
|
||||
initial: {{ oUIBlock.GetInitialValue()|raw }},
|
||||
},
|
||||
{# PLUGIN combodo auto position #}
|
||||
'combodo_auto_position' : {
|
||||
@@ -106,8 +106,9 @@ let oWidget{{ oUIBlock.GetId() }} = $('#{{ oUIBlock.GetId() }}').selectize({
|
||||
// Retrieve current input value
|
||||
let aSelectedItems = me.getValue();
|
||||
// Filter old options data to keep selected values
|
||||
// (options with force flag will be kept event if they doesn't be part of the current value)
|
||||
let options = Object.values(me.options);
|
||||
options = options.filter(item => aSelectedItems.includes(item['{{ oDataProvider.GetDataValueField() }}']));
|
||||
options = options.filter(item => (typeof(item.force) !== "undefined" && item.force === true) || aSelectedItems.includes(item['{{ oDataProvider.GetDataValueField() }}']));
|
||||
// Merge kept and new values
|
||||
options = $.merge(options, res.data.search_data);
|
||||
// Compute groups
|
||||
|
||||
Reference in New Issue
Block a user