N°659 Add uniqueness checks

* modify compiler to save the new rules
* add check on object save (\DBObject::DoCheckUniqueness)
* default model : add uniqueness rules on Brand, Model, Person
This commit is contained in:
Pierre Goiffon
2018-10-19 14:31:55 +02:00
parent cd5e1afb2b
commit 574d72b0e7
34 changed files with 670 additions and 29 deletions

View File

@@ -124,6 +124,24 @@ EOF
$oObj->DisplayDetails($oPage, false);
}
/**
* @param $sMessageId
* @param $sMessage
* @param $sSeverity
* @param $fRank
* @param bool $bMustNotExist
*
* @see SetSessionMessage()
* @since 2.6
*/
protected function SetSessionMessageFromInstance($sMessageId, $sMessage, $sSeverity, $fRank, $bMustNotExist = false)
{
$sObjectClass = get_class($this);
$iObjectId = $this->GetKey();
self::SetSessionMessage($sObjectClass, $iObjectId, $sMessageId, $sMessage, $sSeverity, $fRank);
}
/**
* Set a message diplayed to the end-user next time this object will be displayed
* Messages are uniquely identified so that plugins can override standard messages (the final work is given to the
@@ -138,6 +156,7 @@ EOF
* @param float $fRank Ordering of the message: smallest displayed first (can be negative)
* @param bool $bMustNotExist Do not alter any existing message (considering the id)
*
* @see SetSessionMessageFromInstance() to call from within an instance
*/
public static function SetSessionMessage(
$sClass, $iKey, $sMessageId, $sMessage, $sSeverity, $fRank, $bMustNotExist = false
@@ -3693,6 +3712,8 @@ EOF
{
$res = parent::DBInsertNoReload();
$this->SetWarningsAsSessionMessages('create');
// Invoke extensions after insertion (the object must exist, have an id, etc.)
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
@@ -3727,6 +3748,8 @@ EOF
{
$res = parent::DBUpdate();
$this->SetWarningsAsSessionMessages('update');
// Protection against reentrance (e.g. cascading the update of ticket logs)
// Note: This is based on the fix made on r 3190 in DBObject::DBUpdate()
static $aUpdateReentrance = array();
@@ -3755,6 +3778,25 @@ EOF
return $res;
}
/**
* @param string $sMessageIdPrefix
*
* @since 2.6
*/
protected function SetWarningsAsSessionMessages($sMessageIdPrefix)
{
if (!empty($this->m_aCheckWarnings) && is_array($this->m_aCheckWarnings))
{
$iMsgNb = 0;
foreach ($this->m_aCheckWarnings as $sWarningMessage)
{
$iMsgNb++;
$sMessageId = "$sMessageIdPrefix-$iMsgNb"; // each message must have its own messageId !
$this->SetSessionMessageFromInstance($sMessageId, $sWarningMessage, 'info', 0);
}
}
}
protected static function BulkUpdateTracked_Internal(DBSearch $oFilter, array $aValues)
{
// Todo - invoke the extension

View File

@@ -83,10 +83,28 @@ abstract class DBObject implements iDisplay
private $m_bDirty = false; // Means: "a modification is ongoing"
// The object may have incorrect external keys, then any attempt of reload must be avoided
private $m_bCheckStatus = null; // Means: the object has been verified and is consistent with integrity rules
// if null, then the check has to be performed again to know the status
/**
* @var boolean|null true if the object has been verified and is consistent with integrity rules
* if null, then the check has to be performed again to know the status
* @see CheckToWrite()
*/
private $m_bCheckStatus = null;
/**
* @var null|boolean true if cannot be saved because of security reason
* @see CheckToWrite()
*/
protected $m_bSecurityIssue = null;
/**
* @var null|string[] list of issues preventing object save
* @see CheckToWrite()
*/
protected $m_aCheckIssues = null;
/**
* @var null|string[] list of warnings throws during object save
* @see CheckToWrite()
* @since 2.6 N°659 uniqueness constraints
*/
protected $m_aCheckWarnings = null;
protected $m_aDeleteIssues = null;
private $m_bFullyLoaded = false; // Compound objects can be partially loaded
@@ -1364,13 +1382,115 @@ abstract class DBObject implements iDisplay
{
return true;
}
// check integrity rules (before inserting or updating the object)
// a displayable error is returned
/**
* @throws \CoreException
* @throws \OQLException
* @since 2.6 N°659 uniqueness constraint
*/
protected function DoCheckUniqueness()
{
$sCurrentClass = get_class($this);
$aUniquenessRules = MetaModel::GetUniquenessRules($sCurrentClass);
foreach ($aUniquenessRules as $sUniquenessRuleName => $aUniquenessRuleProperties)
{
if ($aUniquenessRuleProperties['disabled'] === true)
{
continue;
}
$oUniquenessQuery = $this->GetUniquenessDuplicatesQuery($aUniquenessRuleProperties);
$oUniquenessDuplicates = new DBObjectSet($oUniquenessQuery);
$bHasDuplicates = $oUniquenessDuplicates->CountExceeds(0);
if ($bHasDuplicates)
{
$bIsBlockingRule = $aUniquenessRuleProperties['is_blocking'];
if (is_null($bIsBlockingRule))
{
$bIsBlockingRule = true;
}
$sErrorKey = $aUniquenessRuleProperties['error_message'];
$sErrorMessage = $this->GetUniquenessRuleMessage($sErrorKey, $sUniquenessRuleName);
if ($bIsBlockingRule)
{
$this->m_aCheckIssues[] = $sErrorMessage;
continue;
}
$this->m_aCheckWarnings[] = $sErrorMessage;
continue;
}
}
}
/**
* @param string $sMessageKey string or dictionnary key, could be empty
* @param string $sUniquenessRuleName
*
* @return string
* @since 2.6 N°659 uniqueness constraint
*/
protected function GetUniquenessRuleMessage($sMessageKey, $sUniquenessRuleName)
{
if (empty($sMessageKey))
{
return Dict::Format('Core:UniquenessDefaultError', $sUniquenessRuleName);
}
$sTemplate = Dict::S($sMessageKey);
$oString = new TemplateString($sTemplate);
return $oString->Render(array('this' => $this));
}
/**
* @param array $aUniquenessSingleRule
*
* @return \DBSearch
* @throws \CoreException
* @throws \OQLException
* @since 2.6 N°659 uniqueness constraint
*/
protected function GetUniquenessDuplicatesQuery($aUniquenessSingleRule)
{
$sCurrentClass = get_class($this);
$sOqlUniquenessQuery = "SELECT $sCurrentClass";
if (!(empty($sUniquenessFilter = $aUniquenessSingleRule['filter'])))
{
$sOqlUniquenessQuery .= ' WHERE '.$sUniquenessFilter;
}
$oUniquenessQuery = DBObjectSearch::FromOQL($sOqlUniquenessQuery);
if (!$this->IsNew())
{
$oUniquenessQuery->AddCondition('id', $this->GetKey(), '<>');
}
foreach ($aUniquenessSingleRule['attributes'] as $sAttributeCode)
{
$attributeValue = $this->Get($sAttributeCode);
$oUniquenessQuery->AddCondition($sAttributeCode, $attributeValue, '=');
}
return $oUniquenessQuery;
}
/**
* check integrity rules (before inserting or updating the object)
* a displayable error is returned
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \OQLException
*/
public function DoCheckToWrite()
{
$this->DoComputeValues();
$this->DoCheckUniqueness();
$aChanges = $this->ListChanges();
foreach($aChanges as $sAttCode => $value)
@@ -1417,6 +1537,18 @@ abstract class DBObject implements iDisplay
}
}
/**
* @return array containing :
* <ul>
* <li>{@link $m_bCheckStatus}
* <li>{@link $m_aCheckIssues}
* <li>{@link $m_bSecurityIssue}
* </ul>
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \OQLException
*/
final public function CheckToWrite()
{
if (MetaModel::SkipCheckToWrite())

View File

@@ -526,6 +526,74 @@ abstract class MetaModel
return $oRet;
}
/**
* @param string $sClass
*
* @return array
* @throws \CoreException
*
* @since 2.6 N°659 uniqueness constraint
*/
final static public function GetUniquenessRules($sClass)
{
self::_check_subclass($sClass);
$aCurrentUniquenessRules = array();
if (array_key_exists('uniqueness_rules', self::$m_aClassParams[$sClass]))
{
$aCurrentUniquenessRules = self::$m_aClassParams[$sClass]['uniqueness_rules'];
}
$sParentClass = self::GetParentClass($sClass);
if ($sParentClass)
{
$aParentUniquenessRules = self::GetUniquenessRules($sParentClass);
foreach ($aParentUniquenessRules as $sUniquenessRuleId => $aParentUniquenessRuleProperties)
{
$bCopyDisabledKey = true;
$bCurrentDisabledValue = null;
if (array_key_exists($sUniquenessRuleId, $aCurrentUniquenessRules))
{
if (self::IsUniquenessRuleContainingOnlyDisabledKey($aCurrentUniquenessRules[$sUniquenessRuleId]))
{
$bCopyDisabledKey = false;
}
else
{
continue;
}
}
$aMergedUniquenessProperties = $aParentUniquenessRuleProperties;
if (!$bCopyDisabledKey)
{
$aMergedUniquenessProperties['disabled'] = $aCurrentUniquenessRules[$sUniquenessRuleId]['disabled'];
}
$aCurrentUniquenessRules[$sUniquenessRuleId] = $aMergedUniquenessProperties;
}
}
return $aCurrentUniquenessRules;
}
/**
* @param array $aRuleProperties
*
* @return bool
* @since 2.6 N°659 uniqueness constraint
*/
private static function IsUniquenessRuleContainingOnlyDisabledKey($aRuleProperties)
{
$aNonNullRuleProperties = array_filter($aRuleProperties, function ($v) {
return (!is_null($v));
});
return ((count($aNonNullRuleProperties) == 1) && (array_key_exists('disabled', $aNonNullRuleProperties)));
}
/**
* @param string $sClass
*
@@ -2680,6 +2748,25 @@ abstract class MetaModel
$oClassInit->OnAfterClassInitialization($sPHPClass);
}
}
$aCurrentClassUniquenessRules = MetaModel::GetUniquenessRules($sPHPClass);
if (!empty($aCurrentClassUniquenessRules))
{
$aClassFields = self::GetAttributesList($sPHPClass);
foreach ($aCurrentClassUniquenessRules as $sUniquenessRuleId => $aUniquenessRuleProperties)
{
$bHasSameRuleInParent = self::HasSameUniquenessRuleInParent($sPHPClass, $sUniquenessRuleId);
try
{
self::CheckUniquenessRuleValidity($aUniquenessRuleProperties, $bHasSameRuleInParent, $aClassFields);
}
catch (CoreUnexpectedValue $e)
{
throw new Exception("Invalid uniqueness rule declaration : class={$sPHPClass}, rule=$sUniquenessRuleId, reason={$e->getMessage()}");
}
}
}
}
catch (ReflectionException $e)
{
@@ -2948,6 +3035,110 @@ abstract class MetaModel
}
}
/**
* @param string $sClassName
* @param string $sUniquenessRuleId
*
* @return bool true if one of the parent class (recursive) has the same rule defined
* @throws \CoreException
*/
private static function HasSameUniquenessRuleInParent($sClassName, $sUniquenessRuleId)
{
$sParentClass = self::GetParentClass($sClassName);
if (empty($sParentClass))
{
return false;
}
$aParentClassUniquenessRules = self::GetUniquenessRules($sParentClass);
if (array_key_exists($sUniquenessRuleId, $aParentClassUniquenessRules))
{
return true;
}
return self::HasSameUniquenessRuleInParent($sParentClass, $sUniquenessRuleId);
}
/**
* @param array $aUniquenessRuleProperties
* @param bool $bRuleOverride if false then control an original declaration validity,
* otherwise an override validity (can have only the disabled key)
* @param string[] $aExistingClassFields if non empty, will check that all fields declared in the rules exists in the class
*
* @throws \CoreUnexpectedValue if the rule is invalid
*
* @since 2.6 N°659 uniqueness constraint
*/
public static function CheckUniquenessRuleValidity($aUniquenessRuleProperties, $bRuleOverride = true, $aExistingClassFields = array())
{
$MANDATORY_ATTRIBUTES = array('attributes');
$UNIQUENESS_MANDATORY_KEYS_NB = count($MANDATORY_ATTRIBUTES);
$bHasDisabledKey = false;
$bHasMissingMandatoryKey = false;
$iMissingMandatoryKeysNb = 0;
$bHasAllMandatoryKeysMissing = false;
$bHasNonDisabledKeys = false;
foreach ($aUniquenessRuleProperties as $sUniquenessRuleKey => $aUniquenessRuleProperty)
{
if (($sUniquenessRuleKey === 'disabled') && (!is_null($aUniquenessRuleProperty)))
{
$bHasDisabledKey = true;
continue;
}
if (($sUniquenessRuleKey === 'attributes') && (!empty($aExistingClassFields)))
{
foreach ($aUniquenessRuleProperties[$sUniquenessRuleKey] as $sRuleAttribute)
{
if (!in_array($sRuleAttribute, $aExistingClassFields, true))
{
throw new CoreUnexpectedValue("Uniqueness rule : non existing field '$sRuleAttribute'");
}
}
}
if (!$aUniquenessRuleProperty)
{
if (!in_array($sUniquenessRuleKey, $MANDATORY_ATTRIBUTES, true))
{
continue;
}
$bHasMissingMandatoryKey = true;
$iMissingMandatoryKeysNb++;
continue;
}
$bHasNonDisabledKeys = true;
}
if ($iMissingMandatoryKeysNb == $UNIQUENESS_MANDATORY_KEYS_NB)
{
$bHasAllMandatoryKeysMissing = true;
}
if ($bHasDisabledKey)
{
if ($bRuleOverride && $bHasAllMandatoryKeysMissing && !$bHasNonDisabledKeys)
{
return;
}
if ($bHasMissingMandatoryKey)
{
throw new CoreUnexpectedValue('Uniqueness rule : missing mandatory properties');
}
return;
}
if ($bHasMissingMandatoryKey)
{
throw new CoreUnexpectedValue('Uniqueness rule : missing mandatory properties');
}
}
/**
* To be overriden, must be called for any object class (optimization)
*/
@@ -4503,7 +4694,7 @@ abstract class MetaModel
}
}
// Check unicity of the SQL columns
// Check SQL columns uniqueness
//
if (self::HasTable($sClass))
{

View File

@@ -56,18 +56,20 @@ class TemplateString
{
protected $m_sRaw;
protected $m_aPlaceholders;
public function __construct($sRaw)
{
$this->m_sRaw = $sRaw;
$this->m_aPlaceholders = null;
}
/**
* Split the string into placholders
* @param Hash $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
* @return void
*/
* Split the string into placholders
*
* @param array $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
*
* @throws \Exception
*/
protected function Analyze($aParamTypes = array())
{
if (!is_null($this->m_aPlaceholders)) return;
@@ -100,9 +102,10 @@ class TemplateString
}
/**
* Return the placeholders (for reporting purposes)
* @return void
*/
* Return the placeholders (for reporting purposes)
*
* @return array
*/
public function GetPlaceholders()
{
return $this->m_aPlaceholders;
@@ -110,9 +113,11 @@ class TemplateString
/**
* Check the format when possible
* @param Hash $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
* @return void
*/
*
* @param array $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
*
* @return boolean
*/
public function IsValid($aParamTypes = array())
{
$this->Analyze($aParamTypes);
@@ -135,10 +140,12 @@ class TemplateString
}
/**
* Apply the given parameters to replace the placeholders
* @param Hash $aParamValues Value of the expected parameters: hash array of '<param_id>' => '<value>'
* @return void
*/
* Apply the given parameters to replace the placeholders
*
* @param array $aParamValues Value of the expected parameters: hash array of '<param_id>' => '<value>'
*
* @return string
*/
public function Render($aParamValues = array())
{
$aParamTypes = array();
@@ -174,5 +181,4 @@ class TemplateString
}
return str_replace($aSearch, $aReplace, $this->m_sRaw);
}
}
?>
}

