diff --git a/application/nicewebpage.class.inc.php b/application/nicewebpage.class.inc.php index bc7056ea7..e1c0d8bf3 100644 --- a/application/nicewebpage.class.inc.php +++ b/application/nicewebpage.class.inc.php @@ -62,6 +62,7 @@ class NiceWebPage extends WebPage $this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_field.js'); $this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_numeric.js'); $this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_enum.js'); + $this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_tag_set.js'); $this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_key.js'); $this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_hierarchical_key.js'); $this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_abstract.js'); diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index 503d26e93..3b2cfdb5b 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -42,7 +42,7 @@ require_once(APPROOT . 'sources/form/validator/validator.class.inc.php'); require_once(APPROOT . 'sources/form/validator/notemptyextkeyvalidator.class.inc.php'); /** - * MissingColumnException - sent if an attribute is being created but the column is missing in the row + * MissingColumnException - sent if an attribute is being created but the column is missing in the row * * @package iTopORM */ @@ -50,28 +50,28 @@ class MissingColumnException extends Exception {} /** - * add some description here... + * add some description here... * * @package iTopORM */ define('EXTKEY_RELATIVE', 1); /** - * add some description here... + * add some description here... * * @package iTopORM */ define('EXTKEY_ABSOLUTE', 2); /** - * Propagation of the deletion through an external key - ask the user to delete the referencing object + * Propagation of the deletion through an external key - ask the user to delete the referencing object * * @package iTopORM */ define('DEL_MANUAL', 1); /** - * Propagation of the deletion through an external key - ask the user to delete the referencing object + * Propagation of the deletion through an external key - ask the user to delete the referencing object * * @package iTopORM */ @@ -106,7 +106,7 @@ define('LINKSET_EDITMODE_ADDREMOVE', 4); // The "linked" objects can be added/re /** - * Attribute definition API, implemented in and many flavours (Int, String, Enum, etc.) + * Attribute definition API, implemented in and many flavours (Int, String, Enum, etc.) * * @package iTopORM */ @@ -121,6 +121,8 @@ abstract class AttributeDefinition const SEARCH_WIDGET_TYPE_EXTERNAL_FIELD = 'external_field'; const SEARCH_WIDGET_TYPE_DATE_TIME = 'date_time'; const SEARCH_WIDGET_TYPE_DATE = 'date'; + const SEARCH_WIDGET_TYPE_TAG_SET = 'tag_set'; + const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW; @@ -555,7 +557,7 @@ abstract class AttributeDefinition $sLabel = $this->SearchLabel('/Attribute:'.$this->m_sCode.'?', $sDefault, false); } return $sLabel; - } + } public function GetHelpOnSmartSearch() { @@ -567,7 +569,7 @@ abstract class AttributeDefinition { return $sHelp; } - } + } return ''; } @@ -680,7 +682,7 @@ abstract class AttributeDefinition // Note: This is the responsibility of this function to place backticks around column aliases return array('`'.$sClassAlias.$this->GetCode().'`'); } - + public function GetOrderByHint() { return ''; @@ -705,12 +707,12 @@ abstract class AttributeDefinition { return ''; } - + public function CheckFormat($value) { return true; } - + public function GetMaxSize() { return null; @@ -727,17 +729,17 @@ abstract class AttributeDefinition return call_user_func($sComputeFunc); } - + abstract public function GetDefaultValue(DBObject $oHostObject = null); // // To be overloaded in subclasses // - + abstract public function GetBasicFilterOperators(); // returns an array of "opCode"=>"description" abstract public function GetBasicFilterLooseOperator(); // returns an "opCode" //abstract protected GetBasicFilterHTMLInput(); - abstract public function GetBasicFilterSQLExpr($sOpCode, $value); + abstract public function GetBasicFilterSQLExpr($sOpCode, $value); public function GetFilterDefinitions() { @@ -899,7 +901,7 @@ abstract class AttributeDefinition { $oFormField->SetReadOnly(true); } - + // CurrentValue $oFormField->SetCurrentValue($oObject->Get($this->GetCode())); @@ -914,7 +916,7 @@ abstract class AttributeDefinition /** * List the available verbs for 'GetForTemplate' - */ + */ public function EnumTemplateVerbs() { return array( @@ -945,17 +947,17 @@ abstract class AttributeDefinition { case '': return $value; - + case 'html': return $this->GetAsHtml($value, $oHostObject, $bLocalize); - + case 'label': return $this->GetEditValue($value); - + case 'text': return $this->GetAsPlainText($value); break; - + default: throw new Exception("Unknown verb '$sVerb' for attribute ".$this->GetCode().' in class '.get_class($oHostObject)); } @@ -1082,7 +1084,7 @@ abstract class AttributeDefinition $aParams[$sParamName] = "%$sSearchText%"; $sSQLOperator = 'LIKE'; break; - + default: $sSQLOperator = $sOperator; $aParams[$sParamName] = $sSearchText; @@ -1090,7 +1092,7 @@ abstract class AttributeDefinition $oNewCondition = new BinaryExpression($oField, $sSQLOperator, $oRightExpr); return $oNewCondition; } - + /** * Tells if an attribute is part of the unique fingerprint of the object (used for comparing two objects) * All attributes which value is not based on a value from the object itself (like ExternalFields or LinkedSet) @@ -1101,7 +1103,7 @@ abstract class AttributeDefinition { return true; } - + /** * The part of the current attribute in the object's signature, for the supplied value * @param mixed $value The value of this attribute for the object @@ -1114,7 +1116,7 @@ abstract class AttributeDefinition } /** - * Set of objects directly linked to an object, and being part of its definition + * Set of objects directly linked to an object, and being part of its definition * * @package iTopORM */ @@ -1129,9 +1131,9 @@ class AttributeLinkedSet extends AttributeDefinition public function IsWritable() {return true;} static public function IsLinkSet() {return true;} - public function IsIndirect() {return false;} + public function IsIndirect() {return false;} - public function GetValuesDef() {return $this->Get("allowed_values");} + public function GetValuesDef() {return $this->Get("allowed_values");} public function GetPrerequisiteAttributes($sClass = null) {return $this->Get("depends_on");} /** @@ -1191,7 +1193,7 @@ class AttributeLinkedSet extends AttributeDefinition { return $this->GetOptional('edit_mode', LINKSET_EDITMODE_ACTIONS); } - + public function GetLinkedClass() {return $this->Get('linked_class');} public function GetExtKeyToMe() {return $this->Get('ext_key_to_me');} @@ -1354,7 +1356,7 @@ class AttributeLinkedSet extends AttributeDefinition /** * List the available verbs for 'GetForTemplate' - */ + */ public function EnumTemplateVerbs() { return array( @@ -1400,10 +1402,10 @@ class AttributeLinkedSet extends AttributeDefinition { case '': return implode("\n", $aNames); - + case 'html': return ''; - + default: throw new Exception("Unknown verb '$sVerb' for attribute ".$this->GetCode().' in class '.get_class($oHostObject)); } @@ -1573,7 +1575,7 @@ class AttributeLinkedSet extends AttributeDefinition continue; // Don't check the key to self } } - + if ($oAttDef->IsWritable() && $oAttDef->IsNull($oLink->Get($sAttCode)) && !$oAttDef->IsNullAllowed()) { $aErrors[] = $sAttCode; @@ -1686,7 +1688,7 @@ class AttributeLinkedSet extends AttributeDefinition continue; // Don't check the key to self } } - + if ($oAttDef->IsWritable() && $oAttDef->IsNull($oLink->Get($sAttCode)) && !$oAttDef->IsNullAllowed()) { $aErrors[] = $sAttCode; @@ -1778,7 +1780,7 @@ class AttributeLinkedSet extends AttributeDefinition $sFormFieldClass = static::GetFormFieldClass(); $oFormField = new $sFormFieldClass($this->GetCode()); } - + // Setting target class if (!$this->IsIndirect()) { @@ -1812,9 +1814,9 @@ class AttributeLinkedSet extends AttributeDefinition $aAttributesToDisplay[$sAttCodeToDisplay] = $oAttDefToDisplay->GetLabel(); } $oFormField->SetAttributesToDisplay($aAttributesToDisplay); - + parent::MakeFormField($oObject, $oFormField); - + return $oFormField; } @@ -1822,7 +1824,7 @@ class AttributeLinkedSet extends AttributeDefinition } /** - * Set of objects linked to an object (n-n), and being part of its definition + * Set of objects linked to an object (n-n), and being part of its definition * * @package iTopORM */ @@ -1872,12 +1874,12 @@ class AttributeLinkedSetIndirect extends AttributeLinkedSet } /** - * Abstract class implementing default filters for a DB column + * Abstract class implementing default filters for a DB column * * @package iTopORM */ class AttributeDBFieldVoid extends AttributeDefinition -{ +{ static public function ListExpectedParams() { return array_merge(parent::ListExpectedParams(), array("allowed_values", "depends_on", "sql")); @@ -1914,8 +1916,8 @@ class AttributeDBFieldVoid extends AttributeDefinition } public function GetEditClass() {return "String";} - - public function GetValuesDef() {return $this->Get("allowed_values");} + + public function GetValuesDef() {return $this->Get("allowed_values");} public function GetPrerequisiteAttributes($sClass = null) {return $this->Get("depends_on");} static public function IsBasedOnDBColumns() {return true;} @@ -1985,16 +1987,16 @@ class AttributeDBFieldVoid extends AttributeDefinition default: return $this->GetSQLExpr()." = $sQValue"; } - } + } } /** - * Base class for all kind of DB attributes, with the exception of external keys + * Base class for all kind of DB attributes, with the exception of external keys * * @package iTopORM */ class AttributeDBField extends AttributeDBFieldVoid -{ +{ static public function ListExpectedParams() { return array_merge(parent::ListExpectedParams(), array("default_value", "is_null_allowed")); @@ -2004,7 +2006,7 @@ class AttributeDBField extends AttributeDBFieldVoid } /** - * Map an integer column to an attribute + * Map an integer column to an attribute * * @package iTopORM */ @@ -2020,7 +2022,7 @@ class AttributeInteger extends AttributeDBField public function GetEditClass() {return "String";} protected function GetSQLCol($bFullSpec = false) {return "INT(11)".($bFullSpec ? $this->GetSQLColSpec() : '');} - + public function GetValidationPattern() { return "^[0-9]+$"; @@ -2066,23 +2068,23 @@ class AttributeInteger extends AttributeDBField break; case 'in': if (!is_array($value)) throw new CoreException("Expected an array for argument value (sOpCode='$sOpCode')"); - return $this->GetSQLExpr()." IN ('".implode("', '", $value)."')"; + return $this->GetSQLExpr()." IN ('".implode("', '", $value)."')"; break; case '=': default: return $this->GetSQLExpr()." = \"$value\""; } - } + } public function GetNullValue() { return null; - } + } public function IsNull($proposedValue) { return is_null($proposedValue); - } + } public function MakeRealValue($proposedValue, $oHostObj) { @@ -2099,7 +2101,7 @@ class AttributeInteger extends AttributeDBField } /** - * An external key for which the class is defined as the value of another attribute + * An external key for which the class is defined as the value of another attribute * * @package iTopORM */ @@ -2134,17 +2136,17 @@ class AttributeObjectKey extends AttributeDBFieldVoid public function GetBasicFilterSQLExpr($sOpCode, $value) { return parent::GetBasicFilterSQLExpr($sOpCode, $value); - } + } public function GetNullValue() { return 0; - } + } public function IsNull($proposedValue) { return ($proposedValue == 0); - } + } public function MakeRealValue($proposedValue, $oHostObj) { @@ -2159,7 +2161,7 @@ class AttributeObjectKey extends AttributeDBFieldVoid } /** - * Display an integer between 0 and 100 as a percentage / horizontal bar graph + * Display an integer between 0 and 100 as a percentage / horizontal bar graph * * @package iTopORM */ @@ -2218,7 +2220,7 @@ class AttributeDecimal extends AttributeDBField { return "DECIMAL(".$this->Get('digits').",".$this->Get('decimals').")".($bFullSpec ? $this->GetSQLColSpec() : ''); } - + public function GetValidationPattern() { $iNbDigits = $this->Get('digits'); @@ -2267,23 +2269,23 @@ class AttributeDecimal extends AttributeDBField break; case 'in': if (!is_array($value)) throw new CoreException("Expected an array for argument value (sOpCode='$sOpCode')"); - return $this->GetSQLExpr()." IN ('".implode("', '", $value)."')"; + return $this->GetSQLExpr()." IN ('".implode("', '", $value)."')"; break; case '=': default: return $this->GetSQLExpr()." = \"$value\""; } - } + } public function GetNullValue() { return null; - } + } public function IsNull($proposedValue) { return is_null($proposedValue); - } + } public function MakeRealValue($proposedValue, $oHostObj) { @@ -2300,7 +2302,7 @@ class AttributeDecimal extends AttributeDBField } /** - * Map a boolean column to an attribute + * Map a boolean column to an attribute * * @package iTopORM */ @@ -2509,7 +2511,7 @@ class AttributeBoolean extends AttributeInteger } /** - * Map a varchar column (size < ?) to an attribute + * Map a varchar column (size < ?) to an attribute * * @package iTopORM */ @@ -2601,17 +2603,17 @@ class AttributeString extends AttributeDBField default: return $this->GetSQLExpr()." LIKE $sQValue"; } - } + } public function GetNullValue() { return ''; - } + } public function IsNull($proposedValue) { return ($proposedValue == ''); - } + } public function MakeRealValue($proposedValue, $oHostObj) { @@ -2661,7 +2663,7 @@ class AttributeString extends AttributeDBField } /** - * An attibute that matches an object class + * An attibute that matches an object class * * @package iTopORM */ @@ -2688,7 +2690,7 @@ class AttributeClass extends AttributeString { // For this kind of attribute specifying null as default value // is authorized even if null is not allowed - + // Pick the first one... $aClasses = $this->GetAllowedValues(); $sDefault = key($aClasses); @@ -2706,16 +2708,16 @@ class AttributeClass extends AttributeString { return true; } - + public function GetBasicFilterLooseOperator() { return '='; } - + } /** - * An attibute that matches one of the language codes availables in the dictionnary + * An attibute that matches one of the language codes availables in the dictionnary * * @package iTopORM */ @@ -2745,7 +2747,7 @@ class AttributeApplicationLanguage extends AttributeString { return true; } - + public function GetBasicFilterLooseOperator() { return '='; @@ -2753,7 +2755,7 @@ class AttributeApplicationLanguage extends AttributeString } /** - * The attribute dedicated to the finalclass automatic attribute + * The attribute dedicated to the finalclass automatic attribute * * @package iTopORM */ @@ -2919,7 +2921,7 @@ class AttributeFinalClass extends AttributeString { return '='; } - + public function GetValueLabel($sValue) { if (empty($sValue)) return ''; @@ -2940,7 +2942,7 @@ class AttributeFinalClass extends AttributeString /** - * Map a varchar column (size < ?) to an attribute that must never be shown to the user + * Map a varchar column (size < ?) to an attribute that must never be shown to the user * * @package iTopORM */ @@ -2986,7 +2988,7 @@ class AttributePassword extends AttributeString return '******'; } } - + public function IsPartOfFingerprint() { return false; } // Cannot reliably compare two encrypted passwords since the same password will be encrypted in diffferent manners depending on the random 'salt' } @@ -3021,7 +3023,7 @@ class AttributeEncryptedString extends AttributeString * 1) The static class variable $sKey is NOT serialized * 2) The object's constructor is NOT called upon wakeup * 3) mcrypt may crash the server if passed an empty key !! - * + * * So let's restore the key (if needed) when waking up **/ public function __wakeup() @@ -3035,9 +3037,9 @@ class AttributeEncryptedString extends AttributeString self::$sLibrary = MetaModel::GetConfig()->GetEncryptionLibrary(); } } - - protected function GetSQLCol($bFullSpec = false) {return "TINYBLOB";} + + protected function GetSQLCol($bFullSpec = false) {return "TINYBLOB";} public function GetMaxSize() { @@ -3101,7 +3103,7 @@ define('WIKI_OBJECT_REGEXP', '/\[\[(.+):(.+)\]\]/U'); /** - * Map a text column (size > ?) to an attribute + * Map a text column (size > ?) to an attribute * * @package iTopORM */ @@ -3146,7 +3148,7 @@ class AttributeText extends AttributeString } return $aColumns; } - + public function GetMaxSize() { // Is there a way to know the current limitation for mysql? @@ -3172,7 +3174,7 @@ class AttributeText extends AttributeString $sUrl = $aAllMatches[$i][0][0]; // String corresponding to the main pattern $iPos = $aAllMatches[$i][0][1]; // Position of the main pattern $sText = substr_replace($sText, "$sUrl", $iPos, strlen($sUrl)); - + } } } @@ -3182,7 +3184,7 @@ class AttributeText extends AttributeString { $sClass = trim($aMatches[1]); $sName = trim($aMatches[2]); - + if (MetaModel::IsValidClass($sClass)) { $oObj = MetaModel::GetObjectByName($sClass, $sName, false /* MustBeFound */); @@ -3223,19 +3225,19 @@ class AttributeText extends AttributeString $aStyles[] = 'overflow:auto'; $sStyle = 'style="'.implode(';', $aStyles).'"'; } - + if ($this->GetFormat() == 'text') { $sValue = parent::GetAsHTML($sValue, $oHostObject, $bLocalize); $sValue = self::RenderWikiHtml($sValue); - return "
".str_replace("\n", "
\n", $sValue).'
'; + return "
".str_replace("\n", "
\n", $sValue).'
'; } else { $sValue = self::RenderWikiHtml($sValue, true /* wiki only */); return "
".InlineImage::FixUrls($sValue).'
'; } - + } public function GetEditValue($sValue, $oHostObj = null) @@ -3283,7 +3285,7 @@ class AttributeText extends AttributeString return parent::GetAsPlainText($sValue, $oHostObj); } } - + public function MakeRealValue($proposedValue, $oHostObj) { $sValue = $proposedValue; @@ -3295,7 +3297,7 @@ class AttributeText extends AttributeString $sValue = HTMLSanitizer::Sanitize($sValue); } break; - + case 'text': default: if (preg_match_all(WIKI_OBJECT_REGEXP, $sValue, $aAllMatches, PREG_SET_ORDER)) @@ -3323,15 +3325,15 @@ class AttributeText extends AttributeString { return Str::pure2xml($value); } - + public function GetWidth() { - return $this->GetOptional('width', ''); + return $this->GetOptional('width', ''); } - + public function GetHeight() { - return $this->GetOptional('height', ''); + return $this->GetOptional('height', ''); } static public function GetFormFieldClass() @@ -3392,7 +3394,7 @@ class AttributeText extends AttributeString { $sFormat = $this->GetFormat(); } - + switch($sFormat) { case 'text': @@ -3401,7 +3403,7 @@ class AttributeText extends AttributeString $value = utils::TextToHtml($value); } break; - + case 'html': if ($this->GetFormat() == 'text') { @@ -3412,13 +3414,13 @@ class AttributeText extends AttributeString $value = InlineImage::FixUrls((string)$value); } break; - + default: // unknown format ?? } return $value; } - + public function GetSQLValues($value) { $aValues = array(); @@ -3429,8 +3431,8 @@ class AttributeText extends AttributeString $aValues[$this->Get("sql").'_format'] = $this->GetFormat(); } return $aValues; - } - + } + public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true, $bConvertToPlainText = false) { switch($this->GetFormat()) @@ -3445,7 +3447,7 @@ class AttributeText extends AttributeString $sEscaped = str_replace($sFrom, $sTo, (string)$sValue); return $sTextQualifier.$sEscaped.$sTextQualifier; break; - + case 'text': default: return parent::GetAsCSV($sValue, $sSeparator, $sTextQualifier, $oHostObject, $bLocalize, $bConvertToPlainText); @@ -3454,7 +3456,7 @@ class AttributeText extends AttributeString } /** - * Map a log to an attribute + * Map a log to an attribute * * @package iTopORM */ @@ -3474,7 +3476,7 @@ class AttributeLongText extends AttributeText } /** - * An attibute that stores a case log (i.e journal) + * An attibute that stores a case log (i.e journal) * * @package iTopORM */ @@ -3485,7 +3487,7 @@ class AttributeCaseLog extends AttributeLongText public function GetNullValue() { return ''; - } + } public function IsNull($proposedValue) { @@ -3494,7 +3496,7 @@ class AttributeCaseLog extends AttributeLongText return ($proposedValue == ''); } return ($proposedValue->GetText() == ''); - } + } public function ScalarToSQL($value) { @@ -3535,7 +3537,7 @@ class AttributeCaseLog extends AttributeLongText return (string) $value; } } - + public function GetDefaultValue(DBObject $oHostObject = null) {return new ormCaseLog();} public function Equals($val1, $val2) {return ($val1->GetText() == $val2->GetText());} @@ -3568,7 +3570,7 @@ class AttributeCaseLog extends AttributeLongText { $oPreviousLog = $oHostObj->GetOriginal($this->GetCode());; } - + } if (is_object($oPreviousLog)) { @@ -3621,10 +3623,10 @@ class AttributeCaseLog extends AttributeLongText { $sAvailable = implode(', ', array_keys($aCols)); throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}"); - } + } $sLog = $aCols[$sPrefix]; - if (isset($aCols[$sPrefix.'_index'])) + if (isset($aCols[$sPrefix.'_index'])) { $sIndex = $aCols[$sPrefix.'_index']; } @@ -3635,7 +3637,7 @@ class AttributeCaseLog extends AttributeLongText } if (strlen($sIndex) > 0) - { + { $aIndex = unserialize($sIndex); $value = new ormCaseLog($sLog, $aIndex); } @@ -3706,7 +3708,7 @@ class AttributeCaseLog extends AttributeLongText return ''; } } - + public function GetAsXML($value, $oHostObject = null, $bLocalize = true) { if ($value instanceOf ormCaseLog) @@ -3721,7 +3723,7 @@ class AttributeCaseLog extends AttributeLongText /** * List the available verbs for 'GetForTemplate' - */ + */ public function EnumTemplateVerbs() { return array( @@ -3749,25 +3751,25 @@ class AttributeCaseLog extends AttributeLongText { case '': return $value->GetText(true); - + case 'head': return $value->GetLatestEntry('text'); case 'head_html': return $value->GetLatestEntry('html'); - + case 'html': return $value->GetAsEmailHtml(); - + default: throw new Exception("Unknown verb '$sVerb' for attribute ".$this->GetCode().' in class '.get_class($oHostObject)); } } - + /** * Helper to get a value that will be JSON encoded - * The operation is the opposite to FromJSONToValue - */ + * The operation is the opposite to FromJSONToValue + */ public function GetForJSON($value) { return $value->GetForJSON(); @@ -3775,8 +3777,8 @@ class AttributeCaseLog extends AttributeLongText /** * Helper to form a value, given JSON decoded data - * The operation is the opposite to GetForJSON - */ + * The operation is the opposite to GetForJSON + */ public function FromJSONToValue($json) { if (is_string($json)) @@ -3802,7 +3804,7 @@ class AttributeCaseLog extends AttributeLongText } return $ret; } - + public function Fingerprint($value) { $sFingerprint = ''; @@ -3812,7 +3814,7 @@ class AttributeCaseLog extends AttributeLongText } return $sFingerprint; } - + /** * The actual formatting of the text: either text (=plain text) or html (= text with HTML markup) * @return string @@ -3841,7 +3843,7 @@ class AttributeCaseLog extends AttributeLongText } /** - * Map a text column (size > ?), containing HTML code, to an attribute + * Map a text column (size > ?), containing HTML code, to an attribute * * @package iTopORM */ @@ -3874,7 +3876,7 @@ class AttributeHTML extends AttributeLongText } /** - * Specialization of a string: email + * Specialization of a string: email * * @package iTopORM */ @@ -3901,7 +3903,7 @@ class AttributeEmailAddress extends AttributeString } /** - * Specialization of a string: IP address + * Specialization of a string: IP address * * @package iTopORM */ @@ -3950,7 +3952,7 @@ class AttributePhoneNumber extends AttributeString } /** - * Specialization of a string: OQL expression + * Specialization of a string: OQL expression * * @package iTopORM */ @@ -3962,7 +3964,7 @@ class AttributeOQL extends AttributeText } /** - * Specialization of a string: template (contains iTop placeholders like $current_contact_id$ or $this->name$) + * Specialization of a string: template (contains iTop placeholders like $current_contact_id$ or $this->name$) * * @package iTopORM */ @@ -4018,7 +4020,7 @@ class AttributeTemplateHTML extends AttributeText /** - * Map a enum column to an attribute + * Map a enum column to an attribute * * @package iTopORM */ @@ -4061,7 +4063,7 @@ class AttributeEnum extends AttributeString .($bFullSpec ? " DEFAULT ''" : ""); // ENUM() is not an allowed syntax! } } - + protected function GetSQLColSpec() { $default = $this->ScalarToSQL($this->GetDefaultValue()); @@ -4111,7 +4113,7 @@ class AttributeEnum extends AttributeString public function GetBasicFilterSQLExpr($sOpCode, $value) { return parent::GetBasicFilterSQLExpr($sOpCode, $value); - } + } public function GetValueLabel($sValue) { @@ -4245,8 +4247,8 @@ class AttributeEnum extends AttributeString /** * Helper to get a value that will be JSON encoded - * The operation is the opposite to FromJSONToValue - */ + * The operation is the opposite to FromJSONToValue + */ public function GetForJSON($value) { return $value; @@ -4271,7 +4273,7 @@ class AttributeEnum extends AttributeString /** * An enum can be localized - */ + */ public function MakeValueFromString($sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null) { if ($bLocalizedValue) @@ -4315,11 +4317,11 @@ class AttributeEnum extends AttributeString if ($proposedValue == '') return null; return parent::MakeRealValue($proposedValue, $oHostObj); } - + public function GetOrderByHint() { $aValues = $this->GetAllowedValues(); - + return Dict::Format('UI:OrderByHint_Values', implode(', ', $aValues)); } } @@ -4452,7 +4454,7 @@ class AttributeMetaEnum extends AttributeEnum } } /** - * Map a date+time column to an attribute + * Map a date+time column to an attribute * * @package iTopORM */ @@ -4470,11 +4472,11 @@ class AttributeDateTime extends AttributeDBField { if (self::$oFormat == null) { - static::LoadFormatFromConfig(); + static::LoadFormatFromConfig(); } return self::$oFormat; - } - + } + /** * Load the 3 settings: date format, time format and data_time format from the configuration */ @@ -4485,13 +4487,13 @@ class AttributeDateTime extends AttributeDBField $sDateFormat = isset($aFormats[$sLang]['date']) ? $aFormats[$sLang]['date'] : (isset($aFormats['default']['date']) ? $aFormats['default']['date'] : 'Y-m-d'); $sTimeFormat = isset($aFormats[$sLang]['time']) ? $aFormats[$sLang]['time'] : (isset($aFormats['default']['time']) ? $aFormats['default']['time'] : 'H:i:s'); $sDateAndTimeFormat = isset($aFormats[$sLang]['date_time']) ? $aFormats[$sLang]['date_time'] : (isset($aFormats['default']['date_time']) ? $aFormats['default']['date_time'] : '$date $time'); - + $sFullFormat = str_replace(array('$date', '$time'), array($sDateFormat, $sTimeFormat), $sDateAndTimeFormat); - + self::SetFormat(new DateTimeFormat($sFullFormat)); - AttributeDate::SetFormat(new DateTimeFormat($sDateFormat)); + AttributeDate::SetFormat(new DateTimeFormat($sDateFormat)); } - + /** * Returns the format string used for the date & time stored in memory * @return string @@ -4509,17 +4511,17 @@ class AttributeDateTime extends AttributeDBField { return 'Y-m-d H:i:s'; } - + static public function SetFormat(DateTimeFormat $oDateTimeFormat) { self::$oFormat = $oDateTimeFormat; } - + static public function GetSQLTimeFormat() { return 'H:i:s'; } - + /** * Parses a search string coming from user input * @param string $sSearchString @@ -4535,7 +4537,7 @@ class AttributeDateTime extends AttributeDBField catch(Exception $e) { $sFormatString = '!'.(string)AttributeDate::GetFormat(); // BEWARE: ! is needed to set non-parsed fields to zero !!! - $oDateTime = DateTime::createFromFormat($sFormatString, $sSearchString); + $oDateTime = DateTime::createFromFormat($sFormatString, $sSearchString); if ($oDateTime !== false) { $sSearchString = $oDateTime->format($this->GetInternalFormat()); @@ -4543,12 +4545,12 @@ class AttributeDateTime extends AttributeDBField } return $sSearchString; } - + static public function GetFormFieldClass() { return '\\Combodo\\iTop\\Form\\Field\\DateTimeField'; } - + /** * Override to specify Field class * @@ -4619,12 +4621,12 @@ class AttributeDateTime extends AttributeDBField public function GetEditValue($sValue, $oHostObj = null) { return (string)static::GetFormat()->format($sValue); - } + } public function GetValueLabel($sValue, $oHostObj = null) { return (string)static::GetFormat()->format($sValue); - } - + } + protected function GetSQLCol($bFullSpec = false) {return "DATETIME";} public function GetImportColumns() @@ -4708,7 +4710,7 @@ class AttributeDateTime extends AttributeDBField return $this->GetSQLExpr()." = $sQValue"; } } - + public function MakeRealValue($proposedValue, $oHostObj) { if (is_null($proposedValue)) @@ -4741,7 +4743,7 @@ class AttributeDateTime extends AttributeDBField public function ScalarToSQL($value) { if (empty($value)) - { + { return null; } return $value; @@ -4801,7 +4803,7 @@ class AttributeDateTime extends AttributeDBField 'less than or equal' => array('pattern' => '/^<=(.*)$/', 'operator' => '<='), 'less than' => array('pattern' => '/^<(.*)$/', 'operator' => '<'), ); - + $sPatternFound = ''; $aMatches = array(); foreach($aPatterns as $sPatName => $sPattern) @@ -4810,13 +4812,13 @@ class AttributeDateTime extends AttributeDBField { $sPatternFound = $sPatName; break; - } + } } - + switch($sPatternFound) { case 'between': - + $sParamName1 = $oField->GetParent().'_'.$oField->GetName().'_1'; $oRightExpr = new VariableExpression($sParamName1); if ($bParseSearchString) @@ -4840,10 +4842,10 @@ class AttributeDateTime extends AttributeDBField $aParams[$sParamName2] = $aMatches[2]; } $oCondition2 = new BinaryExpression($oField, '<=', $oRightExpr); - + $oNewCondition = new BinaryExpression($oCondition1, 'AND', $oCondition2); break; - + case 'greater than': case 'greater than or equal': case 'less than': @@ -4860,9 +4862,9 @@ class AttributeDateTime extends AttributeDBField $aParams[$sParamName] = $aMatches[1]; } $oNewCondition = new BinaryExpression($oField, $sSQLOperator, $oRightExpr); - + break; - + default: $oNewCondition = parent::GetSmartConditionExpression($sSearchText, $oField, $aParams); @@ -4875,15 +4877,15 @@ class AttributeDateTime extends AttributeDBField public function GetHelpOnSmartSearch() { $sDict = parent::GetHelpOnSmartSearch(); - + $oFormat = static::GetFormat(); $sExample = $oFormat->Format(new DateTime('2015-07-19 18:40:00')); return vsprintf($sDict, array($oFormat->ToPlaceholder(), $sExample)); - } + } } /** - * Store a duration as a number of seconds + * Store a duration as a number of seconds * * @package iTopORM */ @@ -4906,7 +4908,7 @@ class AttributeDuration extends AttributeInteger public function ScalarToSQL($value) { if (is_null($value)) - { + { return null; } return $value; @@ -4924,26 +4926,26 @@ class AttributeDuration extends AttributeInteger if ($duration < 60) { // Less than 1 min - $sResult = Dict::Format('Core:Duration_Seconds', $aDuration['seconds']); + $sResult = Dict::Format('Core:Duration_Seconds', $aDuration['seconds']); } else if ($duration < 3600) { // less than 1 hour, display it in minutes/seconds - $sResult = Dict::Format('Core:Duration_Minutes_Seconds', $aDuration['minutes'], $aDuration['seconds']); + $sResult = Dict::Format('Core:Duration_Minutes_Seconds', $aDuration['minutes'], $aDuration['seconds']); } else if ($duration < 86400) { - // Less than 1 day, display it in hours/minutes/seconds - $sResult = Dict::Format('Core:Duration_Hours_Minutes_Seconds', $aDuration['hours'], $aDuration['minutes'], $aDuration['seconds']); + // Less than 1 day, display it in hours/minutes/seconds + $sResult = Dict::Format('Core:Duration_Hours_Minutes_Seconds', $aDuration['hours'], $aDuration['minutes'], $aDuration['seconds']); } else { // more than 1 day, display it in days/hours/minutes/seconds - $sResult = Dict::Format('Core:Duration_Days_Hours_Minutes_Seconds', $aDuration['days'], $aDuration['hours'], $aDuration['minutes'], $aDuration['seconds']); + $sResult = Dict::Format('Core:Duration_Days_Hours_Minutes_Seconds', $aDuration['days'], $aDuration['hours'], $aDuration['minutes'], $aDuration['seconds']); } return $sResult; } - + static function SplitDuration($duration) { $duration = (int) $duration; @@ -4951,7 +4953,7 @@ class AttributeDuration extends AttributeInteger $hours = floor(($duration - (86400*$days)) / 3600); $minutes = floor(($duration - (86400*$days + 3600*$hours)) / 60); $seconds = ($duration % 60); // modulo - return array( 'days' => $days, 'hours' => $hours, 'minutes' => $minutes, 'seconds' => $seconds ); + return array( 'days' => $days, 'hours' => $hours, 'minutes' => $minutes, 'seconds' => $seconds ); } static public function GetFormFieldClass() @@ -4978,7 +4980,7 @@ class AttributeDuration extends AttributeInteger } /** - * Map a date+time column to an attribute + * Map a date+time column to an attribute * * @package iTopORM */ @@ -4987,12 +4989,12 @@ class AttributeDate extends AttributeDateTime const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_DATE; static $oDateFormat = null; - + static public function GetFormat() { if (self::$oDateFormat == null) - { - AttributeDateTime::LoadFormatFromConfig(); + { + AttributeDateTime::LoadFormatFromConfig(); } return self::$oDateFormat; } @@ -5019,7 +5021,7 @@ class AttributeDate extends AttributeDateTime { return 'Y-m-d'; } - + static public function ListExpectedParams() { return parent::ListExpectedParams(); @@ -5046,10 +5048,10 @@ class AttributeDate extends AttributeDateTime { $oFormField = parent::MakeFormField($oObject, $oFormField); $oFormField->SetDateOnly(true); - + return $oFormField; } - + } /** @@ -5073,7 +5075,7 @@ class AttributeDeadline extends AttributeDateTime $iValue = AttributeDateTime::GetAsUnixSeconds($value); $sDate = AttributeDateTime::GetFormat()->Format($value); $difference = $iValue - time(); - + if ($difference >= 0) { $sDifference = self::FormatDuration($difference); @@ -5098,29 +5100,29 @@ class AttributeDeadline extends AttributeDateTime if ($duration < 60) { // Less than 1 min - $sResult =Dict::S('UI:Deadline_LessThan1Min'); + $sResult =Dict::S('UI:Deadline_LessThan1Min'); } else if ($duration < 3600) { // less than 1 hour, display it in minutes - $sResult =Dict::Format('UI:Deadline_Minutes', $minutes); + $sResult =Dict::Format('UI:Deadline_Minutes', $minutes); } else if ($duration < 86400) { - // Less that 1 day, display it in hours/minutes - $sResult =Dict::Format('UI:Deadline_Hours_Minutes', $hours, $minutes); + // Less that 1 day, display it in hours/minutes + $sResult =Dict::Format('UI:Deadline_Hours_Minutes', $hours, $minutes); } else { - // Less that 1 day, display it in hours/minutes - $sResult =Dict::Format('UI:Deadline_Days_Hours_Minutes', $days, $hours, $minutes); + // Less that 1 day, display it in hours/minutes + $sResult =Dict::Format('UI:Deadline_Days_Hours_Minutes', $days, $hours, $minutes); } return $sResult; } } /** - * Map a foreign key to an attribute + * Map a foreign key to an attribute * AttributeExternalKey and AttributeExternalField may be an external key * the difference is that AttributeExternalKey corresponds to a column into the defined table * where an AttributeExternalField corresponds to a column into another table (class) @@ -5171,9 +5173,9 @@ class AttributeExternalKey extends AttributeDBFieldVoid public function IsExternalKey($iType = EXTKEY_RELATIVE) {return true;} public function GetTargetClass($iType = EXTKEY_RELATIVE) {return $this->Get("targetclass");} public function GetKeyAttDef($iType = EXTKEY_RELATIVE){return $this;} - public function GetKeyAttCode() {return $this->GetCode();} + public function GetKeyAttCode() {return $this->GetCode();} public function GetDisplayStyle() { return $this->GetOptional('display_style', 'select'); } - + public function GetDefaultValue(DBObject $oHostObject = null) {return 0;} public function IsNullAllowed() @@ -5198,7 +5200,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid public function GetBasicFilterSQLExpr($sOpCode, $value) { return parent::GetBasicFilterSQLExpr($sOpCode, $value); - } + } // overloaded here so that an ext key always have the answer to // "what are your possible values?" @@ -5248,12 +5250,12 @@ class AttributeExternalKey extends AttributeDBFieldVoid public function GetNullValue() { return 0; - } + } public function IsNull($proposedValue) { return ($proposedValue == 0); - } + } public function MakeRealValue($proposedValue, $oHostObj) { @@ -5262,17 +5264,17 @@ class AttributeExternalKey extends AttributeDBFieldVoid if (MetaModel::IsValidObject($proposedValue)) return $proposedValue->GetKey(); return (int)$proposedValue; } - + public function GetMaximumComboLength() { return $this->GetOptional('max_combo_length', MetaModel::GetConfig()->Get('max_combo_length')); } - + public function GetMinAutoCompleteChars() { return $this->GetOptional('min_autocomplete_chars', MetaModel::GetConfig()->Get('min_autocomplete_chars')); } - + public function AllowTargetCreation() { return $this->GetOptional('allow_target_creation', MetaModel::GetConfig()->Get('allow_target_creation')); @@ -5311,7 +5313,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid $sFormFieldClass = static::GetFormFieldClass(); $oFormField = new $sFormFieldClass($this->GetCode()); } - + // Setting params $oFormField->SetMaximumComboLength($this->GetMaximumComboLength()); $oFormField->SetMinAutoCompleteChars($this->GetMinAutoCompleteChars()); @@ -5505,7 +5507,7 @@ class AttributeHierarchicalKey extends AttributeExternalKey } /** - * An attribute which corresponds to an external key (direct or indirect) + * An attribute which corresponds to an external key (direct or indirect) * * @package iTopORM */ @@ -5558,14 +5560,14 @@ class AttributeExternalField extends AttributeDefinition public function GetFinalAttDef() { $oExtAttDef = $this->GetExtAttDef(); - return $oExtAttDef->GetFinalAttDef(); + return $oExtAttDef->GetFinalAttDef(); } protected function GetSQLCol($bFullSpec = false) { // throw new CoreException("external attribute: does it make any sense to request its type ?"); $oExtAttDef = $this->GetExtAttDef(); - return $oExtAttDef->GetSQLCol($bFullSpec); + return $oExtAttDef->GetSQLCol($bFullSpec); } public function GetSQLExpressions($sPrefix = '') @@ -5577,7 +5579,7 @@ class AttributeExternalField extends AttributeDefinition else { return $sPrefix; - } + } } public function GetLabel($sDefault = null) @@ -5625,7 +5627,7 @@ class AttributeExternalField extends AttributeDefinition $sLabel = $oRemoteAtt->GetDescription(''); } return $sLabel; - } + } public function GetHelpOnEdition($sDefault = null) { $sLabel = parent::GetHelpOnEdition(''); @@ -5635,7 +5637,7 @@ class AttributeExternalField extends AttributeDefinition $sLabel = $oRemoteAtt->GetHelpOnEdition(''); } return $sLabel; - } + } public function IsExternalKey($iType = EXTKEY_RELATIVE) { @@ -5727,7 +5729,7 @@ class AttributeExternalField extends AttributeDefinition throw new CoreException("Unexpected value for argument iType: '$iType'"); } } - + public function GetPrerequisiteAttributes($sClass = null) { return array($this->Get("extkey_attcode")); @@ -5755,8 +5757,8 @@ class AttributeExternalField extends AttributeDefinition public function GetSQLExpr() { $oExtAttDef = $this->GetExtAttDef(); - return $oExtAttDef->GetSQLExpr(); - } + return $oExtAttDef->GetSQLExpr(); + } public function GetDefaultValue(DBObject $oHostObject = null) { @@ -5766,7 +5768,7 @@ class AttributeExternalField extends AttributeDefinition public function IsNullAllowed() { $oExtAttDef = $this->GetExtAttDef(); - return $oExtAttDef->IsNullAllowed(); + return $oExtAttDef->IsNullAllowed(); } static public function IsScalar() @@ -5782,31 +5784,31 @@ class AttributeExternalField extends AttributeDefinition public function GetBasicFilterOperators() { $oExtAttDef = $this->GetExtAttDef(); - return $oExtAttDef->GetBasicFilterOperators(); + return $oExtAttDef->GetBasicFilterOperators(); } public function GetBasicFilterLooseOperator() { $oExtAttDef = $this->GetExtAttDef(); - return $oExtAttDef->GetBasicFilterLooseOperator(); + return $oExtAttDef->GetBasicFilterLooseOperator(); } public function GetBasicFilterSQLExpr($sOpCode, $value) { $oExtAttDef = $this->GetExtAttDef(); return $oExtAttDef->GetBasicFilterSQLExpr($sOpCode, $value); - } + } public function GetNullValue() { $oExtAttDef = $this->GetExtAttDef(); return $oExtAttDef->GetNullValue(); - } + } public function IsNull($proposedValue) { $oExtAttDef = $this->GetExtAttDef(); return $oExtAttDef->IsNull($proposedValue); - } + } public function MakeRealValue($proposedValue, $oHostObj) { @@ -5909,7 +5911,8 @@ class AttributeExternalField extends AttributeDefinition */ class AttributeTagSet extends AttributeDBFieldVoid { - const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_STRING; + const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_TAG_SET; + static public function ListExpectedParams() { return array_merge(parent::ListExpectedParams(), array("is_null_allowed")); @@ -5923,16 +5926,18 @@ class AttributeTagSet extends AttributeDBFieldVoid public function GetEditValue($value, $oHostObj = null) { - if (empty($value)) - { - return ''; - } - if ($value instanceof ormTagSet) - { - $aValues = $value->GetValue(); - return implode(' ', $aValues); - } - return ''; + if (empty($value)) + { + return ''; + } + if ($value instanceof ormTagSet) + { + $aValues = $value->GetValue(); + + return implode(' ', $aValues); + } + + return ''; } protected function GetSQLCol($bFullSpec = false) @@ -5959,6 +5964,19 @@ class AttributeTagSet extends AttributeDBFieldVoid return ($val1 == $val2); } + public function GetAllowedValues($aArgs = array(), $sContains = '') + { + $sAttCode = $this->GetCode(); + $sClass = MetaModel::GetAttributeOrigin($this->GetHostClass(), $sAttCode); + $aAllowedTags = TagSetFieldData::GetAllowedValues($sClass, $sAttCode); + $aAllowedValues = array(); + foreach($aAllowedTags as $oAllowedTag) + { + $aAllowedValues[$oAllowedTag->Get('tag_code')] = $oAllowedTag->Get('tag_label'); + } + return $aAllowedValues; + } + /** * @param array $aCols * @param string $sPrefix @@ -6048,19 +6066,46 @@ class AttributeTagSet extends AttributeDBFieldVoid return count($proposedValue->GetValue()) == 0; } - /** - * To be overloaded for localized enums - * - * @param $sValue - * - * @return string label corresponding to the given value (in plain text) - */ + /** + * To be overloaded for localized enums + * + * @param $sValue + * + * @return string label corresponding to the given value (in plain text) + * @throws \CoreWarning + * @throws \Exception + */ public function GetValueLabel($sValue) { - return $sValue; + if (empty($sValue)) + { + return ''; + } + if (is_string($sValue)) + { + $sValue = $this->MakeRealValue($sValue, null); + } + if ($sValue instanceof ormTagSet) + { + $aValues = $sValue->GetTags(); + return implode(' ', $aValues); + } + throw new CoreWarning('Expected the attribute value to be a TagSet', array('found_type' => gettype($sValue), 'value' => $sValue, 'class' => $this->GetHostClass(), 'attribute' => $this->GetCode())); } - /** + /** + * @param string $sValue + * @param null $oHostObj + * + * @return string + * @throws \CoreWarning + */ + public function GetAsPlainText($sValue, $oHostObj = null) + { + return $this->GetValueLabel($sValue); + } + + /** * @param $value * * @return string @@ -6339,7 +6384,7 @@ class AttributeTagSet extends AttributeDBFieldVoid } /** - * Map a varchar column to an URL (formats the ouput in HMTL) + * Map a varchar column to an URL (formats the ouput in HMTL) * * @package iTopORM */ @@ -6362,7 +6407,7 @@ class AttributeURL extends AttributeString { return 2048; } - + public function GetEditClass() {return "String";} public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true) @@ -6411,7 +6456,7 @@ class AttributeURL extends AttributeString } /** - * A blob is an ormDocument, it is stored as several columns in the database + * A blob is an ormDocument, it is stored as several columns in the database * * @package iTopORM */ @@ -6436,7 +6481,7 @@ class AttributeBlob extends AttributeDefinition { return ''; } - + /** * Users can provide the document from an URL (including an URL on iTop itself) * for CSV import. Administrators can even provide the path to a local file @@ -6446,7 +6491,7 @@ class AttributeBlob extends AttributeDefinition public function MakeRealValue($proposedValue, $oHostObj) { if ($proposedValue === null) return null; - + if (is_object($proposedValue)) { $proposedValue = clone $proposedValue; @@ -6463,7 +6508,7 @@ class AttributeBlob extends AttributeDefinition IssueLog::Warning(get_class($this)."::MakeRealValue - ".$e->getMessage()); // Not a real document !! store is as text !!! (This was the default behavior before) $proposedValue = new ormDocument($e->getMessage()." \n".$proposedValue, 'text/plain'); - } + } } return $proposedValue; } @@ -6488,21 +6533,21 @@ class AttributeBlob extends AttributeDefinition { $sAvailable = implode(', ', array_keys($aCols)); throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}"); - } + } $sMimeType = isset($aCols[$sPrefix]) ? $aCols[$sPrefix] : ''; - if (!array_key_exists($sPrefix.'_data', $aCols)) + if (!array_key_exists($sPrefix.'_data', $aCols)) { $sAvailable = implode(', ', array_keys($aCols)); throw new MissingColumnException("Missing column '".$sPrefix."_data' from {$sAvailable}"); - } + } $data = isset($aCols[$sPrefix.'_data']) ? $aCols[$sPrefix.'_data'] : null; - if (!array_key_exists($sPrefix.'_filename', $aCols)) + if (!array_key_exists($sPrefix.'_filename', $aCols)) { $sAvailable = implode(', ', array_keys($aCols)); throw new MissingColumnException("Missing column '".$sPrefix."_filename' from {$sAvailable}"); - } + } $sFileName = isset($aCols[$sPrefix.'_filename']) ? $aCols[$sPrefix.'_filename'] : ''; $value = new ormDocument($data, $sMimeType, $sFileName); @@ -6560,7 +6605,7 @@ class AttributeBlob extends AttributeDefinition public function GetBasicFilterSQLExpr($sOpCode, $value) { return 'true'; - } + } public function GetAsHTML($value, $oHostObject = null, $bLocalize = true) { @@ -6615,8 +6660,8 @@ class AttributeBlob extends AttributeDefinition /** * Helper to get a value that will be JSON encoded - * The operation is the opposite to FromJSONToValue - */ + * The operation is the opposite to FromJSONToValue + */ public function GetForJSON($value) { if ($value instanceOf ormDocument) @@ -6635,8 +6680,8 @@ class AttributeBlob extends AttributeDefinition /** * Helper to form a value, given JSON decoded data - * The operation is the opposite to GetForJSON - */ + * The operation is the opposite to GetForJSON + */ public function FromJSONToValue($json) { if (isset($json->data)) @@ -6650,7 +6695,7 @@ class AttributeBlob extends AttributeDefinition } return $value; } - + public function Fingerprint($value) { $sFingerprint = ''; @@ -6658,7 +6703,7 @@ class AttributeBlob extends AttributeDefinition { $sFingerprint = md5($value->GetData()); } - return $sFingerprint; + return $sFingerprint; } static public function GetFormFieldClass() @@ -6708,7 +6753,7 @@ class AttributeImage extends AttributeBlob // The validation of the MIME Type is done by CheckFormat below return $oDoc; } - + /** * Check that the supplied ormDocument actually contains an image * {@inheritDoc} @@ -6722,7 +6767,7 @@ class AttributeImage extends AttributeBlob } return true; } - + public function GetAsHTML($value, $oHostObject = null, $bLocalize = true) { $iMaxWidthPx = $this->Get('display_max_width').'px'; @@ -6778,7 +6823,7 @@ class AttributeImage extends AttributeBlob } } /** - * A stop watch is an ormStopWatch object, it is stored as several columns in the database + * A stop watch is an ormStopWatch object, it is stored as several columns in the database * * @package iTopORM */ @@ -6823,7 +6868,7 @@ class AttributeStopWatch extends AttributeDefinition /** * Construct a brand new (but configured) stop watch - */ + */ public function NewStopWatch() { $oSW = new ormStopWatch(); @@ -6904,7 +6949,7 @@ class AttributeStopWatch extends AttributeDefinition { $sAvailable = implode(', ', array_keys($aCols)); throw new MissingColumnException("Missing column '$sExpectedCol' from {$sAvailable}"); - } + } } $value = new ormStopWatch( @@ -7058,7 +7103,7 @@ class AttributeStopWatch extends AttributeDefinition { return $this->Get('thresholds'); } - + public function Fingerprint($value) { $sFingerprint = ''; @@ -7498,7 +7543,7 @@ class AttributeStopWatch extends AttributeDefinition * If an attribute implements the verbs GetSubItem.... then it can expose * internal values, each of them being an attribute and therefore they * can be displayed at different times in the object lifecycle, and used for - * reporting (as a condition in OQL, or as an additional column in an export) + * reporting (as a condition in OQL, or as an additional column in an export) * Known usages: Stop Watches can expose threshold statuses */ class AttributeSubItem extends AttributeDefinition @@ -7510,11 +7555,11 @@ class AttributeSubItem extends AttributeDefinition return array_merge(parent::ListExpectedParams(), array('target_attcode', 'item_code')); } - public function GetParentAttCode() {return $this->Get("target_attcode");} + public function GetParentAttCode() {return $this->Get("target_attcode");} /** - * Helper : get the attribute definition to which the execution will be forwarded - */ + * Helper : get the attribute definition to which the execution will be forwarded + */ public function GetTargetAttDef() { $sClass = $this->GetHostClass(); @@ -7523,7 +7568,7 @@ class AttributeSubItem extends AttributeDefinition } public function GetEditClass() {return "";} - + public function GetValuesDef() {return null;} static public function IsBasedOnDBColumns() {return true;} @@ -7589,7 +7634,7 @@ class AttributeSubItem extends AttributeDefinition default: return $this->GetSQLExpr()." = $sQValue"; } - } + } public function GetSQLExpressions($sPrefix = '') { @@ -7625,7 +7670,7 @@ class AttributeSubItem extends AttributeDefinition $res = $oParent->GetSubItemAsCSV($this->Get('item_code'), $value, $sSeparator, $sTextQualifier, $bConvertToPlainText); return $res; } - + public function GetAsXML($value, $oHostObject = null, $bLocalize = true) { $oParent = $this->GetTargetAttDef(); @@ -7635,14 +7680,14 @@ class AttributeSubItem extends AttributeDefinition /** * As of now, this function must be implemented to have the value in spreadsheet format - */ + */ public function GetEditValue($value, $oHostObj = null) { $oParent = $this->GetTargetAttDef(); $res = $oParent->GetSubItemAsEditValue($this->Get('item_code'), $value); return $res; } - + public function IsPartOfFingerprint() { return false; @@ -7727,14 +7772,14 @@ class AttributeOneWayPassword extends AttributeDefinition { $sAvailable = implode(', ', array_keys($aCols)); throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}"); - } + } $hashed = isset($aCols[$sPrefix]) ? $aCols[$sPrefix] : ''; - if (!array_key_exists($sPrefix.'_salt', $aCols)) + if (!array_key_exists($sPrefix.'_salt', $aCols)) { $sAvailable = implode(', ', array_keys($aCols)); throw new MissingColumnException("Missing column '".$sPrefix."_salt' from {$sAvailable}"); - } + } $sSalt = isset($aCols[$sPrefix.'_salt']) ? $aCols[$sPrefix.'_salt'] : ''; $value = new ormPassword($hashed, $sSalt); @@ -7785,7 +7830,7 @@ class AttributeOneWayPassword extends AttributeDefinition { $sAvailable = implode(', ', array_keys($aCols)); throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}"); - } + } $sClearPwd = $aCols[$sPrefix]; $oPassword = new ormPassword('', ''); @@ -7811,7 +7856,7 @@ class AttributeOneWayPassword extends AttributeDefinition public function GetBasicFilterSQLExpr($sOpCode, $value) { return 'true'; - } + } public function GetAsHTML($value, $oHostObject = null, $bLocalize = true) { @@ -7826,18 +7871,18 @@ class AttributeOneWayPassword extends AttributeDefinition { return ''; // Not exportable in CSV } - + public function GetAsXML($value, $oHostObject = null, $bLocalize = true) { return ''; // Not exportable in XML } - + public function GetValueLabel($sValue, $oHostObj = null) { // Don't display anything in "group by" reports return '*****'; } - + } // Indexed array having two dimensions @@ -7860,12 +7905,12 @@ class AttributeTable extends AttributeDBField public function GetNullValue() { return array(); - } + } public function IsNull($proposedValue) { return (count($proposedValue) == 0); - } + } public function GetEditValue($sValue, $oHostObj = null) { @@ -8062,13 +8107,13 @@ class AttributePropertySet extends AttributeTable } /** - * The attribute dedicated to the friendly name automatic attribute (not written) + * The attribute dedicated to the friendly name automatic attribute (not written) * * @package iTopORM */ /** - * The attribute dedicated to the friendly name automatic attribute (not written) + * The attribute dedicated to the friendly name automatic attribute (not written) * * @package iTopORM */ @@ -8128,7 +8173,7 @@ class AttributeFriendlyName extends AttributeDefinition $sLabel = Dict::S('Core:FriendlyName-Description'); } return $sLabel; - } + } public function FromSQLToValue($aCols, $sPrefix = '') { @@ -8228,7 +8273,7 @@ class AttributeFriendlyName extends AttributeDefinition return $this->GetSQLExpr()." LIKE $sQValue"; } } - + public function IsPartOfFingerprint() { return false; } } @@ -8250,7 +8295,7 @@ class AttributeRedundancySettings extends AttributeDBField return array('sql', 'relation_code', 'from_class', 'neighbour_id', 'enabled', 'enabled_mode', 'min_up', 'min_up_type', 'min_up_mode'); } - public function GetValuesDef() {return null;} + public function GetValuesDef() {return null;} public function GetPrerequisiteAttributes($sClass = null) {return array();} public function GetEditClass() {return "RedundancySetting";} @@ -8292,17 +8337,17 @@ class AttributeRedundancySettings extends AttributeDBField public function IsNullAllowed() { return false; - } + } public function GetNullValue() { return ''; - } + } public function IsNull($proposedValue) { return ($proposedValue == ''); - } + } public function MakeRealValue($proposedValue, $oHostObj) { @@ -8386,8 +8431,8 @@ class AttributeRedundancySettings extends AttributeDBField } /** - * Helper to interpret the value, given the current settings and string representation of the attribute - */ + * Helper to interpret the value, given the current settings and string representation of the attribute + */ public function IsEnabled($sValue) { if ($this->get('enabled_mode') == 'fixed') @@ -8402,8 +8447,8 @@ class AttributeRedundancySettings extends AttributeDBField } /** - * Helper to interpret the value, given the current settings and string representation of the attribute - */ + * Helper to interpret the value, given the current settings and string representation of the attribute + */ public function GetMinUpType($sValue) { if ($this->get('min_up_mode') == 'fixed') @@ -8422,8 +8467,8 @@ class AttributeRedundancySettings extends AttributeDBField } /** - * Helper to interpret the value, given the current settings and string representation of the attribute - */ + * Helper to interpret the value, given the current settings and string representation of the attribute + */ public function GetMinUpValue($sValue) { if ($this->get('min_up_mode') == 'fixed') @@ -8444,7 +8489,7 @@ class AttributeRedundancySettings extends AttributeDBField /** * Helper to determine if the redundancy can be viewed/edited by the end-user - */ + */ public function IsVisible() { $bRet = false; @@ -8470,7 +8515,7 @@ class AttributeRedundancySettings extends AttributeDBField /** * Returns an HTML form that can be read by ReadValueFromPostedForm - */ + */ public function GetDisplayForm($sCurrentValue, $oPage, $bEditMode = false, $sFormPrefix = '') { $sRet = ''; @@ -8500,7 +8545,7 @@ class AttributeRedundancySettings extends AttributeDBField /** * Depending on the xxx_mode parameters, build the list of options that are allowed to the end-user - */ + */ protected function GetUserOptions($sValue) { $aRet = array(); @@ -8508,7 +8553,7 @@ class AttributeRedundancySettings extends AttributeDBField { $aRet[] = self::USER_OPTION_DISABLED; } - + if ($this->Get('min_up_mode') == 'user') { $aRet[] = self::USER_OPTION_ENABLED_COUNT; @@ -8529,8 +8574,8 @@ class AttributeRedundancySettings extends AttributeDBField } /** - * Convert the string representation into one of the existing options - */ + * Convert the string representation into one of the existing options + */ protected function GetCurrentOption($sValue) { $sRet = self::USER_OPTION_DISABLED; @@ -8577,7 +8622,7 @@ class AttributeRedundancySettings extends AttributeDBField case self::USER_OPTION_DISABLED: $sValue = ''; // Empty placeholder break; - + case self::USER_OPTION_ENABLED_COUNT: if ($bEditMode) { @@ -8592,7 +8637,7 @@ class AttributeRedundancySettings extends AttributeDBField $sValue = $iCurrentValue; } break; - + case self::USER_OPTION_ENABLED_PERCENT: if ($bEditMode) { @@ -8627,8 +8672,8 @@ class AttributeRedundancySettings extends AttributeDBField } /** - * Makes the string representation out of the values given by the form defined in GetDisplayForm - */ + * Makes the string representation out of the values given by the form defined in GetDisplayForm + */ public function ReadValueFromPostedForm($sFormPrefix) { $sHtmlNamesPrefix = 'rddcy_'.$this->Get('relation_code').'_'.$this->Get('from_class').'_'.$this->Get('neighbour_id'); @@ -8759,7 +8804,7 @@ class AttributeCustomFields extends AttributeDefinition $oFormField->SetForm($this->GetForm($oObject)); } parent::MakeFormField($oObject, $oFormField); - + return $oFormField; } diff --git a/core/oql/expression.class.inc.php b/core/oql/expression.class.inc.php index 6ba166916..aff3bd7b3 100644 --- a/core/oql/expression.class.inc.php +++ b/core/oql/expression.class.inc.php @@ -928,6 +928,24 @@ class ScalarExpression extends UnaryExpression IssueLog::Error($e->getMessage()); } break; + case ($oAttDef instanceof AttributeTagSet): + try + { + if (!empty($this->GetValue())) + { + /** @var AttributeTagSet $oAttDef */ + $aValue['label'] = $oAttDef->GetValueLabel($this->GetValue()); + } + else + { + $aValue['label'] = Dict::S('Enum:Undefined'); + } + } + catch (Exception $e) + { + IssueLog::Error($e->getMessage()); + } + break; case $oAttDef->IsExternalKey(): try { @@ -1575,7 +1593,7 @@ class ListExpression extends Expression { if ($oExpr instanceof VariableExpression) { - $this->m_aExpressions[$idx] = $oExpr->GetAsScalar(); + $this->m_aExpressions[$idx] = $oExpr->GetAsScalar($aArgs); } else { @@ -2119,7 +2137,7 @@ class CharConcatExpression extends Expression { if ($oExpr instanceof VariableExpression) { - $this->m_aExpressions[$idx] = $oExpr->GetAsScalar(); + $this->m_aExpressions[$idx] = $oExpr->GetAsScalar($aArgs); } else { diff --git a/css/light-grey.css b/css/light-grey.css index 3a3f3c7c5..d80c61feb 100644 --- a/css/light-grey.css +++ b/css/light-grey.css @@ -884,6 +884,9 @@ input.dp-applied { left: 0px; margin-top: -1px; } +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_buttons, .search_form_handler .sf_criterion_area .sf_more_criterion .sfc_form_group .sfc_fg_buttons, .search_form_handler .sf_criterion_area .sf_button .sfc_form_group .sfc_fg_buttons, .search_form_handler .sf_criterion_area .search_form_criteria .sfm_content .sfc_fg_buttons, .search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content .sfc_fg_buttons, .search_form_handler .sf_criterion_area .sf_button .sfm_content .sfc_fg_buttons { + white-space: nowrap; +} .search_form_handler .sf_criterion_area .search_form_criteria { /* Non editable criteria */ /* Draft criteria (modifications not applied) */ @@ -1127,6 +1130,15 @@ input.dp-applied { .search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_enum .sfc_form_group .sfc_fg_operator_in > label .sfc_op_content { width: 100%; } +.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_tag_set .sfc_form_group .sfc_fg_operator_in > label { + display: inline-block; + width: 100%; + line-height: initial; + white-space: nowrap; +} +.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_tag_set .sfc_form_group .sfc_fg_operator_in > label .sfc_op_content { + width: 100%; +} .search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_numeric .sfc_fg_operators .sfc_fg_operator.sfc_fg_operator_between .sfc_op_content_from_outer { display: inline; } @@ -2862,19 +2874,16 @@ table.listResults .originColor { .menu-icon-select > .ui-menu-item { padding: 0.3em 3%; } - .attribute-tagset > span, .attribute-tagset-undefined > span { display: inline-block; padding: 3px; margin-right: 3px; border-radius: 4px; } - .attribute-tagset > span { color: white; background-color: grey; } - .attribute-tagset-undefined > span { color: grey; background-color: lightgrey; diff --git a/css/light-grey.scss b/css/light-grey.scss index a84dbff38..20fb1ee0e 100644 --- a/css/light-grey.scss +++ b/css/light-grey.scss @@ -991,6 +991,10 @@ input.dp-applied { min-width: 100%; left: 0px; margin-top: -1px; + + .sfc_fg_buttons{ + white-space: nowrap; + } } } @@ -1304,6 +1308,22 @@ input.dp-applied { } } } + &.search_form_criteria_tag_set{ + .sfc_form_group{ + .sfc_fg_operator_in{ + > label{ + display: inline-block; + width: 100%; + line-height: initial; + white-space: nowrap; + + .sfc_op_content{ + width: 100%; + } + } + } + } + } &.search_form_criteria_numeric { //.sfc_form_group.advanced { // .sfc_fg_operator_between { diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php index c9c8497c4..1e61d44fd 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -1447,6 +1447,8 @@ When associated with a trigger, each action is given an "order" number, specifyi 'UI:Search:Criteria:Title:Enum:In' => '%1$s: %2$s', 'UI:Search:Criteria:Title:Enum:In:Many' => '%1$s: %2$s and %3$s others', 'UI:Search:Criteria:Title:Enum:In:All' => '%1$s: Any', + // - TagSet widget + 'UI:Search:Criteria:Title:TagSet:Matches' => '%1$s: %2$s', // - External key widget 'UI:Search:Criteria:Title:ExternalKey:Empty' => '%1$s is defined', 'UI:Search:Criteria:Title:ExternalKey:NotEmpty' => '%1$s is not defined', @@ -1480,6 +1482,8 @@ When associated with a trigger, each action is given an "order" number, specifyi 'UI:Search:Criteria:Operator:Numeric:LessThan' => 'Less', // => '<', 'UI:Search:Criteria:Operator:Numeric:LessThanOrEquals' => 'Less / equals', // > '<=', 'UI:Search:Criteria:Operator:Numeric:Different' => 'Different', // => '≠', + // - Tag Set Widget + 'UI:Search:Criteria:Operator:TagSet:Matches' => 'Matches', // - Other translations 'UI:Search:Value:Filter:Placeholder' => 'Filter...', diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php index cac02df9d..82159bc78 100644 --- a/dictionaries/fr.dictionary.itop.ui.php +++ b/dictionaries/fr.dictionary.itop.ui.php @@ -1280,6 +1280,8 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé 'UI:Search:Criteria:Title:Enum:In' => '%1$s : %2$s', 'UI:Search:Criteria:Title:Enum:In:Many' => '%1$s : %2$s et %3$s autres', 'UI:Search:Criteria:Title:Enum:In:All' => '%1$s : Indifférent', + // - TagSet widget + 'UI:Search:Criteria:Title:TagSet:Matches' => '%1$s : %2$s', // - External key widget 'UI:Search:Criteria:Title:ExternalKey:Empty' => '%1$s est renseigné', 'UI:Search:Criteria:Title:ExternalKey:NotEmpty' => '%1$s n\'est pas renseigné', @@ -1294,6 +1296,8 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé 'UI:Search:Criteria:Title:HierarchicalKey:In' => '%1$s : %2$s', 'UI:Search:Criteria:Title:HierarchicalKey:In:Many' => '%1$s : %2$s et %3$s autres', 'UI:Search:Criteria:Title:HierarchicalKey:In:All' => '%1$s : Indifférent', + // - Tag Set Widget + 'UI:Search:Criteria:Operator:TagSet:Matches' => 'Contient', /// - Criteria operators // - Default widget diff --git a/js/search/search_form_criteria_tag_set.js b/js/search/search_form_criteria_tag_set.js new file mode 100644 index 000000000..999108ff8 --- /dev/null +++ b/js/search/search_form_criteria_tag_set.js @@ -0,0 +1,86 @@ +//iTop Search form criteria tag_set +; +$(function() +{ + // the widget definition, where 'itop' is the namespace, + // 'search_form_criteria_tag_set' the widget name + $.widget( 'itop.search_form_criteria_tag_set', $.itop.search_form_criteria_enum, + { + // default options + options: + { + // Overload default operator + 'operator': 'MATCHES', + // Available operators + 'available_operators': { + 'MATCHES': { + 'label': Dict.S('UI:Search:Criteria:Operator:TagSet:MATCHES'), + 'code': 'matches', + 'rank': 10, + }, + 'IN': null, + '=': null, // Remove this one from tag_set widget. + 'empty': null, // Remove as it will be handle by the "null" value in the "MATCHES" operator + 'not_empty': null, // Remove as it will be handle by the "null" value in the "MATCHES" operator + }, + }, + + + // the constructor + _create: function() + { + var me = this; + + this._super(); + this.element.addClass('search_form_criteria_tag_set'); + }, + // called when created, and later when changing options + _refresh: function() + { + + }, + // events bound via _bind are removed automatically + // revert other modifications here + _destroy: function() + { + this.element.removeClass('search_form_criteria_tag_set'); + this._super(); + }, + // _setOptions is called with a hash of all options that are changing + // always refresh when changing options + _setOptions: function() + { + this._superApply(arguments); + }, + // _setOption is called for each individual option that is changing + _setOption: function( key, value ) + { + this._super( key, value ); + }, + + //------------------ + // Inherited methods + //------------------ + _prepareMatchesOperator: function(oOpElem, sOpIdx, oOp) + { + this._prepareInOperator(oOpElem, sOpIdx, oOp); + }, + + // Operators helpers + // Reset operator's state + _resetMatchesOperator: function(oOpElem) + { + this._resetInOperator(oOpElem); + }, + // Get operator's values + _getMatchesOperatorValues: function(oOpElem) + { + return this._getInOperatorValues(oOpElem); + }, + // Set operator's values + _setMatchesOperatorValues: function(oOpElem, aValues) + { + return this._setInOperatorValues(oOpElem, aValues); + }, + }); +}); diff --git a/sources/application/search/criterionconversion/criteriontooql.class.inc.php b/sources/application/search/criterionconversion/criteriontooql.class.inc.php index 025fe51e3..53c0bc90c 100644 --- a/sources/application/search/criterionconversion/criteriontooql.class.inc.php +++ b/sources/application/search/criterionconversion/criteriontooql.class.inc.php @@ -74,6 +74,7 @@ class CriterionToOQL extends CriterionConversionAbstract self::OP_BETWEEN => 'BetweenToOql', self::OP_REGEXP => 'RegexpToOql', self::OP_IN => 'InToOql', + self::OP_MATCHES => 'MatchesToOql', self::OP_ALL => 'AllToOql', ); @@ -118,7 +119,10 @@ class CriterionToOQL extends CriterionConversionAbstract $aValues = self::GetValues($aCriteria); $sValue = self::GetValue($aValues, 0); - if (empty($sValue)) return "1"; + if (empty($sValue)) + { + return "1"; + } return "({$sRef} LIKE '%{$sValue}%')"; } @@ -128,7 +132,10 @@ class CriterionToOQL extends CriterionConversionAbstract $aValues = self::GetValues($aCriteria); $sValue = self::GetValue($aValues, 0); - if (empty($sValue)) return "1"; + if (empty($sValue)) + { + return "1"; + } return "({$sRef} LIKE '{$sValue}%')"; } @@ -138,7 +145,10 @@ class CriterionToOQL extends CriterionConversionAbstract $aValues = self::GetValues($aCriteria); $sValue = self::GetValue($aValues, 0); - if (empty($sValue)) return "1"; + if (empty($sValue)) + { + return "1"; + } return "({$sRef} LIKE '%{$sValue}')"; } @@ -148,7 +158,10 @@ class CriterionToOQL extends CriterionConversionAbstract $aValues = self::GetValues($aCriteria); $sValue = self::GetValue($aValues, 0); - if (empty($sValue)) return "1"; + if (empty($sValue)) + { + return "1"; + } return "({$sRef} = '{$sValue}')"; } @@ -158,11 +171,32 @@ class CriterionToOQL extends CriterionConversionAbstract $aValues = self::GetValues($aCriteria); $sValue = self::GetValue($aValues, 0); - if (empty($sValue)) return "1"; + if (empty($sValue)) + { + return "1"; + } return "({$sRef} REGEXP '{$sValue}')"; } + protected static function MatchesToOql($oSearch, $sRef, $aCriteria) + { + $aValues = self::GetValues($aCriteria); + $aRawValues = array(); + for($i = 0; $i < count($aValues); $i++) + { + $aRawValues[] = self::GetValue($aValues, $i); + } + $sValue = implode(' ', $aRawValues); + + if (empty($sValue)) + { + return "1"; + } + + return "({$sRef} MATCHES '{$sValue}')"; + } + protected static function EmptyToOql($oSearch, $sRef, $aCriteria) { if (isset($aCriteria['widget'])) @@ -197,18 +231,18 @@ class CriterionToOQL extends CriterionConversionAbstract return "({$sRef} != '')"; } - /** - * @param \DBObjectSearch $oSearch - * @param string $sRef - * @param array $aCriteria - * - * @return mixed|string - * - * @throws \CoreException - * @throws \MissingQueryArgument - * @throws \MySQLException - * @throws \MySQLHasGoneAwayException - */ + /** + * @param \DBObjectSearch $oSearch + * @param string $sRef + * @param array $aCriteria + * + * @return mixed|string + * + * @throws \CoreException + * @throws \MissingQueryArgument + * @throws \MySQLException + * @throws \MySQLHasGoneAwayException + */ protected static function InToOql($oSearch, $sRef, $aCriteria) { $sAttCode = $aCriteria['code']; @@ -225,8 +259,7 @@ class CriterionToOQL extends CriterionConversionAbstract try { $aAttributeDefs = MetaModel::ListAttributeDefs($sClass); - } - catch (\CoreException $e) + } catch (\CoreException $e) { return "1"; } @@ -254,8 +287,7 @@ class CriterionToOQL extends CriterionConversionAbstract try { $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sTargetClass); - } - catch (\CoreException $e) + } catch (\CoreException $e) { } } @@ -371,9 +403,10 @@ class CriterionToOQL extends CriterionConversionAbstract else { // Add 'AND 1' to group the 'OR' inside an AND list for OQL parsing - $sCondition = "(({$sCondition} OR {$sFilterOnUndefined}) AND 1)"; + $sCondition = "(({$sCondition} OR {$sFilterOnUndefined}) AND 1)"; } } + return $sCondition; } @@ -406,8 +439,7 @@ class CriterionToOQL extends CriterionConversionAbstract $oDate = $oFormat->parse($sStartDate); $sStartDate = $oDate->format($sAttributeClass::GetSQLFormat()); $aOQL[] = "({$sRef} >= '$sStartDate')"; - } - catch (Exception $e) + } catch (Exception $e) { } } @@ -420,8 +452,7 @@ class CriterionToOQL extends CriterionConversionAbstract $oDate = $oFormat->parse($sEndDate); $sEndDate = $oDate->format($sAttributeClass::GetSQLFormat()); $aOQL[] = "({$sRef} <= '$sEndDate')"; - } - catch (Exception $e) + } catch (Exception $e) { } } diff --git a/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php b/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php index f02394abd..484a99daa 100644 --- a/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php +++ b/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php @@ -71,6 +71,7 @@ class CriterionToSearchForm extends CriterionConversionAbstract AttributeDefinition::SEARCH_WIDGET_TYPE_EXTERNAL_KEY => 'ExternalKeyToSearchForm', AttributeDefinition::SEARCH_WIDGET_TYPE_HIERARCHICAL_KEY => 'ExternalKeyToSearchForm', AttributeDefinition::SEARCH_WIDGET_TYPE_ENUM => 'EnumToSearchForm', + AttributeDefinition::SEARCH_WIDGET_TYPE_TAG_SET => 'TagSetToSearchForm', ); foreach($aAndCriterionRaw as $aCriteria) @@ -666,6 +667,36 @@ class CriterionToSearchForm extends CriterionConversionAbstract return $aCriteria; } + protected static function TagSetToSearchForm($aCriteria, $aFields) + { + $sOperator = $aCriteria['operator']; + switch ($sOperator) + { + case 'MATCHES': + // Nothing special to do + break; + + case 'ISNULL': + $aCriteria['operator'] = CriterionConversionAbstract::OP_EQUALS; + if (isset($aCriteria['has_undefined']) && $aCriteria['has_undefined']) + { + if (!isset($aCriteria['values'])) + { + $aCriteria['values'] = array(); + } + // Convention for 'undefined' enums + $aCriteria['values'][] = array('value' => 'null', 'label' => Dict::S('Enum:Undefined')); + } + break; + + default: + // Unknown operator + $aCriteria['widget'] = AttributeDefinition::SEARCH_WIDGET_TYPE_RAW; + break; + } + return $aCriteria; + } + protected static function ExternalKeyToSearchForm($aCriteria, $aFields) { $sOperator = $aCriteria['operator']; diff --git a/sources/application/search/criterionconversionabstract.class.inc.php b/sources/application/search/criterionconversionabstract.class.inc.php index d4296edbf..b1f41d7e1 100644 --- a/sources/application/search/criterionconversionabstract.class.inc.php +++ b/sources/application/search/criterionconversionabstract.class.inc.php @@ -37,6 +37,7 @@ abstract class CriterionConversionAbstract const OP_BETWEEN = 'between'; const OP_REGEXP = 'REGEXP'; const OP_ALL = 'all'; + const OP_MATCHES = 'MATCHES'; }