mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
N°3198 Relations Table Mode : control duplicates server side
This commit is contained in:
@@ -295,7 +295,7 @@ abstract class AttributeDefinition
|
||||
* @param \DBObject $oHostObject
|
||||
* @param $value Object error if any, null otherwise
|
||||
*
|
||||
* @return bool
|
||||
* @return bool|string true for no errors, false or error message otherwise
|
||||
*/
|
||||
public function CheckValue(DBObject $oHostObject, $value)
|
||||
{
|
||||
@@ -2273,22 +2273,17 @@ class AttributeLinkedSetIndirect extends AttributeLinkedSet
|
||||
/** @var \AttributeExternalKey $oExtKeyToRemote */
|
||||
$oExtKeyToRemote = MetaModel::GetAttributeDef($this->GetLinkedClass(), $this->GetExtKeyToRemote());
|
||||
$sRemoteClass = $oExtKeyToRemote->GetTargetClass();
|
||||
foreach(MetaModel::ListAttributeDefs($sRemoteClass) as $sRemoteAttCode => $oRemoteAttDef)
|
||||
{
|
||||
if (!$oRemoteAttDef instanceof AttributeLinkedSetIndirect)
|
||||
{
|
||||
foreach(MetaModel::ListAttributeDefs($sRemoteClass) as $sRemoteAttCode => $oRemoteAttDef) {
|
||||
if (!$oRemoteAttDef instanceof AttributeLinkedSetIndirect) {
|
||||
continue;
|
||||
}
|
||||
if ($oRemoteAttDef->GetLinkedClass() != $this->GetLinkedClass())
|
||||
{
|
||||
if ($oRemoteAttDef->GetLinkedClass() != $this->GetLinkedClass()) {
|
||||
continue;
|
||||
}
|
||||
if ($oRemoteAttDef->GetExtKeyToMe() != $this->GetExtKeyToRemote())
|
||||
{
|
||||
if ($oRemoteAttDef->GetExtKeyToMe() != $this->GetExtKeyToRemote()) {
|
||||
continue;
|
||||
}
|
||||
if ($oRemoteAttDef->GetExtKeyToRemote() != $this->GetExtKeyToMe())
|
||||
{
|
||||
if ($oRemoteAttDef->GetExtKeyToRemote() != $this->GetExtKeyToMe()) {
|
||||
continue;
|
||||
}
|
||||
$oRet = $oRemoteAttDef;
|
||||
|
||||
@@ -1822,13 +1822,13 @@ abstract class DBObject implements iDisplay
|
||||
/**
|
||||
* Check if the given (or current) value is suitable for the attribute
|
||||
*
|
||||
* @api
|
||||
* @api-advanced
|
||||
*
|
||||
* @param string $sAttCode
|
||||
* @param boolean|string $value true if successful, the error description otherwise
|
||||
* @api
|
||||
* @api-advanced
|
||||
*
|
||||
* @return bool|string
|
||||
* @param string $sAttCode
|
||||
* @param mixed $value if not passed, then will get value using Get method
|
||||
*
|
||||
* @return bool|string true if successful, the error description otherwise
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
@@ -2108,23 +2108,75 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
|
||||
$aChildClassesWithRuleDisabled = MetaModel::GetChildClassesWithDisabledUniquenessRule($sRuleRootClass, $sUniquenessRuleId);
|
||||
if (!empty($aChildClassesWithRuleDisabled))
|
||||
{
|
||||
if (!empty($aChildClassesWithRuleDisabled)) {
|
||||
$oUniquenessQuery->AddConditionForInOperatorUsingParam('finalclass', $aChildClassesWithRuleDisabled, false);
|
||||
}
|
||||
|
||||
return $oUniquenessQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAttCode
|
||||
* @param mixed $value
|
||||
*
|
||||
* @uses m_aCheckWarnings to log to user duplicates found
|
||||
*
|
||||
* @since 2.8.0 N°3198 check duplicates if necessary :<br>
|
||||
* Before we could only add or remove lnk using the uilinks widget. This widget has a filter based on existing values, and so
|
||||
* forbids to add duplicates.<br>
|
||||
* Now we can modify existing entries using the extkey widget, and the widget doesn't have (yet !) such
|
||||
* a filter. The widget will be updated later on, but as a first step we're checking for duplicates server side. This is a non
|
||||
* blocking warning, as it was already possible to add duplicates by other means.
|
||||
*/
|
||||
protected function DoCheckLinkedSetDuplicates($sAttCode, $value)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
|
||||
if (!($oAttDef instanceof AttributeLinkedSetIndirect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($oAttDef->DuplicatesAllowed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var \ormLinkSet $value */
|
||||
$aModifiedLnk = $value->ListModifiedLinks();
|
||||
$sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
|
||||
$aExistingRemotesId = $value->GetColumnAsArray($sExtKeyToRemote, true);
|
||||
$aExistingRemotesFriendlyName = $value->GetColumnAsArray($sExtKeyToRemote.'_friendlyname', true);
|
||||
$aDuplicatesFields = [];
|
||||
foreach ($aModifiedLnk as $oModifiedLnk) {
|
||||
$iModifiedLnkId = $oModifiedLnk->GetKey();
|
||||
$iModifiedLnkRemoteId = $oModifiedLnk->Get($sExtKeyToRemote);
|
||||
$aExistingRemotesIdToCheck = array_filter($aExistingRemotesId, function ($iLnkKey) use ($iModifiedLnkId) {
|
||||
return ($iLnkKey != $iModifiedLnkId);
|
||||
}, ARRAY_FILTER_USE_KEY);
|
||||
|
||||
if (!in_array($iModifiedLnkRemoteId, $aExistingRemotesIdToCheck, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$iLnkId = $oModifiedLnk->GetKey();
|
||||
$aDuplicatesFields[] = $aExistingRemotesFriendlyName[$iLnkId];
|
||||
}
|
||||
|
||||
if (!empty($aDuplicatesFields)) {
|
||||
$this->m_aCheckWarnings[] = Dict::Format('Core:AttributeLinkedSetDuplicatesFound',
|
||||
$oAttDef->GetLabel(),
|
||||
implode(', ', $aDuplicatesFields));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check integrity rules (before inserting or updating the object)
|
||||
*
|
||||
* **This method is not meant to be called directly, use DBObject::CheckToWrite()!**
|
||||
* **This method is not meant to be called directly, use DBObject::CheckToWrite()!**
|
||||
* Errors should be inserted in $m_aCheckIssues and $m_aCheckWarnings arrays
|
||||
*
|
||||
* @overwritable-hook You can extend this method in order to provide your own logic.
|
||||
* @see CheckToWrite()
|
||||
* @see $m_aCheckIssues
|
||||
*
|
||||
* @overwritable-hook You can extend this method in order to provide your own logic.
|
||||
* @see CheckToWrite()
|
||||
* @see $m_aCheckIssues
|
||||
* @see $m_aCheckWarnings
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
@@ -2140,14 +2192,14 @@ abstract class DBObject implements iDisplay
|
||||
|
||||
$aChanges = $this->ListChanges();
|
||||
|
||||
foreach($aChanges as $sAttCode => $value)
|
||||
{
|
||||
foreach($aChanges as $sAttCode => $value) {
|
||||
$res = $this->CheckValue($sAttCode);
|
||||
if ($res !== true)
|
||||
{
|
||||
if ($res !== true) {
|
||||
// $res contains the error description
|
||||
$this->m_aCheckIssues[] = "Unexpected value for attribute '$sAttCode': $res";
|
||||
}
|
||||
|
||||
$this->DoCheckLinkedSetDuplicates($sAttCode, $value);
|
||||
}
|
||||
if (count($this->m_aCheckIssues) > 0)
|
||||
{
|
||||
|
||||
@@ -33,6 +33,8 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Core:AttributeLinkedSet' => 'Array of objects',
|
||||
'Core:AttributeLinkedSet+' => 'Any kind of objects of the same class or subclass',
|
||||
|
||||
'Core:AttributeLinkedSetDuplicatesFound' => 'Duplicates in the \'%1$s\' field : %2$s',
|
||||
|
||||
'Core:AttributeDashboard' => 'Dashboard',
|
||||
'Core:AttributeDashboard+' => '',
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Core:AttributeLinkedSet' => 'Objets liés (1-n)',
|
||||
'Core:AttributeLinkedSet+' => 'Liste d\'objets d\'une classe donnée et pointant sur l\'objet courant',
|
||||
|
||||
'Core:AttributeLinkedSetDuplicatesFound' => 'Des doublons sont présents dans le champ \'%1$s\' : %2$s',
|
||||
|
||||
'Core:AttributeDashboard' => 'Tableau de bord',
|
||||
'Core:AttributeDashboard+' => '',
|
||||
|
||||
|
||||
Reference in New Issue
Block a user