View File

@@ -203,6 +203,10 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'Class:Person/Attribute:tickets_list+' => 'Všechny tikety, které tato osoba zadala',
'Class:Person/Attribute:manager_id_friendlyname' => 'Popisný název vedoucího',
'Class:Person/Attribute:manager_id_friendlyname+' => '',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization~~',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number~~',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization~~',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name~~',
));
//
@@ -1293,6 +1297,8 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'Class:Brand+' => '',
'Class:Brand/Attribute:physicaldevices_list' => 'Fyzická zařízení',
'Class:Brand/Attribute:physicaldevices_list+' => 'Všechna fyzická zařízení odpovídající této značce',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique~~',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists~~',
));
//
@@ -1346,6 +1352,8 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'Class:Model/Attribute:type/Value:Phone+' => '',
'Class:Model/Attribute:physicaldevices_list' => 'Fyzická zařízení',
'Class:Model/Attribute:physicaldevices_list+' => 'Všechna fyzická zařízení odpovídající tomuto modelu',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand~~',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand~~',
));
//

View File

@@ -88,6 +88,10 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Class:Person/Attribute:team_list+' => '',
'Class:Person/Attribute:tickets_list' => 'List Tickets',
'Class:Person/Attribute:tickets_list+' => '',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization~~',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number~~',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization~~',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name~~',
'Class:Team' => 'Team',
'Class:Team+' => '',
'Class:Team/Attribute:persons_list' => 'List Medlemmer',
@@ -256,6 +260,8 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Class:Brand+' => '',
'Class:Brand/Attribute:physicaldevices_list' => 'Fysisk enhed',
'Class:Brand/Attribute:physicaldevices_list+' => '',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique~~',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists~~',
'Class:Model' => 'Model',
'Class:Model+' => '',
'Class:Model/Attribute:brand_id' => 'Mærke',
@@ -300,6 +306,8 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Class:Model/Attribute:type/Value:Telephone+' => '',
'Class:Model/Attribute:physicaldevices_list' => 'Fyisk enhed',
'Class:Model/Attribute:physicaldevices_list+' => '',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand~~',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand~~',
'Class:NetworkDeviceType' => 'Netværksenhed type',
'Class:NetworkDeviceType+' => '',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list' => 'Netværks enheder',

