diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index a6642306d..503d26e93 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -5977,7 +5977,7 @@ class AttributeTagSet extends AttributeDBFieldVoid $aGoodTags = array(); foreach($aTagCodes as $sTagCode) { - if ($oTagSet->TagsExist($sTagCode)) + if ($oTagSet->IsValidTag($sTagCode)) { $aGoodTags[] = $sTagCode; } diff --git a/core/cmdbobject.class.inc.php b/core/cmdbobject.class.inc.php index 1f3694766..8f2cf1485 100644 --- a/core/cmdbobject.class.inc.php +++ b/core/cmdbobject.class.inc.php @@ -563,6 +563,12 @@ abstract class CMDBObject extends DBObject $this->DBUpdate(); } + /** + * @param null $oDeletionPlan + * + * @return \DeletionPlan|null + * @throws \DeleteException + */ public function DBDelete(&$oDeletionPlan = null) { return $this->DBDeleteTracked_Internal($oDeletionPlan); @@ -575,6 +581,12 @@ abstract class CMDBObject extends DBObject $this->DBDeleteTracked_Internal($oDeletionPlan); } + /** + * @param null $oDeletionPlan + * + * @return \DeletionPlan|null + * @throws \DeleteException + */ protected function DBDeleteTracked_Internal(&$oDeletionPlan = null) { $prevkey = $this->GetKey(); diff --git a/core/ormtagset.class.inc.php b/core/ormtagset.class.inc.php index 6a8af77d7..8bc7c1190 100644 --- a/core/ormtagset.class.inc.php +++ b/core/ormtagset.class.inc.php @@ -4,7 +4,7 @@ * * This file is part of iTop. * - * iTop is free software; you can redistribute it and/or modify + * iTop is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -24,160 +24,147 @@ * Date: 24/08/2018 * Time: 14:35 */ - - final class ormTagSet { - private $sClass; // class of the tag field - private $sAttCode; // attcode of the tag field - private $aOriginalObjects = null; + private $sClass; // class of the tag field + private $sAttCode; // attcode of the tag field + private $aOriginalObjects = null; - /** - * @var bool - */ - private $bHasDelta = false; + /** + * @var bool + */ + private $bHasDelta = false; - /** - * Object from the original set, minus the removed objects - * @var DBObject[] array of iObjectId => DBObject - */ - private $aPreserved = array(); + /** + * Object from the original set, minus the removed objects + * + * @var DBObject[] array of iObjectId => DBObject + */ + private $aPreserved = array(); - /** - * @var DBObject[] New items - */ - private $aAdded = array(); + /** + * @var DBObject[] New items + */ + private $aAdded = array(); - /** - * @var DBObject[] Removed items - */ - private $aRemoved = array(); + /** + * @var DBObject[] Removed items + */ + private $aRemoved = array(); - /** - * __toString magical function overload. - */ - public function __toString() - { - return ''; - } + /** + * __toString magical function overload. + */ + public function __toString() + { + $aValue = $this->GetValue(); + if (!empty($aValue)) + { + return implode(' ', $aValue); + } + else + { + return ' '; + } + } - /** - * ormTagSet constructor. - * - * @param string $sClass - * @param string $sAttCode - * - * @throws \Exception - */ - public function __construct($sClass, $sAttCode) - { - $this->sAttCode = $sAttCode; + /** + * ormTagSet constructor. + * + * @param string $sClass + * @param string $sAttCode + * + * @throws \Exception + */ + public function __construct($sClass, $sAttCode) + { + $this->sAttCode = $sAttCode; - $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); - if (!$oAttDef instanceof AttributeTagSet) - { - throw new Exception("ormTagSet: field {$sClass}:{$sAttCode} is not a tag"); - } - $this->sClass = $sClass; - } + $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); + if (!$oAttDef instanceof AttributeTagSet) + { + throw new Exception("ormTagSet: field {$sClass}:{$sAttCode} is not a tag"); + } + $this->sClass = $sClass; + } - /** - * - * @param array $aTagCodes - * - * @throws \CoreException - * @throws \CoreUnexpectedValue when a code is invalid - */ - public function SetValue($aTagCodes) - { - if (!is_array($aTagCodes)) - { - throw new CoreUnexpectedValue("Wrong value {$aTagCodes} for {$this->sClass}:{$this->sAttCode}"); - } + /** + * + * @param array $aTagCodes + * + * @throws \CoreException + * @throws \CoreUnexpectedValue when a code is invalid + */ + public function SetValue($aTagCodes) + { + if (!is_array($aTagCodes)) + { + throw new CoreUnexpectedValue("Wrong value {$aTagCodes} for {$this->sClass}:{$this->sAttCode}"); + } - $oTags = array(); - foreach($aTagCodes as $sTagCode) - { - $oTag = $this->GetTagFromCode($sTagCode); - $oTags[$oTag->GetKey()] = $oTag; - } + $oTags = array(); + foreach($aTagCodes as $sTagCode) + { + $oTag = $this->GetTagFromCode($sTagCode); + $oTags[$oTag->GetKey()] = $oTag; + } - $this->aPreserved = &$oTags; - $this->aRemoved = array(); - $this->aAdded = array(); - $this->aOriginalObjects = $oTags; - $this->bHasDelta = false; - } + $this->aPreserved = &$oTags; + $this->aRemoved = array(); + $this->aAdded = array(); + $this->aOriginalObjects = $oTags; + $this->bHasDelta = false; + } - /** - * @return array of tag codes - */ - public function GetValue() - { - $aValues = array(); - foreach ($this->aPreserved as $oTag) - { - try - { - $aValues[] = $oTag->Get('tag_code'); - } catch (CoreException $e) - { - IssueLog::Error($e->getMessage()); - } - } - foreach ($this->aAdded as $oTag) - { - try - { - $aValues[] = $oTag->Get('tag_code'); - } catch (CoreException $e) - { - IssueLog::Error($e->getMessage()); - } - } + /** + * @return array of tag codes + */ + public function GetValue() + { + $aValues = array(); + foreach($this->aPreserved as $oTag) + { + try + { + $aValues[] = $oTag->Get('tag_code'); + } catch (CoreException $e) + { + IssueLog::Error($e->getMessage()); + } + } + foreach($this->aAdded as $oTag) + { + try + { + $aValues[] = $oTag->Get('tag_code'); + } catch (CoreException $e) + { + IssueLog::Error($e->getMessage()); + } + } - sort($aValues); + sort($aValues); - return $aValues; - } + return $aValues; + } /** * @return array of tag labels indexed by code */ public function GetTags() - { - $aTags = array(); - foreach ($this->aPreserved as $oTag) - { - try - { - $aTags[$oTag->Get('tag_code')] = $oTag->Get('tag_label'); - } catch (CoreException $e) - { - IssueLog::Error($e->getMessage()); - } - } - foreach ($this->aAdded as $oTag) - { - try - { - $aTags[$oTag->Get('tag_code')] = $oTag->Get('tag_label'); - } catch (CoreException $e) - { - IssueLog::Error($e->getMessage()); - } - } - ksort($aTags); - return $aTags; - } - - /** - * @return array of tag labels indexed by code for only the added tags - */ - public function GetAddedTags() { $aTags = array(); - foreach ($this->aAdded as $oTag) + foreach($this->aPreserved as $oTag) + { + try + { + $aTags[$oTag->Get('tag_code')] = $oTag->Get('tag_label'); + } catch (CoreException $e) + { + IssueLog::Error($e->getMessage()); + } + } + foreach($this->aAdded as $oTag) { try { @@ -188,6 +175,28 @@ final class ormTagSet } } ksort($aTags); + + return $aTags; + } + + /** + * @return array of tag labels indexed by code for only the added tags + */ + public function GetAddedTags() + { + $aTags = array(); + foreach($this->aAdded as $oTag) + { + try + { + $aTags[$oTag->Get('tag_code')] = $oTag->Get('tag_label'); + } catch (CoreException $e) + { + IssueLog::Error($e->getMessage()); + } + } + ksort($aTags); + return $aTags; } @@ -197,7 +206,7 @@ final class ormTagSet public function GetRemovedTags() { $aTags = array(); - foreach ($this->aRemoved as $oTag) + foreach($this->aRemoved as $oTag) { try { @@ -208,6 +217,7 @@ final class ormTagSet } } ksort($aTags); + return $aTags; } @@ -222,29 +232,30 @@ final class ormTagSet * * @throws \CoreException * @throws \CoreUnexpectedValue + * @throws \Exception */ public function GetDelta(ormTagSet $oOtherTagSet) - { + { $oTag = new ormTagSet($this->sClass, $this->sAttCode); // Set the initial value - $aOrigTagCodes = $this->GetValue(); - $oTag->SetValue($aOrigTagCodes); + $aOrigTagCodes = $this->GetValue(); + $oTag->SetValue($aOrigTagCodes); // now remove everything - foreach($aOrigTagCodes as $sTagCode) - { - $oTag->RemoveTag($sTagCode); - } - // now add the tags of the other TagSet - foreach($oOtherTagSet->GetValue() as $sTagCode) - { - $oTag->AddTag($sTagCode); - } - $aDelta = array(); - $aDelta['added'] = $oTag->GetAddedTags(); - $aDelta['removed'] = $oTag->GetRemovedTags(); + foreach($aOrigTagCodes as $sTagCode) + { + $oTag->RemoveTag($sTagCode); + } + // now add the tags of the other TagSet + foreach($oOtherTagSet->GetValue() as $sTagCode) + { + $oTag->AddTag($sTagCode); + } + $aDelta = array(); + $aDelta['added'] = $oTag->GetAddedTags(); + $aDelta['removed'] = $oTag->GetRemovedTags(); - return $aDelta; - } + return $aDelta; + } /** * Apply a delta to the current TagSet @@ -255,179 +266,195 @@ final class ormTagSet * @throws \CoreUnexpectedValue */ public function ApplyDelta($aDelta) - { - if (isset($aDelta['removed'])) - { - foreach($aDelta['removed'] as $sTagCode => $aTagLabel) - { - $this->RemoveTag($sTagCode); - } - } - if (isset($aDelta['added'])) - { - foreach($aDelta['added'] as $sTagCode => $aTagLabel) - { - $this->AddTag($sTagCode); - } - } - } + { + if (isset($aDelta['removed'])) + { + foreach($aDelta['removed'] as $sTagCode => $aTagLabel) + { + $this->RemoveTag($sTagCode); + } + } + if (isset($aDelta['added'])) + { + foreach($aDelta['added'] as $sTagCode => $aTagLabel) + { + $this->AddTag($sTagCode); + } + } + } /** + * Check whether a tag code is valid or not for this TagSet + * * @param string $sTagCode * * @return bool + */ + public function IsValidTag($sTagCode) + { + try + { + $this->GetTagFromCode($sTagCode); + + return true; + } catch (Exception $e) + { + return false; + } + } + + /** + * @param $sTagCode + * + * @throws \CoreException + * @throws \CoreUnexpectedValue + */ + public function AddTag($sTagCode) + { + if ($this->IsTagInList($this->aPreserved, $sTagCode) || $this->IsTagInList($this->aAdded, $sTagCode)) + { + // nothing to do, already existing tag + return; + } + // if removed then added again + if (($oTag = $this->RemoveTagFromList($this->aRemoved, $sTagCode)) !== false) + { + // put it back into preserved + $this->aPreserved[] = $oTag; + } + else + { + $this->aAdded[] = $this->GetTagFromCode($sTagCode); + } + $this->UpdateHasDeltaFlag(); + } + + /** + * @param $sTagCode + */ + public function RemoveTag($sTagCode) + { + if ($this->IsTagInList($this->aRemoved, $sTagCode)) + { + // nothing to do, already removed tag + return; + } + // if added then remove it + if (($oTag = $this->RemoveTagFromList($this->aAdded, $sTagCode)) === false) + { + // if present then remove it + if (($oTag = $this->RemoveTagFromList($this->aPreserved, $sTagCode)) !== false) + { + $this->aRemoved[] = $oTag; + } + } + $this->UpdateHasDeltaFlag(); + } + + private function IsTagInList($aTagList, $sTagCode) + { + foreach($aTagList as $oTag) + { + /** @var \TagSetFieldData $oTag */ + try + { + $sCode = $oTag->Get('tag_code'); + if ($sCode === $sTagCode) + { + return true; + } + } catch (CoreException $e) + { + IssueLog::Error($e->getMessage()); + } + } + + return false; + } + + private function RemoveTagFromList(&$aTagList, $sTagCode) + { + foreach($aTagList as $index => $oTag) + { + /** @var \TagSetFieldData $oTag */ + try + { + $sCode = $oTag->Get('tag_code'); + if ($sCode === $sTagCode) + { + unset($aTagList[$index]); + + return $oTag; + } + } catch (CoreException $e) + { + IssueLog::Error($e->getMessage()); + } + } + + return false; + } + + private function UpdateHasDeltaFlag() + { + if ((count($this->aAdded) == 0) && (count($this->aRemoved) == 0)) + { + $this->bHasDelta = false; + } + else + { + $this->bHasDelta = true; + } + } + + + /** + * @param $sTagCode + * + * @return DBObject tag + * @throws \CoreUnexpectedValue * @throws \CoreException */ - public function TagsExist($sTagCode) - { - try - { - $this->GetTagFromCode($sTagCode); - return true; - } catch (CoreUnexpectedValue $e) - { - return false; - } - } + private function GetTagFromCode($sTagCode) + { + $aAllowedTags = $this->GetAllowedTags(); + foreach($aAllowedTags as $oAllowedTag) + { + if ($oAllowedTag->Get('tag_code') === $sTagCode) + { + return $oAllowedTag; + } + } + throw new CoreUnexpectedValue("{$sTagCode} is not defined as a valid tag for {$this->sClass}:{$this->sAttCode}"); + } - /** - * @param $sTagCode - * - * @throws \CoreException - * @throws \CoreUnexpectedValue - */ - public function AddTag($sTagCode) - { - if ($this->IsTagInList($this->aPreserved, $sTagCode) || $this->IsTagInList($this->aAdded, $sTagCode)) - { - // nothing to do, already existing tag - return; - } - // if removed then added again - if (($oTag = $this->RemoveTagFromList($this->aRemoved, $sTagCode)) !== false) - { - // put it back into preserved - $this->aPreserved[] = $oTag; - } - else - { - $this->aAdded[] = $this->GetTagFromCode($sTagCode); - } - $this->UpdateHasDeltaFlag(); - } + /** + * @return array + */ + private function GetAllowedTags() + { + return TagSetFieldData::GetAllowedValues($this->sClass, $this->sAttCode); + } - /** - * @param $sTagCode - * - * @throws \CoreException - * @throws \CoreUnexpectedValue - */ - public function RemoveTag($sTagCode) - { - if ($this->IsTagInList($this->aRemoved, $sTagCode)) - { - // nothing to do, already removed tag - return; - } - // if added then remove it - if (($oTag = $this->RemoveTagFromList($this->aAdded, $sTagCode)) === false) - { - // if present then remove it - if (($oTag = $this->RemoveTagFromList($this->aPreserved, $sTagCode)) !== false) - { - $this->aRemoved[] = $oTag; - } - } - $this->UpdateHasDeltaFlag(); - } + /** + * Compare Tag Set + * + * @param \ormTagSet $other + * + * @return bool true if same tag set + */ + public function Equals(ormTagSet $other) + { + if ($this->GetTagDataClass() !== $other->GetTagDataClass()) + { + return false; + } - private function IsTagInList($aTagList, $sTagCode) - { - foreach ($aTagList as $oTag) - { - $sCode = $oTag->Get('tag_code'); - if ($sCode === $sTagCode) - { - return true; - } - } - return false; - } + return implode(' ', $this->GetValue()) === implode(' ', $other->GetValue()); + } - private function RemoveTagFromList(&$aTagList, $sTagCode) - { - foreach ($aTagList as $index => $oTag) - { - $sCode = $oTag->Get('tag_code'); - if ($sCode === $sTagCode) - { - unset($aTagList[$index]); - return $oTag; - } - } - return false; - } - - private function UpdateHasDeltaFlag() - { - if ((count($this->aAdded) == 0) && (count($this->aRemoved) == 0)) - { - $this->bHasDelta = false; - } - else - { - $this->bHasDelta = true; - } - } - - /** - * @param $sTagCode - * - * @return DBObject tag - * @throws \CoreUnexpectedValue - * @throws \CoreException - */ - private function GetTagFromCode($sTagCode) - { - $aAllowedTags = $this->GetAllowedTags(); - foreach($aAllowedTags as $oAllowedTag) - { - if ($oAllowedTag->Get('tag_code') === $sTagCode) - { - return $oAllowedTag; - } - } - throw new CoreUnexpectedValue("{$sTagCode} is not defined as a valid tag for {$this->sClass}:{$this->sAttCode}"); - } - - /** - * @return array - * @throws \CoreException - * @throws \Exception - */ - private function GetAllowedTags() - { - return TagSetFieldData::GetAllowedValues($this->sClass, $this->sAttCode); - } - - /** - * Compare Tag Set - * - * @param \ormTagSet $other - * - * @return bool true if same tag set - */ - public function Equals(ormTagSet $other) - { - if ($this->GetTagDataClass() !== $other->GetTagDataClass()) - { - return false; - } - return implode(' ',$this->GetValue()) === implode(' ', $other->GetValue()); - } - - public function GetTagDataClass() - { - return MetaModel::GetTagDataClass($this->sClass, $this->sAttCode); - } + public function GetTagDataClass() + { + return MetaModel::GetTagDataClass($this->sClass, $this->sAttCode); + } } \ No newline at end of file diff --git a/core/tagsetfield.class.inc.php b/core/tagsetfield.class.inc.php index 3970d04b5..196e15350 100644 --- a/core/tagsetfield.class.inc.php +++ b/core/tagsetfield.class.inc.php @@ -20,8 +20,9 @@ /** *
Stores data for {@link AttributeTagSet} fields * - *
We will have an implementation for each class/field to be able to customize rights (generated in \MFCompiler::CompileClass).
- * Only this abstract class will exists in the DB : the implementations won't had any new field.
+ *
We will have an implementation for each class/field to be able to customize rights (generated in
+ * \MFCompiler::CompileClass).
Only this abstract class will exists in the DB : the implementations won't had any
+ * new field.
*
* @since 2.6 N°931 tag fields
*/
@@ -29,64 +30,68 @@ abstract class TagSetFieldData extends cmdbAbstractObject
{
private static $m_aAllowedValues = array();
- public static function Init()
- {
- $aParams = array
- (
- 'category' => 'bizmodel',
- 'key_type' => 'autoincrement',
- 'name_attcode' => array('tag_label'),
- 'state_attcode' => '',
- 'reconc_keys' => array('tag_code'),
- 'db_table' => 'priv_tagfielddata',
- 'db_key_field' => 'id',
- 'db_finalclass_field' => 'finalclass',
- );
+ /**
+ * @throws \CoreException
+ * @throws \Exception
+ */
+ public static function Init()
+ {
+ $aParams = array
+ (
+ 'category' => 'bizmodel',
+ 'key_type' => 'autoincrement',
+ 'name_attcode' => array('tag_label'),
+ 'state_attcode' => '',
+ 'reconc_keys' => array('tag_code'),
+ 'db_table' => 'priv_tagfielddata',
+ 'db_key_field' => 'id',
+ 'db_finalclass_field' => 'finalclass',
+ );
- MetaModel::Init_Params($aParams);
- MetaModel::Init_InheritAttributes();
+ MetaModel::Init_Params($aParams);
+ MetaModel::Init_InheritAttributes();
- MetaModel::Init_AddAttribute(new AttributeString("tag_code", array(
- "allowed_values" => null,
- "sql" => 'tag_code',
- "default_value" => '',
- "is_null_allowed" => false,
- "depends_on" => array()
- )));
- MetaModel::Init_AddAttribute(new AttributeString("tag_label", array(
- "allowed_values" => null,
- "sql" => 'tag_label',
- "default_value" => '',
- "is_null_allowed" => false,
- "depends_on" => array()
- )));
- MetaModel::Init_AddAttribute(new AttributeString("tag_description", array(
- "allowed_values" => null,
- "sql" => 'tag_description',
- "default_value" => '',
- "is_null_allowed" => true,
- "depends_on" => array()
- )));
- MetaModel::Init_AddAttribute(new AttributeString("tag_class", array(
- "allowed_values" => null,
- "sql" => 'tag_class',
- "default_value" => '',
- "is_null_allowed" => false,
- "depends_on" => array()
- )));
- MetaModel::Init_AddAttribute(new AttributeString("tag_attcode", array(
- "allowed_values" => null,
- "sql" => 'tag_attcode',
- "default_value" => '',
- "is_null_allowed" => false,
- "depends_on" => array()
- )));
+ MetaModel::Init_AddAttribute(new AttributeString("tag_code", array(
+ "allowed_values" => null,
+ "sql" => 'tag_code',
+ "default_value" => '',
+ "is_null_allowed" => false,
+ "depends_on" => array()
+ )));
+ MetaModel::Init_AddAttribute(new AttributeString("tag_label", array(
+ "allowed_values" => null,
+ "sql" => 'tag_label',
+ "default_value" => '',
+ "is_null_allowed" => false,
+ "depends_on" => array()
+ )));
+ MetaModel::Init_AddAttribute(new AttributeString("tag_description", array(
+ "allowed_values" => null,
+ "sql" => 'tag_description',
+ "default_value" => '',
+ "is_null_allowed" => true,
+ "depends_on" => array()
+ )));
+ MetaModel::Init_AddAttribute(new AttributeString("tag_class", array(
+ "allowed_values" => null,
+ "sql" => 'tag_class',
+ "default_value" => '',
+ "is_null_allowed" => false,
+ "depends_on" => array()
+ )));
+ MetaModel::Init_AddAttribute(new AttributeString("tag_attcode", array(
+ "allowed_values" => null,
+ "sql" => 'tag_attcode',
+ "default_value" => '',
+ "is_null_allowed" => false,
+ "depends_on" => array()
+ )));
- MetaModel::Init_SetZListItems('details', array('tag_code', 'tag_label', 'tag_description'));
- MetaModel::Init_SetZListItems('standard_search', array('tag_code', 'tag_label', 'tag_description'));
- MetaModel::Init_SetZListItems('list', array('tag_code', 'tag_label', 'tag_description'));
- }
+ MetaModel::Init_SetZListItems('details', array('tag_code', 'tag_label', 'tag_description'));
+ MetaModel::Init_SetZListItems('standard_search', array('tag_code', 'tag_label', 'tag_description'));
+ MetaModel::Init_SetZListItems('list', array('tag_code', 'tag_label', 'tag_description'));
+ }
public function ComputeValues()
{
@@ -122,11 +127,30 @@ abstract class TagSetFieldData extends cmdbAbstractObject
unset(self::$m_aAllowedValues[$sTagDataClass]);
}
+ /**
+ * @throws \CoreException
+ * @throws \MissingQueryArgument
+ * @throws \MySQLException
+ * @throws \MySQLHasGoneAwayException
+ * @throws \OQLException
+ */
public function DoCheckToWrite()
{
// Check that code and labels are uniques
$sTagCode = $this->Get('tag_code');
+ // Check tag_code syntax
+ if (!preg_match("@^[a-zA-Z0-9]{1,20}$@", $sTagCode))
+ {
+ $this->m_aCheckIssues[] = Dict::S('Core:TagSetFieldData:ErrorTagCodeSyntax');
+ }
+
$sTagLabel = $this->Get('tag_label');
+ if (empty($sTagLabel) || (strpos($sTagLabel, "|") !== false))
+ {
+ // Label must not contain | character
+ $this->m_aCheckIssues[] = Dict::S('Core:TagSetFieldData:ErrorTagLabelSyntax');
+ }
+
$id = $this->GetKey();
$sClassName = get_class($this);
if (empty($id))
@@ -151,6 +175,28 @@ abstract class TagSetFieldData extends cmdbAbstractObject
parent::DoCheckToWrite();
}
+ /**
+ * @throws \CoreException
+ */
+ public function OnUpdate()
+ {
+ parent::OnUpdate();
+ $aChanges = $this->ListChanges();
+ if (array_key_exists('tag_code', $aChanges))
+ {
+ throw new CoreException(Dict::S('Core:TagSetFieldData:ErrorCodeUpdateNotAllowed'));
+ }
+ }
+
+ /**
+ * @param $sClass
+ * @param $sAttCode
+ *
+ * @return mixed
+ * @throws \CoreException
+ * @throws \CoreUnexpectedValue
+ * @throws \MySQLException
+ */
public static function GetAllowedValues($sClass, $sAttCode)
{
$sTagDataClass = MetaModel::GetTagDataClass($sClass, $sAttCode);
@@ -162,6 +208,7 @@ abstract class TagSetFieldData extends cmdbAbstractObject
$oSet = new DBObjectSet($oSearch);
self::$m_aAllowedValues[$sTagDataClass] = $oSet->ToArray();
}
+
return self::$m_aAllowedValues[$sTagDataClass];
}
}
\ No newline at end of file
diff --git a/dictionaries/en.dictionary.itop.core.php b/dictionaries/en.dictionary.itop.core.php
index 56776820f..9d64cc960 100644
--- a/dictionaries/en.dictionary.itop.core.php
+++ b/dictionaries/en.dictionary.itop.core.php
@@ -663,7 +663,7 @@ Dict::Add('EN US', 'English', 'English', array(
'SynchroDataSource:Definition' => 'Definition',
'Core:SynchroAttributes' => 'Attributes',
'Core:SynchroStatus' => 'Status',
- 'Core:Synchro:ErrorsLabel' => 'Errors',
+ 'Core:Synchro:ErrorsLabel' => 'Errors',
'Core:Synchro:CreatedLabel' => 'Created',
'Core:Synchro:ModifiedLabel' => 'Modified',
'Core:Synchro:UnchangedLabel' => 'Unchanged',
@@ -690,7 +690,7 @@ Dict::Add('EN US', 'English', 'English', array(
'Core:Synchro:label_obj_disappeared_errors' => 'Errors (%1$s)',
'Core:Synchro:label_obj_disappeared_no_action' => 'No Action (%1$s)',
'Core:Synchro:label_obj_unchanged' => 'Unchanged (%1$s)',
- 'Core:Synchro:label_obj_updated' => 'Updated (%1$s)',
+ 'Core:Synchro:label_obj_updated' => 'Updated (%1$s)',
'Core:Synchro:label_obj_updated_errors' => 'Errors (%1$s)',
'Core:Synchro:label_obj_new_unchanged' => 'Unchanged (%1$s)',
'Core:Synchro:label_obj_new_updated' => 'Updated (%1$s)',
@@ -699,8 +699,8 @@ Dict::Add('EN US', 'English', 'English', array(
'Core:SynchroLogTitle' => '%1$s - %2$s',
'Core:Synchro:Nb_Replica' => 'Replica processed: %1$s',
'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s',
- 'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'At Least one reconciliation key must be specified, or the reconciliation policy must be to use the primary key.',
- 'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'A delete retention period must be specified, since objects are to be deleted after being marked as obsolete',
+ 'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'At Least one reconciliation key must be specified, or the reconciliation policy must be to use the primary key.',
+ 'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'A delete retention period must be specified, since objects are to be deleted after being marked as obsolete',
'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => 'Obsolete objects are to be updated, but no update is specified.',
'Class:SynchroDataSource/Error:DataTableAlreadyExists' => 'The table %1$s already exists in the database. Please use another name for the synchro data table.',
'Core:SynchroReplica:PublicData' => 'Public Data',
@@ -829,16 +829,16 @@ Dict::Add('EN US', 'English', 'English', array(
'Core:ExecProcess:Code255' => 'PHP Error (parsing, or runtime)',
// Attribute Duration
- 'Core:Duration_Seconds' => '%1$ds',
- 'Core:Duration_Minutes_Seconds' =>'%1$dmin %2$ds',
- 'Core:Duration_Hours_Minutes_Seconds' => '%1$dh %2$dmin %3$ds',
- 'Core:Duration_Days_Hours_Minutes_Seconds' => '%1$sd %2$dh %3$dmin %4$ds',
+ 'Core:Duration_Seconds' => '%1$ds',
+ 'Core:Duration_Minutes_Seconds' =>'%1$dmin %2$ds',
+ 'Core:Duration_Hours_Minutes_Seconds' => '%1$dh %2$dmin %3$ds',
+ 'Core:Duration_Days_Hours_Minutes_Seconds' => '%1$sd %2$dh %3$dmin %4$ds',
// Explain working time computing
'Core:ExplainWTC:ElapsedTime' => 'Time elapsed (stored as "%1$s")',
'Core:ExplainWTC:StopWatch-TimeSpent' => 'Time spent for "%1$s"',
'Core:ExplainWTC:StopWatch-Deadline' => 'Deadline for "%1$s" at %2$d%%',
-
+
// Bulk export
'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".',
@@ -914,8 +914,11 @@ Dict::Add('EN US', 'English', 'English', array(
// Class: TagSetFieldData
//
Dict::Add('EN US', 'English', 'English', array(
- 'Class:TagSetFieldData' => 'List of tags',
- 'Class:TagSetFieldData+' => '',
+ 'Class:TagSetFieldData' => 'List of tags',
+ 'Class:TagSetFieldData+' => '',
'Core:TagSetFieldData:ErrorDeleteUsedTag' => 'Used tags cannot be deleted',
'Core:TagSetFieldData:ErrorDuplicateTagCodeOrLabel' => 'Tags codes or labels must be unique',
+ 'Core:TagSetFieldData:ErrorTagCodeSyntax' => 'Tags code should match [a-zA-Z0-9]{1,20} syntax',
+ 'Core:TagSetFieldData:ErrorTagLabelSyntax' => 'Tags label should not contain | nor be empty',
+ 'Core:TagSetFieldData:ErrorCodeUpdateNotAllowed' => 'Tags code cannot be changed',
));
diff --git a/dictionaries/fr.dictionary.itop.core.php b/dictionaries/fr.dictionary.itop.core.php
index 56c9eb98d..fc7a14f0c 100644
--- a/dictionaries/fr.dictionary.itop.core.php
+++ b/dictionaries/fr.dictionary.itop.core.php
@@ -766,4 +766,7 @@ Opérateurs :
'Core:Validator:MustSelectOne' => 'Veuillez choisir une valeur',
'Core:TagSetFieldData:ErrorDeleteUsedTag' => 'Impossible de supprimer une étiquette utilisée',
'Core:TagSetFieldData:ErrorDuplicateTagCodeOrLabel' => 'Les codes et noms des étiquettes doivent être unique',
+ 'Core:TagSetFieldData:ErrorTagCodeSyntax' => 'Le code de l\'étiquette doit avoir la syntaxe suivante : [a-zA-Z0-9]{1,20}',
+ 'Core:TagSetFieldData:ErrorTagLabelSyntax' => 'Le nom de l\'étiquette ne doit pas être vide ni contenir le caractère \'|\'',
+ 'Core:TagSetFieldData:ErrorCodeUpdateNotAllowed' => 'Le code de l\'étiquette ne peut pas être changé',
));
diff --git a/test/core/TagSetFieldDataTest.php b/test/core/TagSetFieldDataTest.php
index e463e9a4d..689b1eb73 100644
--- a/test/core/TagSetFieldDataTest.php
+++ b/test/core/TagSetFieldDataTest.php
@@ -16,9 +16,12 @@ use TagSetFieldData;
class TagSetFieldDataTest extends ItopDataTestCase
{
- // Need commit to create the FULLTEXT INDEX of MySQL
+ // Need database COMMIT in order to create the FULLTEXT INDEX of MySQL
const USE_TRANSACTION = false;
+ /**
+ * @throws \CoreException
+ */
public function testGetAllowedValues()
{
$aAllowedValues = TagSetFieldData::GetAllowedValues(TAG_CLASS, TAG_ATTCODE);
@@ -41,6 +44,9 @@ class TagSetFieldDataTest extends ItopDataTestCase
static::assertEquals(4, $iCurrCount - $iInitialCount);
}
+ /**
+ * @throws \CoreException
+ */
public function testDoCheckToWrite()
{
$aAllowedValues = TagSetFieldData::GetAllowedValues(TAG_CLASS, TAG_ATTCODE);
@@ -78,7 +84,7 @@ class TagSetFieldDataTest extends ItopDataTestCase
try
{
- $this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag5', 'Fourth');
+ $this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'zembrek', 'Fourth');
} catch (\CoreException $e)
{
$this->debug($e->getMessage());
@@ -91,28 +97,38 @@ class TagSetFieldDataTest extends ItopDataTestCase
/**
* @throws \CoreException
* @throws \CoreUnexpectedValue
+ * @throws \Exception
*/
public function testDoCheckToDelete()
{
$oTagData = $this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First');
$oTagData->DBDelete();
+ // Create a tag
$oTagData = $this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First');
+ //Use it
$oTicket = $this->CreateTicket(1);
$oTicket->Set(TAG_ATTCODE, 'tag1');
$oTicket->DBWrite();
+
+ // Try to delete the tag, must complain !
try
{
$oTagData->DBDelete();
- }
- catch (\CoreException $e)
+ } catch (\DeleteException $e)
{
static::assertTrue(true);
+
return;
}
+ // Should not pass here
static::assertFalse(true);
}
+ /**
+ * @throws \CoreException
+ * @throws \Exception
+ */
public function testComputeValues()
{
$sTagClass = \MetaModel::GetTagDataClass(TAG_CLASS, TAG_ATTCODE);
@@ -126,4 +142,59 @@ class TagSetFieldDataTest extends ItopDataTestCase
static::assertEquals(TAG_ATTCODE, $oTagData->Get('tag_attcode'));
}
+ /**
+ * Test invalid tag codes
+ * @dataProvider InvalidTagCodeProvider
+ *
+ * @expectedException \CoreException
+ *
+ * @param string $sTagCode
+ *
+ * @throws \CoreException
+ */
+ public function testInvalidTagCode($sTagCode)
+ {
+ $this->CreateTagData(TAG_CLASS, TAG_ATTCODE, $sTagCode, 'First');
+ // Should not pass here
+ static::assertFalse(true);
+ }
+
+ public function InvalidTagCodeProvider()
+ {
+ return array(
+ 'No space' => array('tag1 1'),
+ 'No _' => array('tag_1'),
+ 'No -' => array('tag-1'),
+ 'No %' => array('tag%1'),
+ 'Less than 21 chars' => array('012345678901234567890'),
+ 'At least one char' => array(''),
+ 'No #' => array('#tag'),
+ 'No !' => array('tag!'),
+ );
+ }
+
+ /**
+ * Test invalid tag labels
+ * @expectedException \CoreException
+ * @throws \CoreException
+ */
+ public function testInvalidTagLabel()
+ {
+ $this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First|Second');
+ // Should not pass here
+ static::assertFalse(true);
+ }
+
+ /**
+ * Test that tag code cannot be modified
+ * @expectedException \CoreException
+ * @throws \CoreException
+ * @throws \CoreUnexpectedValue
+ */
+ public function testUpdateCode()
+ {
+ $oTagData = $this->CreateTagData(TAG_CLASS, TAG_ATTCODE, 'tag1', 'First');
+ $oTagData->Set('tag_code', 'tag2');
+ $oTagData->DBWrite();
+ }
}