View File

@@ -499,6 +499,31 @@
<attribute id="employee_number"/>
</attributes>
</reconciliation>
<uniqueness_rules>
<rule id="employee_number">
<attributes>
<attribute id="org_id"/>
<attribute id="employee_number"/>
</attributes>
<filter><![CDATA[employee_number != '']]></filter>
<disabled>false</disabled>
<is_blocking>true</is_blocking>
<description>Class:Person/UniquenessRule:employee_number/Description</description>
<error_message>Class:Person/UniquenessRule:employee_number/Error</error_message>
</rule>
<rule id="name">
<attributes>
<attribute id="org_id"/>
<attribute id="name"/>
<attribute id="first_name"/>
</attributes>
<filter/>
<disabled>false</disabled>
<is_blocking>false</is_blocking>
<description>Class:Person/UniquenessRule:name/Description</description>
<error_message>Class:Person/UniquenessRule:name/Error</error_message>
</rule>
</uniqueness_rules>
</properties>
<fields>
<field id="picture" xsi:type="AttributeImage">
@@ -5792,6 +5817,16 @@
<attribute id="name"/>
</attributes>
</reconciliation>
<uniqueness_rules>
<rule id="name">
<attributes>
<attribute id="name"/>
</attributes>
<is_blocking>true</is_blocking>
<description>Class:Brand/UniquenessRule:name/Description</description>
<error_message>Class:Brand/UniquenessRule:name/Error</error_message>
</rule>
</uniqueness_rules>
</properties>
<fields>
<field id="physicaldevices_list" xsi:type="AttributeLinkedSet">
@@ -5855,6 +5890,17 @@
<attribute id="type"/>
</attributes>
</reconciliation>
<uniqueness_rules>
<rule id="name_brand">
<attributes>
<attribute id="name"/>
<attribute id="brand_id"/>
</attributes>
<is_blocking>true</is_blocking>
<description>Class:Model/UniquenessRule:name_brand/Description</description>
<error_message>Class:Model/UniquenessRule:name_brand/Error</error_message>
</rule>
</uniqueness_rules>
</properties>
<fields>
<field id="brand_id" xsi:type="AttributeExternalKey">

View File

@@ -79,6 +79,10 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:Person/Attribute:team_list+' => '',
'Class:Person/Attribute:tickets_list' => 'Tickets',
'Class:Person/Attribute:tickets_list+' => '',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization~~',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number~~',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization~~',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name~~',
'Class:Team' => 'Team',
'Class:Team+' => '',
'Class:Team/Attribute:persons_list' => 'Mitglieder',
@@ -249,6 +253,8 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:Brand+' => '',
'Class:Brand/Attribute:physicaldevices_list' => 'Physische Geräte',
'Class:Brand/Attribute:physicaldevices_list+' => '',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique~~',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists~~',
'Class:Model' => 'Modell',
'Class:Model+' => '',
'Class:Model/Attribute:brand_id' => 'Marke',
@@ -293,6 +299,8 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:Model/Attribute:type/Value:Phone+' => '',
'Class:Model/Attribute:physicaldevices_list' => 'Phyische Geräte',
'Class:Model/Attribute:physicaldevices_list+' => '',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand~~',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand~~',
'Class:NetworkDeviceType' => 'Netzwerkgerätetyp',
'Class:NetworkDeviceType+' => '',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list' => 'Netzwerkgeräte',

View File

@@ -206,6 +206,10 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:Person/Attribute:manager_id_friendlyname+' => '',
'Class:Person/Attribute:picture' => 'Picture',
'Class:Person/Attribute:picture+' => '',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name',
));
//
@@ -1297,6 +1301,8 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:Brand+' => '',
'Class:Brand/Attribute:physicaldevices_list' => 'Physical devices',
'Class:Brand/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this brand',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists',
));
//
@@ -1350,6 +1356,8 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:Model/Attribute:type/Value:Phone+' => 'Telephone',
'Class:Model/Attribute:physicaldevices_list' => 'Physical devices',
'Class:Model/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this model',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand',
));
//

View File

@@ -207,6 +207,10 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Class:Person/Attribute:manager_id_friendlyname+' => 'Nombre del Jefe',
'Class:Person/Attribute:picture' => 'Fotografía',
'Class:Person/Attribute:picture+' => 'Fotografía',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization~~',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number~~',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization~~',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name~~',
));
//
@@ -1287,6 +1291,8 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Class:Brand+' => 'Marca',
'Class:Brand/Attribute:physicaldevices_list' => 'Dispositivo Físico',
'Class:Brand/Attribute:physicaldevices_list+' => 'Dispositivo Físico',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique~~',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists~~',
));
//
@@ -1340,6 +1346,8 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Class:Model/Attribute:type/Value:Phone+' => 'Teléfono',
'Class:Model/Attribute:physicaldevices_list' => 'Dispositivo Físico',
'Class:Model/Attribute:physicaldevices_list+' => 'Dispositivo Físico',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand~~',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand~~',
));
//

View File

@@ -148,6 +148,11 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:Person/Attribute:manager_id_friendlyname+' => '',
'Class:Person/Attribute:picture' => 'Photo',
'Class:Person/Attribute:picture+' => '',
'Class:Person/UniquenessRule:employee_number/Description' => 'Le numéro d\'employé doit être unique dans l\'organisation',
'Class:Person/UniquenessRule:employee_number/Error' => 'il y a déjà une personne avec ce numéro d\'employé dans l\'organisation
\'$this->org_name$\'',
'Class:Person/UniquenessRule:name/Description' => 'Le nom de l\'employé devrait être unique dans l\'organisation',
'Class:Person/UniquenessRule:name/Error' => 'Il y a déjà une personne avec ce nom dans l\'organisation \'$this->org_name$\'',
));
//
@@ -1238,6 +1243,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:Brand+' => '',
'Class:Brand/Attribute:physicaldevices_list' => 'Matériels',
'Class:Brand/Attribute:physicaldevices_list+' => '',
'Class:Brand/UniquenessRule:name/Description' => 'Le nom doit être unique',
'Class:Brand/UniquenessRule:name/Error' => 'cette marque existe déjà',
));
//
@@ -1289,6 +1296,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:Model/Attribute:type/Value:Phone+' => 'Téléphone',
'Class:Model/Attribute:physicaldevices_list' => 'Matériels',
'Class:Model/Attribute:physicaldevices_list+' => '',
'Class:Model/UniquenessRule:name_brand/Description' => 'Le nom doit être unique dans une marque',
'Class:Model/UniquenessRule:name_brand/Error' => 'ce modèle existe déjà dans cette marque',
));
//

View File

@@ -743,6 +743,10 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:Person/Attribute:tickets_list' => 'Tickets~~',
'Class:Person/Attribute:tickets_list+' => 'All the tickets this person is the caller~~',
'Class:Person/Attribute:manager_id_friendlyname' => 'Manager friendly name~~',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization~~',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number~~',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization~~',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name~~',
'Class:Team/Attribute:persons_list' => 'Members~~',
'Class:Team/Attribute:persons_list+' => 'All the people belonging to this team~~',
'Class:Team/Attribute:tickets_list' => 'Tickets~~',
@@ -1106,6 +1110,8 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:Brand' => 'Brand~~',
'Class:Brand/Attribute:physicaldevices_list' => 'Physical devices~~',
'Class:Brand/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this brand~~',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique~~',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists~~',
'Class:Model' => 'Model~~',
'Class:Model/Attribute:brand_id' => 'Brand~~',
'Class:Model/Attribute:brand_name' => 'Brand name~~',
@@ -1148,6 +1154,8 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:Model/Attribute:type/Value:Phone+' => 'Telephone~~',
'Class:Model/Attribute:physicaldevices_list' => 'Physical devices~~',
'Class:Model/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this model~~',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand~~',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand~~',
'Class:NetworkDeviceType' => 'Network Device Type~~',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list' => 'Network devices~~',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list+' => 'All the network devices corresponding to this type~~',

View File

@@ -743,6 +743,10 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:Person/Attribute:tickets_list' => 'Tickets~~',
'Class:Person/Attribute:tickets_list+' => 'All the tickets this person is the caller~~',
'Class:Person/Attribute:manager_id_friendlyname' => 'Manager friendly name~~',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization~~',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number~~',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization~~',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name~~',
'Class:Team/Attribute:persons_list' => 'Members~~',
'Class:Team/Attribute:persons_list+' => 'All the people belonging to this team~~',
'Class:Team/Attribute:tickets_list' => 'Tickets~~',
@@ -1106,6 +1110,8 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:Brand' => 'Brand~~',
'Class:Brand/Attribute:physicaldevices_list' => 'Physical devices~~',
'Class:Brand/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this brand~~',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique~~',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists~~',
'Class:Model' => 'Model~~',
'Class:Model/Attribute:brand_id' => 'Brand~~',
'Class:Model/Attribute:brand_name' => 'Brand name~~',
@@ -1148,6 +1154,8 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:Model/Attribute:type/Value:Phone+' => 'Telephone~~',
'Class:Model/Attribute:physicaldevices_list' => 'Physical devices~~',
'Class:Model/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this model~~',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand~~',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand~~',
'Class:NetworkDeviceType' => 'Network Device Type~~',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list' => 'Network devices~~',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list+' => 'All the network devices corresponding to this type~~',

View File

@@ -86,6 +86,10 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
'Class:Person/Attribute:team_list+' => '',
'Class:Person/Attribute:tickets_list' => 'チケット',
'Class:Person/Attribute:tickets_list+' => '',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization~~',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number~~',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization~~',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name~~',
'Class:Team' => 'チーム',
'Class:Team+' => '',
'Class:Team/Attribute:persons_list' => 'メンバー',
@@ -254,6 +258,8 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
'Class:Brand+' => '',
'Class:Brand/Attribute:physicaldevices_list' => '物理デバイス',
'Class:Brand/Attribute:physicaldevices_list+' => '',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique~~',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists~~',
'Class:Model' => 'モデル',
'Class:Model+' => '',
'Class:Model/Attribute:brand_id' => 'ブランド',
@@ -298,6 +304,8 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
'Class:Model/Attribute:type/Value:Phone+' => '電話',
'Class:Model/Attribute:physicaldevices_list' => '物理デバイス',
'Class:Model/Attribute:physicaldevices_list+' => '',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand~~',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand~~',
'Class:NetworkDeviceType' => 'ネットワークデバイスタイプ',
'Class:NetworkDeviceType+' => '',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list' => 'ネットワークデバイス',

View File

@@ -207,6 +207,10 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'Class:Person/Attribute:tickets_list+' => 'Alle tickets waarvan deze persoon de aanvrager is',
'Class:Person/Attribute:manager_id_friendlyname' => 'Volledige naam van de manager',
'Class:Person/Attribute:manager_id_friendlyname+' => '',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization~~',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number~~',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization~~',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name~~',
));
//
@@ -1285,6 +1289,8 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'Class:Brand+' => '',
'Class:Brand/Attribute:physicaldevices_list' => 'Fysieke apparaten',
'Class:Brand/Attribute:physicaldevices_list+' => 'Alle fysieke apparaten die corresponderen met dit merk',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique~~',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists~~',
));
//
@@ -1338,6 +1344,8 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'Class:Model/Attribute:type/Value:Telephone+' => 'Telefoon',
'Class:Model/Attribute:physicaldevices_list' => 'Physical devices',
'Class:Model/Attribute:physicaldevices_list+' => 'Alle fysieke apparaten die corresponderen met dit model',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand~~',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand~~',
));
//

View File

@@ -204,6 +204,10 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:Person/Attribute:tickets_list+' => 'Todos as solicitações que essa pessoa solicitou',
'Class:Person/Attribute:manager_id_friendlyname' => 'Nome amigável gerente',
'Class:Person/Attribute:manager_id_friendlyname+' => '',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization~~',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number~~',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization~~',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name~~',
));
//
@@ -1276,6 +1280,8 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:Brand+' => '',
'Class:Brand/Attribute:physicaldevices_list' => 'Dispositivos físicos',
'Class:Brand/Attribute:physicaldevices_list+' => 'Todos os dispositivos físicos correspondentes a essa fabricante',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique~~',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists~~',
));
//
@@ -1329,6 +1335,8 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:Model/Attribute:type/Value:Phone+' => 'Telefone',
'Class:Model/Attribute:physicaldevices_list' => 'Dispositivo físico',
'Class:Model/Attribute:physicaldevices_list+' => 'Todos os dispositivos físicos correspondentes a esse modelo',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand~~',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand~~',
));
//

View File

@@ -204,6 +204,10 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Person/Attribute:manager_id_friendlyname+' => '',
'Class:Person/Attribute:picture' => 'Фотография',
'Class:Person/Attribute:picture+' => '',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization~~',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number~~',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization~~',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name~~',
));
//
@@ -1295,6 +1299,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Brand+' => '',
'Class:Brand/Attribute:physicaldevices_list' => 'Устройства',
'Class:Brand/Attribute:physicaldevices_list+' => 'Все устройства этого бренда',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique~~',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists~~',
));
//
@@ -1348,6 +1354,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Model/Attribute:type/Value:Telephone+' => 'Телефон',
'Class:Model/Attribute:physicaldevices_list' => 'Устройства',
'Class:Model/Attribute:physicaldevices_list+' => 'Все устройства этой модели',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand~~',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand~~',
));
//

View File

@@ -1094,6 +1094,10 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'Class:Person/Attribute:tickets_list' => 'Tickets~~',
'Class:Person/Attribute:tickets_list+' => 'All the tickets this person is the caller~~',
'Class:Person/Attribute:manager_id_friendlyname' => 'Manager friendly name~~',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization~~',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number~~',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization~~',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name~~',
'Class:Team/Attribute:persons_list' => 'Members~~',
'Class:Team/Attribute:persons_list+' => 'All the people belonging to this team~~',
'Class:Team/Attribute:tickets_list' => 'Tickets~~',
@@ -1457,6 +1461,8 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'Class:Brand' => 'Brand~~',
'Class:Brand/Attribute:physicaldevices_list' => 'Physical devices~~',
'Class:Brand/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this brand~~',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique~~',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists~~',
'Class:Model' => 'Model~~',
'Class:Model/Attribute:brand_id' => 'Brand~~',
'Class:Model/Attribute:brand_name' => 'Brand name~~',
@@ -1499,6 +1505,8 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'Class:Model/Attribute:type/Value:Phone+' => 'Telephone~~',
'Class:Model/Attribute:physicaldevices_list' => 'Physical devices~~',
'Class:Model/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this model~~',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand~~',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand~~',
'Class:NetworkDeviceType' => 'Network Device Type~~',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list' => 'Network devices~~',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list+' => 'All the network devices corresponding to this type~~',

View File

@@ -1096,6 +1096,10 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Person/Attribute:tickets_list' => 'Tickets~~',
'Class:Person/Attribute:tickets_list+' => 'All the tickets this person is the caller~~',
'Class:Person/Attribute:manager_id_friendlyname' => 'Manager friendly name~~',
'Class:Person/UniquenessRule:employee_number/Description' => 'The employee number must be unique in the organization~~',
'Class:Person/UniquenessRule:employee_number/Error' => 'there is already a person in \'$this->org_name$\' organization with the same employee number~~',
'Class:Person/UniquenessRule:name/Description' => 'The employee name should be unique inside its organization~~',
'Class:Person/UniquenessRule:name/Error' => 'There is already a person in \'$this->org_name$\' organization with the same name~~',
'Class:Team/Attribute:persons_list' => 'Members~~',
'Class:Team/Attribute:persons_list+' => 'All the people belonging to this team~~',
'Class:Team/Attribute:tickets_list' => 'Tickets~~',
@@ -1459,6 +1463,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Brand' => 'Brand~~',
'Class:Brand/Attribute:physicaldevices_list' => 'Physical devices~~',
'Class:Brand/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this brand~~',
'Class:Brand/UniquenessRule:name/Description' => 'The name must be unique~~',
'Class:Brand/UniquenessRule:name/Error' => 'This brand already exists~~',
'Class:Model' => 'Model~~',
'Class:Model/Attribute:brand_id' => 'Brand~~',
'Class:Model/Attribute:brand_name' => 'Brand name~~',
@@ -1501,6 +1507,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Model/Attribute:type/Value:Phone+' => 'Telephone~~',
'Class:Model/Attribute:physicaldevices_list' => 'Physical devices~~',
'Class:Model/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this model~~',
'Class:Model/UniquenessRule:name_brand/Description' => 'Name must be unique in the brand~~',
'Class:Model/UniquenessRule:name_brand/Error' => 'this model already exists for this brand~~',
'Class:NetworkDeviceType' => 'Network Device Type~~',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list' => 'Network devices~~',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list+' => 'All the network devices corresponding to this type~~',

View File

@@ -33,6 +33,8 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'Core:UnknownObjectLabel' => 'Objekt nenalezen (třída: %1$s, id: %2$d)',
'Core:UnknownObjectTip' => 'Objekt nemohl být nalezen. Je možné, že byl odstraněn před nějakou dobou a protokol byl mezitím vyčištěn.',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error~~',
'Core:AttributeLinkedSet' => 'Pole objektů',
'Core:AttributeLinkedSet+' => 'Jakékoli objekty stejné třídy, nebo podtřídy',

View File

@@ -650,4 +650,5 @@ Operatoren:<br/>
'Core:Validator:Mandatory' => 'Bitte dieses Feld ausfüllen',
'Core:Validator:MustBeInteger' => 'Muss ein Integer sein',
'Core:Validator:MustSelectOne' => 'Min. ein Eintrag muss ausgewählt sein',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error~~',
));

View File

@@ -31,6 +31,8 @@ Dict::Add('EN US', 'English', 'English', array(
'Core:UnknownObjectLabel' => 'Object not found (class: %1$s, id: %2$d)',
'Core:UnknownObjectTip' => 'The object could not be found. It may have been deleted some time ago and the log has been purged since.',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error',
'Core:AttributeLinkedSet' => 'Array of objects',
'Core:AttributeLinkedSet+' => 'Any kind of objects of the same class or subclass',

View File

@@ -31,6 +31,8 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Core:UnknownObjectLabel' => 'Elemento No Encontrado (Clase: %1$s, Identificador: %2$d)',
'Core:UnknownObjectTip' => 'El Elemento no pudo ser encontrado. Pudo haber sido eliminado hace tiempo y purgado de la Bitácora.',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error~~',
'Core:AttributeLinkedSet' => 'Arreglo de objetos',
'Core:AttributeLinkedSet+' => 'Cualquier tipo de objetos [subclass] de la misma clase',

View File

@@ -27,6 +27,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Core:UnknownObjectLabel' => 'Classe: %1$s, Identifiant: %2$d',
'Core:UnknownObjectTip' => 'L\'objet n\'a pu être trouvé. Il se peut que les archives aient été purgées après son effacement.',
'Core:UniquenessDefaultError' => 'La règle d\'unicité \'%1$s\' renvoie une erreur',
'Class:ActionEmail' => 'Notification par mél',
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Destinataire de test',

View File

@@ -630,4 +630,5 @@ Operators:<br/>
'Core:Validator:Mandatory' => 'Please, fill this field~~',
'Core:Validator:MustBeInteger' => 'Must be an integer~~',
'Core:Validator:MustSelectOne' => 'Please, select one~~',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error~~',
));

View File

@@ -878,4 +878,5 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Core:Validator:Mandatory' => 'Please, fill this field~~',
'Core:Validator:MustBeInteger' => 'Must be an integer~~',
'Core:Validator:MustSelectOne' => 'Please, select one~~',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error~~',
));

View File

@@ -652,4 +652,5 @@ Operators:<br/>
'Core:Validator:Mandatory' => 'Please, fill this field~~',
'Core:Validator:MustBeInteger' => 'Must be an integer~~',
'Core:Validator:MustSelectOne' => 'Please, select one~~',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error~~',
));

View File

@@ -36,6 +36,8 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'Core:UnknownObjectLabel' => 'Object niet gevonden (klasse: %1$s, id: %2$d)',
'Core:UnknownObjectTip' => 'Object kon niet worden gevonden. Het zou eerder verwijderd kunnen zijn en de log zou kunnen zijn opgeschoond.',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error~~',
'Core:AttributeLinkedSet' => 'Reeks van objecten',
'Core:AttributeLinkedSet+' => 'Elke soort objecten van dezelfde klasse of subklasse',

View File

@@ -31,6 +31,8 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Core:UnknownObjectLabel' => 'Objeto não encontrado (classe: %1$s, id: %2$d)',
'Core:UnknownObjectTip' => 'O objeto não pode ser encontrado. Ele pode ter sido eliminado há algum tempo e o log foi removido desde então.',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error~~',
'Core:AttributeLinkedSet' => 'Array de objetos',
'Core:AttributeLinkedSet+' => 'Qualquer tipo de objetos da mesma classe ou subclasses',

View File

@@ -17,6 +17,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Core:UnknownObjectLabel' => 'Объект не найден (class: %1$s, id: %2$d)',
'Core:UnknownObjectTip' => 'Не может быть найден. Возможно он был удален и очищен в лог-е.',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error~~',
'Core:AttributeLinkedSet' => 'Массив объектов',
'Core:AttributeLinkedSet+' => 'Any kind of objects of the same class or subclass',

View File

@@ -802,4 +802,5 @@ Operators:<br/>
'Core:Validator:Mandatory' => 'Please, fill this field~~',
'Core:Validator:MustBeInteger' => 'Must be an integer~~',
'Core:Validator:MustSelectOne' => 'Please, select one~~',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error~~',
));

View File

@@ -801,4 +801,5 @@ Operators:<br/>
'Core:Validator:Mandatory' => 'Please, fill this field~~',
'Core:Validator:MustBeInteger' => 'Must be an integer~~',
'Core:Validator:MustSelectOne' => 'Please, select one~~',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error~~',
));

View File

@@ -797,6 +797,37 @@ EOF
}
}
/**
* @param $oNode
* @param $sTag
* @param bool|null $bDefault
*
* @return bool|null
*/
private function GetPropBooleanConverted($oNode, $sTag, $bDefault = null)
{
$sValue = $this->GetPropBoolean($oNode, $sTag, $bDefault);
if ($sValue == null)
{
return null;
}
if ($sValue == 'true')
{
return true;
}
return false;
}
/**
* @param $oNode
* @param $sTag
* @param bool|null $bDefault
*
* @return null|string
* @see GetPropBooleanConverted() to get boolean value
*/
protected function GetPropBoolean($oNode, $sTag, $bDefault = null)
{
$val = $oNode->GetChildText($sTag);
@@ -936,7 +967,7 @@ EOF
}
/**
* @param \DOMElement $oClass
* @param \MFElement $oClass
* @param string $sTempTargetDir
* @param string $sFinalTargetDir
* @param string $sModuleRelativeDir
@@ -962,8 +993,10 @@ EOF
if ($oNaming = $oProperties->GetOptionalElement('naming'))
{
$oNameAttributes = $oNaming->GetUniqueElement('attributes');
/** @var \DOMNodeList $oAttributes */
$oAttributes = $oNameAttributes->getElementsByTagName('attribute');
$aNameAttCodes = array();
/** @var \MFElement $oAttribute */
foreach($oAttributes as $oAttribute)
{
$aNameAttCodes[] = $oAttribute->getAttribute('id');
@@ -1080,6 +1113,7 @@ EOF
$bEnabled = $this->GetPropBoolean($oArchive, 'enabled', false);
$aClassParams['archive'] = $bEnabled;
}
if ($oObsolescence = $oProperties->GetOptionalElement('obsolescence'))
{
$sCondition = trim($this->GetPropString($oObsolescence, 'condition', ''));
@@ -1089,6 +1123,51 @@ EOF
}
}
if ($oUniquenessRules = $oProperties->GetOptionalElement('uniqueness_rules'))
{
$aUniquenessRules = array();
/** @var \MFElement $oUniquenessSingleRule */
foreach ($oUniquenessRules->GetElementsByTagName('rule') as $oUniquenessSingleRule)
{
$sCurrentRuleId = $oUniquenessSingleRule->getAttribute('id');
$oAttributes = $oUniquenessSingleRule->GetUniqueElement('attributes', false);
if ($oAttributes)
{
$aUniquenessAttributes = array();
foreach ($oAttributes->getElementsByTagName('attribute') as $oAttribute)
{
$aUniquenessAttributes[] = $oAttribute->getAttribute('id');
}
$aUniquenessRules[$sCurrentRuleId]['attributes'] = $aUniquenessAttributes;
}
else
{
$aUniquenessRules[$sCurrentRuleId]['attributes'] = null;
}
$aUniquenessRules[$sCurrentRuleId]['filter'] = $oUniquenessSingleRule->GetChildText('filter');
$aUniquenessRules[$sCurrentRuleId]['disabled'] = $this->GetPropBooleanConverted($oUniquenessSingleRule, 'disabled', null);
$aUniquenessRules[$sCurrentRuleId]['is_blocking'] = $this->GetPropBooleanConverted($oUniquenessSingleRule, 'is_blocking',
null);
$aUniquenessRules[$sCurrentRuleId]['description'] = $oUniquenessSingleRule->GetChildText('description');
$aUniquenessRules[$sCurrentRuleId]['error_message'] = $oUniquenessSingleRule->GetChildText('error_message');
try
{
// we're just checking all mandatory fields are present right now
// we will check for rule overrides validity later (see \MetaModel::InitClasses)
MetaModel::CheckUniquenessRuleValidity($aUniquenessRules[$sCurrentRuleId], true);
}
catch (CoreUnexpectedValue $e)
{
throw(new DOMFormatException("Invalid uniqueness rule declaration : class={$oClass->getAttribute('id')}, rule=$sCurrentRuleId, reason={$e->getMessage()}"));
}
}
$aClassParams['uniqueness_rules'] = var_export($aUniquenessRules, true);
}
// Finalize class params declaration
//
$sClassParams = $this->GetAssociativeArrayAsPhpCode($aClassParams);
@@ -1746,7 +1825,7 @@ EOF
'details' => 'details',
'standard_search' => 'search',
'default_search' => 'default_search',
'list' => 'list'
'list' => 'list',
);
$oPresentation = $oClass->GetUniqueElement('presentation');
@@ -1934,6 +2013,7 @@ EOF;
return 'TagSetFieldDataFor_'.$sTagSuffix;
}
/**
* @param $oMenu
* @param $sTempTargetDir
@@ -2164,7 +2244,7 @@ EOF;
// Hardcode the administrator profile
$aProfiles[1] = array(
'name' => 'Administrator',
'description' => 'Has the rights on everything (bypassing any control)'
'description' => 'Has the rights on everything (bypassing any control)',
);
$aGrants = array();
@@ -2224,7 +2304,7 @@ EOF;
$aProfiles[$iProfile] = array(
'name' => $sName,
'description' => $sDescription
'description' => $sDescription,
);
}

View File

@@ -657,6 +657,18 @@ class iTopDesignFormat
// Remove AttributeTagSet nodes
//
$sPath = "/itop_design/classes/class/fields/field[@xsi:type='AttributeTagSet']";
$this->RemoveNodeFromXPath($sPath);
// Remove uniqueness rules nodes
//
$sPath = "/itop_design/classes/class/properties/uniqueness_rules";
$this->RemoveNodeFromXPath($sPath);
}
private function RemoveNodeFromXPath($sPath)
{
$oXPath = new DOMXPath($this->oDocument);
$oNodeList = $oXPath->query($sPath);
foreach ($oNodeList as $oNode)
{
@@ -666,7 +678,6 @@ class iTopDesignFormat
}
/**
* Delete a node from the DOM and make sure to also remove the immediately following line break (DOMText), if any.
* This prevents generating empty lines in the middle of the XML