N°1420 - Performances enhancement

SVN:trunk[5833]
This commit is contained in:
Eric Espié
2018-06-07 15:06:38 +00:00
parent 5b2f32c08a
commit 70a0a3c52e
14 changed files with 300 additions and 113 deletions

View File

@@ -101,7 +101,7 @@ class UIExtKeyWidget
/** /**
* Get the HTML fragment corresponding to the ext key editing widget * Get the HTML fragment corresponding to the ext key editing widget
* @param WebPage $oP The web page used for all the output * @param WebPage $oP The web page used for all the output
* @param Hash $aArgs Extra context arguments * @param array $aArgs Extra context arguments
* @return string The HTML fragment to be inserted into the page * @return string The HTML fragment to be inserted into the page
*/ */
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = null, $sDisplayStyle = 'select', $bSearchMultiple = true) public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = null, $sDisplayStyle = 'select', $bSearchMultiple = true)
@@ -145,7 +145,12 @@ class UIExtKeyWidget
throw new Exception('Implementation: null value for allowed values definition'); throw new Exception('Implementation: null value for allowed values definition');
} }
$oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData()); $oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData());
if ($oAllowedValues->Count() < $iMaxComboLength) // Don't automatically launch the search if the table is huge
$bDoSearch = !utils::IsHighCardinality($this->sTargetClass);
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
if (!$oAllowedValues->CountExceeds($iMaxComboLength))
{ {
// Discrete list of values, use a SELECT or RADIO buttons depending on the config // Discrete list of values, use a SELECT or RADIO buttons depending on the config
switch($sDisplayStyle) switch($sDisplayStyle)
@@ -170,7 +175,6 @@ class UIExtKeyWidget
case 'select': case 'select':
case 'list': case 'list':
default: default:
$sSelectMode = 'true';
$sHelpText = ''; //$this->oAttDef->GetHelpOnEdition(); $sHelpText = ''; //$this->oAttDef->GetHelpOnEdition();
$sHTMLValue .= "<div class=\"field_select_wrapper\">\n"; $sHTMLValue .= "<div class=\"field_select_wrapper\">\n";
@@ -203,13 +207,13 @@ class UIExtKeyWidget
if (($oAllowedValues->Count() == 1) && ($bMandatory == 'true') ) if (($oAllowedValues->Count() == 1) && ($bMandatory == 'true') )
{ {
// When there is only once choice, select it by default // When there is only once choice, select it by default
$sSelected = ' selected'; $sSelected = 'selected';
} }
else else
{ {
$sSelected = (is_array($value) && in_array($key, $value)) || ($value == $key) ? ' selected' : ''; $sSelected = (is_array($value) && in_array($key, $value)) || ($value == $key) ? 'selected' : '';
} }
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n"; $sHTMLValue .= "<option value=\"$key\" $sSelected>$display_value</option>\n";
} }
$sHTMLValue .= "</select>\n"; $sHTMLValue .= "</select>\n";
$sHTMLValue .= "</div>\n"; $sHTMLValue .= "</div>\n";
@@ -229,7 +233,7 @@ class UIExtKeyWidget
} }
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode); oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>"; oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } ); $('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
$('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } ); $('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
@@ -241,8 +245,6 @@ EOF
else else
{ {
// Too many choices, use an autocomplete // Too many choices, use an autocomplete
$sSelectMode = 'false';
// Check that the given value is allowed // Check that the given value is allowed
$oSearch = $oAllowedValues->GetFilter(); $oSearch = $oAllowedValues->GetFilter();
$oSearch->AddCondition('id', $value); $oSearch->AddCondition('id', $value);
@@ -261,10 +263,9 @@ EOF
$sDisplayValue = $this->GetObjectName($value); $sDisplayValue = $this->GetObjectName($value);
} }
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 3; //@@@ $this->oAttDef->GetMinAutoCompleteChars(); $iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 3; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
$iFieldSize = isset($aArgs['iFieldSize']) ? $aArgs['iFieldSize'] : 20; //@@@ $this->oAttDef->GetMaxSize();
// the input for the auto-complete // the input for the auto-complete
$sHTMLValue .= "<input class=\"field_autocomplete\" count=\"".$oAllowedValues->Count()."\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>"; $sHTMLValue .= "<input class=\"field_autocomplete\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.Search();\"/></span>"; $sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.Search();\"/></span>";
// another hidden input to store & pass the object's Id // another hidden input to store & pass the object's Id
@@ -274,7 +275,7 @@ EOF
// Scripts to start the autocomplete and bind some events to it // Scripts to start the autocomplete and bind some events to it
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode); oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>"; oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter',bSearchMode:$JSSearchMode, json: function() { return $sWizHelperJSON; } }}); $('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter',bSearchMode:$JSSearchMode, json: function() { return $sWizHelperJSON; } }});
$('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly ! $('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly !
@@ -376,9 +377,13 @@ EOF
/** /**
* Search for objects to be selected * Search for objects to be selected
*
* @param WebPage $oP The page used for the output (usually an AjaxWebPage) * @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param $sFilter
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass * @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
* @param Array $aAlreadyLinkedIds List of IDs of objects of "remote" class already linked, to be filtered out of the search * @param null $oObj
*
* @throws \OQLException
*/ */
public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null) public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null)
{ {
@@ -403,10 +408,14 @@ EOF
/** /**
* Search for objects to be selected * Search for objects to be selected
*
* @param WebPage $oP The page used for the output (usually an AjaxWebPage) * @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param string $sFilter The OQL expression used to define/limit limit the scope of possible values * @param string $sFilter The OQL expression used to define/limit limit the scope of possible values
* @param DBObject $oObj The current object for the OQL context * @param DBObject $oObj The current object for the OQL context
* @param string $sContains The text of the autocomplete to filter the results * @param string $sContains The text of the autocomplete to filter the results
* @param string $sOutputFormat
*
* @throws \CoreException
*/ */
public function AutoComplete(WebPage $oP, $sFilter, $oObj = null, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV) public function AutoComplete(WebPage $oP, $sFilter, $oObj = null, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV)
{ {
@@ -419,8 +428,26 @@ EOF
$iCurrentExtKeyId = (is_null($oObj) || $this->sAttCode === '') ? 0 : $oObj->Get($this->sAttCode); $iCurrentExtKeyId = (is_null($oObj) || $this->sAttCode === '') ? 0 : $oObj->Get($this->sAttCode);
$oValuesSet = new ValueSetObjects($sFilter, 'friendlyname'); // Bypass GetName() to avoid the encoding by htmlentities $oValuesSet = new ValueSetObjects($sFilter, 'friendlyname'); // Bypass GetName() to avoid the encoding by htmlentities
$iMax = 150;
$oValuesSet->SetLimit($iMax);
$oValuesSet->SetSort(false);
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode); $oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$aValues = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains);
$aValues = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'equals_start_with');
$iMax -= count($aValues);
if ($iMax > 0)
{
$oValuesSet->SetLimit($iMax);
$aValuesContains = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains');
asort($aValuesContains);
foreach($aValuesContains as $sKey => $sFriendlyName)
{
if (!isset($aValues[$sKey]))
{
$aValues[$sKey] = $sFriendlyName;
}
}
}
switch($sOutputFormat) switch($sOutputFormat)
{ {
@@ -461,12 +488,15 @@ EOF
} }
} }
/** /**
* Get the form to select a leaf class from the $this->sTargetClass (that should be abstract) * Get the form to select a leaf class from the $this->sTargetClass (that should be abstract)
* Note: Inspired from UILinksWidgetDirect::GetObjectCreationDialog() * Note: Inspired from UILinksWidgetDirect::GetObjectCreationDialog()
* *
* @param WebPage $oPage * @param WebPage $oPage
*/ *
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
public function GetClassSelectionForm(WebPage $oPage) public function GetClassSelectionForm(WebPage $oPage)
{ {
// For security reasons: check that the "proposed" class is actually a subclass of the linked class // For security reasons: check that the "proposed" class is actually a subclass of the linked class
@@ -568,21 +598,11 @@ EOF
{ {
throw new Exception('Implementation: null value for allowed values definition'); throw new Exception('Implementation: null value for allowed values definition');
} }
try
{ $oFilter = DBObjectSearch::FromOQL($sFilter);
$oFilter = DBObjectSearch::FromOQL($sFilter); $oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode); $oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj, 'current_extkey_id' => $currValue));
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj, 'current_extkey_id' => $currValue));
}
catch(MissingQueryArgument $e)
{
// When used in a search form the $this parameter may be missing, in this case return all possible values...
// TODO check if we can improve this behavior...
$sOQL = 'SELECT '.$this->m_sTargetClass;
$oFilter = DBObjectSearch::FromOQL($sOQL);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter);
}
$oSet->SetShowObsoleteData(utils::ShowObsoleteData()); $oSet->SetShowObsoleteData(utils::ShowObsoleteData());
$sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass); $sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass);

View File

@@ -275,7 +275,10 @@ class UILinksWidgetDirect
$sJSONLabels = json_encode($aLabels); $sJSONLabels = json_encode($aLabels);
$sJSONButtons = json_encode($aButtons); $sJSONButtons = json_encode($aButtons);
$sWizHelper = 'oWizardHelper'.$sFormPrefix; $sWizHelper = 'oWizardHelper'.$sFormPrefix;
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, submit_to: '$sSubmitUrl', buttons: $sJSONButtons, oWizardHelper: $sWizHelper });"); // Don't automatically launch the search if the table is huge
$bDoSearch = !utils::IsHighCardinality($this->sLinkedClass);
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, submit_to: '$sSubmitUrl', buttons: $sJSONButtons, oWizardHelper: $sWizHelper, do_search: $sJSDoSearch});");
} }
/** /**
@@ -337,6 +340,7 @@ class UILinksWidgetDirect
'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}", 'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}",
'table_id' => "add_{$this->sInputid}", 'table_id' => "add_{$this->sInputid}",
'table_inner_id' => "ResultsToAdd_{$this->sInputid}", 'table_inner_id' => "ResultsToAdd_{$this->sInputid}",
'selection_mode' => true,
'cssCount' => "#count_{$this->sInputid}", 'cssCount' => "#count_{$this->sInputid}",
'query_params' => $oFilter->GetInternalParams(), 'query_params' => $oFilter->GetInternalParams(),
'hidden_criteria' => $sHiddenCriteria, 'hidden_criteria' => $sHiddenCriteria,

View File

@@ -194,7 +194,7 @@ class UILinksWidget
$aArgs['prefix'] = $sPrefix; $aArgs['prefix'] = $sPrefix;
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}_".($iUniqueId < 0 ? -$iUniqueId : $iUniqueId); $aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}_".($iUniqueId < 0 ? -$iUniqueId : $iUniqueId);
$aArgs['this'] = $oNewLinkObj; $aArgs['this'] = $oNewLinkObj;
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"-$iUniqueId\">"; $aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnChange();\" value=\"-$iUniqueId\">";
foreach($this->m_aEditableFields as $sFieldCode) foreach($this->m_aEditableFields as $sFieldCode)
{ {
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.-$iUniqueId.']'; $sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.-$iUniqueId.']';
@@ -365,13 +365,16 @@ EOF
} }
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm); $sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
$sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false'; $sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
// Don't automatically launch the search if the table is huge
$bDoSearch = !utils::IsHighCardinality($this->m_sRemoteClass);
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
$sWizHelper = 'oWizardHelper'.$sFormPrefix; $sWizHelper = 'oWizardHelper'.$sFormPrefix;
$oPage->add_ready_script(<<<EOF $oPage->add_ready_script(<<<EOF
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}'); oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}', $sJSDoSearch);
oWidget{$this->m_iInputId}.Init(); oWidget{$this->m_iInputId}.Init();
EOF EOF
); );
$sHtmlValue .= "<span style=\"float:left;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >"; $sHtmlValue .= "<span style=\"float:left;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.Removeed();\" >";
$sHtmlValue .= "&nbsp;&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"><span id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_indicatorAdd\"></span></span>\n"; $sHtmlValue .= "&nbsp;&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"><span id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_indicatorAdd\"></span></span>\n";
$sHtmlValue .= "<span style=\"clear:both;\"><p>&nbsp;</p></span>\n"; $sHtmlValue .= "<span style=\"clear:both;\"><p>&nbsp;</p></span>\n";
$sHtmlValue .= "</div>\n"; $sHtmlValue .= "</div>\n";

View File

@@ -1924,4 +1924,17 @@ class utils
} }
return COMPILATION_TIMESTAMP; return COMPILATION_TIMESTAMP;
} }
/**
* Check if the given class if configured as a high cardinality class.
*
* @param $sClass
*
* @return bool
*/
public static function IsHighCardinality($sClass)
{
$aHugeClasses = MetaModel::GetConfig()->Get('high_cardinality_classes');
return in_array($sClass, $aHugeClasses);
}
} }

View File

@@ -1111,12 +1111,20 @@ class Config
), ),
'search_manual_submit' => array( 'search_manual_submit' => array(
'type' => 'array', 'type' => 'array',
'description' => 'Force manual submit of search requests (class => true)', 'description' => 'Force manual submit of search all requests',
'default' => false, 'default' => false,
'value' => true, 'value' => true,
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => true, 'show_in_conf_sample' => true,
), ),
'high_cardinality_classes' => array(
'type' => 'array',
'description' => 'List of classes with high cardinality (Force manual submit of search)',
'default' => array(),
'value' => array(),
'source_of_value' => '',
'show_in_conf_sample' => true,
),
); );
public function IsProperty($sPropCode) public function IsProperty($sPropCode)

View File

@@ -77,18 +77,20 @@ class DBObjectSet implements iDBObjectSetIterator
* @var mysqli_result * @var mysqli_result
*/ */
protected $m_oSQLResult; protected $m_oSQLResult;
protected $m_bSort;
/** /**
* Create a new set based on a Search definition. * Create a new set based on a Search definition.
* *
* @param DBSearch $oFilter The search filter defining the objects which are part of the set (multiple columns/objects per row are supported) * @param DBSearch $oFilter The search filter defining the objects which are part of the set (multiple columns/objects per row are supported)
* @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending * @param array $aOrderBy Array of '[<classalias>.]attcode' => bAscending
* @param hash $aArgs Values to substitute for the search/query parameters (if any). Format: param_name => value * @param array $aArgs Values to substitute for the search/query parameters (if any). Format: param_name => value
* @param hash $aExtendedDataSpec * @param array $aExtendedDataSpec
* @param int $iLimitCount Maximum number of rows to load (i.e. equivalent to MySQL's LIMIT start, count) * @param int $iLimitCount Maximum number of rows to load (i.e. equivalent to MySQL's LIMIT start, count)
* @param int $iLimitStart Index of the first row to load (i.e. equivalent to MySQL's LIMIT start, count) * @param int $iLimitStart Index of the first row to load (i.e. equivalent to MySQL's LIMIT start, count)
* @param bool $bSort if false no order by is done
*/ */
public function __construct(DBSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0) public function __construct(DBSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bSort = true)
{ {
$this->m_oFilter = $oFilter->DeepClone(); $this->m_oFilter = $oFilter->DeepClone();
$this->m_aAddedIds = array(); $this->m_aAddedIds = array();
@@ -98,6 +100,7 @@ class DBObjectSet implements iDBObjectSetIterator
$this->m_aExtendedDataSpec = $aExtendedDataSpec; $this->m_aExtendedDataSpec = $aExtendedDataSpec;
$this->m_iLimitCount = $iLimitCount; $this->m_iLimitCount = $iLimitCount;
$this->m_iLimitStart = $iLimitStart; $this->m_iLimitStart = $iLimitStart;
$this->m_bSort = $bSort;
$this->m_iNumTotalDBRows = null; $this->m_iNumTotalDBRows = null;
$this->m_iNumLoadedDBRows = 0; $this->m_iNumLoadedDBRows = 0;
@@ -601,10 +604,15 @@ class DBObjectSet implements iDBObjectSetIterator
* *
* Limitation: the sort order has no effect on objects added in-memory * Limitation: the sort order has no effect on objects added in-memory
* *
* @return hash Format: field_code => boolean (true = ascending, false = descending) * @return array Format: field_code => boolean (true = ascending, false = descending)
*/ */
public function GetRealSortOrder() public function GetRealSortOrder()
{ {
if (!$this->m_bSort)
{
// No order by
return array();
}
// Get the class default sort order if not specified with the API // Get the class default sort order if not specified with the API
// //
if (empty($this->m_aOrderBy)) if (empty($this->m_aOrderBy))
@@ -719,7 +727,19 @@ class DBObjectSet implements iDBObjectSetIterator
return $this->m_iNumTotalDBRows + count($this->m_aAddedObjects); // Does it fix Trac #887 ?? return $this->m_iNumTotalDBRows + count($this->m_aAddedObjects); // Does it fix Trac #887 ??
} }
public function CountExceeds($iLimit)
{
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, $iLimit + 2, 0, true);
$resQuery = CMDBSource::Query($sSQL);
if (!$resQuery) return (0 > $iLimit);
$aRow = CMDBSource::FetchArray($resQuery);
CMDBSource::FreeResult($resQuery);
return (intval($aRow['COUNT']) > $iLimit);
}
/** /**
* Number of rows available in memory (loaded from DB + added in memory) * Number of rows available in memory (loaded from DB + added in memory)
* *

View File

@@ -638,6 +638,20 @@ abstract class MetaModel
return reset($aAttributes); return reset($aAttributes);
} }
/**
* Returns the list of attributes composing the friendlyname
*
* @param $sClass
*
* @return array
*/
final static public function GetFriendlyNameAttributeCodeList($sClass)
{
$aNameSpec = self::GetNameSpec($sClass);
$aAttributes = $aNameSpec[1];
return $aAttributes;
}
/** /**
* @param string $sClass * @param string $sClass
* *
@@ -5034,6 +5048,7 @@ abstract class MetaModel
// Check that any defined field exists // Check that any defined field exists
// //
$aTableInfo['Fields'][$sKeyField]['used'] = true; $aTableInfo['Fields'][$sKeyField]['used'] = true;
$aFriendlynameAttcodes = self::GetFriendlyNameAttributeCodeList($sClass);
foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) foreach(self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{ {
if (!$oAttDef->CopyOnAllTables()) if (!$oAttDef->CopyOnAllTables())
@@ -5050,6 +5065,14 @@ abstract class MetaModel
$aTableInfo['Fields'][$sField]['used'] = true; $aTableInfo['Fields'][$sField]['used'] = true;
$bIndexNeeded = $oAttDef->RequiresIndex(); $bIndexNeeded = $oAttDef->RequiresIndex();
if (!$bIndexNeeded)
{
// Add an index on the columns of the friendlyname
if (in_array($sField, $aFriendlynameAttcodes))
{
$bIndexNeeded = true;
}
}
$sFieldDefinition = "`$sField` $sDBFieldSpec"; $sFieldDefinition = "`$sField` $sDBFieldSpec";
if (!CMDBSource::IsField($sTable, $sField)) if (!CMDBSource::IsField($sTable, $sField))

View File

@@ -339,6 +339,14 @@ class SQLObjectQuery extends SQLQuery
$this->PrepareRendering(); $this->PrepareRendering();
$sFrom = self::ClauseFrom($this->__aFrom, $sIndent); $sFrom = self::ClauseFrom($this->__aFrom, $sIndent);
$sWhere = self::ClauseWhere($this->m_oConditionExpr, $aArgs); $sWhere = self::ClauseWhere($this->m_oConditionExpr, $aArgs);
if ($iLimitCount > 0)
{
$sLimit = 'LIMIT '.$iLimitStart.', '.$iLimitCount;
}
else
{
$sLimit = '';
}
if ($bGetCount) if ($bGetCount)
{ {
if (count($this->__aSelectedIdFields) > 0) if (count($this->__aSelectedIdFields) > 0)
@@ -349,11 +357,13 @@ class SQLObjectQuery extends SQLQuery
$aCountFields[] = "COALESCE($sFieldExpr, 0)"; // Null values are excluded from the count $aCountFields[] = "COALESCE($sFieldExpr, 0)"; // Null values are excluded from the count
} }
$sCountFields = implode(', ', $aCountFields); $sCountFields = implode(', ', $aCountFields);
$sSQL = "SELECT$sLineSep COUNT(DISTINCT $sCountFields) AS COUNT$sLineSep FROM $sFrom$sLineSep WHERE $sWhere"; // Count can be limited for performance reason, in this case the total amount is not important,
// we only need to know if the number of entries is greater than a certain amount.
$sSQL = "SELECT COUNT(*) AS COUNT FROM (SELECT$sLineSep DISTINCT $sCountFields $sLineSep FROM $sFrom$sLineSep WHERE $sWhere $sLimit) AS _tatooine_";
} }
else else
{ {
$sSQL = "SELECT$sLineSep COUNT(*) AS COUNT$sLineSep FROM $sFrom$sLineSep WHERE $sWhere"; $sSQL = "SELECT COUNT(*) AS COUNT FROM (SELECT$sLineSep 1 $sLineSep FROM $sFrom$sLineSep WHERE $sWhere $sLimit) AS _tatooine_";
} }
} }
else else
@@ -364,14 +374,7 @@ class SQLObjectQuery extends SQLQuery
{ {
$sOrderBy = "ORDER BY $sOrderBy$sLineSep"; $sOrderBy = "ORDER BY $sOrderBy$sLineSep";
} }
if ($iLimitCount > 0)
{
$sLimit = 'LIMIT '.$iLimitStart.', '.$iLimitCount;
}
else
{
$sLimit = '';
}
$sSQL = "SELECT$sLineSep DISTINCT $sSelect$sLineSep FROM $sFrom$sLineSep WHERE $sWhere$sLineSep $sOrderBy $sLimit"; $sSQL = "SELECT$sLineSep DISTINCT $sSelect$sLineSep FROM $sFrom$sLineSep WHERE $sWhere$sLineSep $sOrderBy $sLimit";
} }
return $sSQL; return $sSQL;

View File

@@ -103,29 +103,33 @@ class SQLUnionQuery extends SQLQuery
// Render SELECTS without orderby/limit/count // Render SELECTS without orderby/limit/count
$aSelects[] = $oSQLQuery->RenderSelect(array(), $aArgs, 0, 0, false, $bBeautifulQuery); $aSelects[] = $oSQLQuery->RenderSelect(array(), $aArgs, 0, 0, false, $bBeautifulQuery);
} }
$sSelects = '('.implode(")$sLineSep UNION$sLineSep(", $aSelects).')'; if ($iLimitCount > 0)
{
$sLimit = 'LIMIT '.$iLimitStart.', '.$iLimitCount;
}
else
{
$sLimit = '';
}
if ($bGetCount) if ($bGetCount)
{ {
$sSelects = '('.implode(" $sLimit)$sLineSep UNION$sLineSep(", $aSelects)." $sLimit)";
$sFrom = "($sLineSep$sSelects$sLineSep) as __selects__"; $sFrom = "($sLineSep$sSelects$sLineSep) as __selects__";
$sSQL = "SELECT$sLineSep COUNT(*) AS COUNT$sLineSep FROM $sFrom$sLineSep"; $sSQL = "SELECT COUNT(*) AS COUNT FROM (SELECT$sLineSep 1 $sLineSep FROM $sFrom$sLineSep) AS _union_tatooine_";
} }
else else
{ {
$sOrderBy = $this->aQueries[0]->RenderOrderByClause($aOrderBy); $sOrderBy = $this->aQueries[0]->RenderOrderByClause($aOrderBy);
if (!empty($sOrderBy)) if (!empty($sOrderBy))
{ {
$sOrderBy = "ORDER BY $sOrderBy$sLineSep"; $sOrderBy = "ORDER BY $sOrderBy$sLineSep $sLimit";
} $sSQL = '('.implode(")$sLineSep UNION$sLineSep (", $aSelects).')'.$sLineSep.$sOrderBy;
if ($iLimitCount > 0)
{
$sLimit = 'LIMIT '.$iLimitStart.', '.$iLimitCount;
} }
else else
{ {
$sLimit = ''; $sSQL = '('.implode(" $sLimit)$sLineSep UNION$sLineSep (", $aSelects)." $sLimit)";
} }
$sSQL = $sSelects.$sLineSep.$sOrderBy.' '.$sLimit;
} }
return $sSQL; return $sSQL;
} }

View File

@@ -52,7 +52,7 @@ abstract class ValueSetDefinition
} }
public function GetValues($aArgs, $sContains = '') public function GetValues($aArgs, $sContains = '', $sOperation = 'contains')
{ {
if (!$this->m_bIsLoaded) if (!$this->m_bIsLoaded)
{ {
@@ -93,12 +93,16 @@ abstract class ValueSetDefinition
class ValueSetObjects extends ValueSetDefinition class ValueSetObjects extends ValueSetDefinition
{ {
protected $m_sContains; protected $m_sContains;
protected $m_sOperation;
protected $m_sFilterExpr; // in OQL protected $m_sFilterExpr; // in OQL
protected $m_sValueAttCode; protected $m_sValueAttCode;
protected $m_aOrderBy; protected $m_aOrderBy;
protected $m_aExtraConditions; protected $m_aExtraConditions;
private $m_bAllowAllData; private $m_bAllowAllData;
private $m_aModifierProperties; private $m_aModifierProperties;
private $m_bSort;
private $m_iLimit;
/** /**
* @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending * @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
@@ -106,12 +110,15 @@ class ValueSetObjects extends ValueSetDefinition
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false, $aModifierProperties = array()) public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false, $aModifierProperties = array())
{ {
$this->m_sContains = ''; $this->m_sContains = '';
$this->m_sOperation = '';
$this->m_sFilterExpr = $sFilterExp; $this->m_sFilterExpr = $sFilterExp;
$this->m_sValueAttCode = $sValueAttCode; $this->m_sValueAttCode = $sValueAttCode;
$this->m_aOrderBy = $aOrderBy; $this->m_aOrderBy = $aOrderBy;
$this->m_bAllowAllData = $bAllowAllData; $this->m_bAllowAllData = $bAllowAllData;
$this->m_aModifierProperties = $aModifierProperties; $this->m_aModifierProperties = $aModifierProperties;
$this->m_aExtraConditions = array(); $this->m_aExtraConditions = array();
$this->m_bSort = true;
$this->m_iLimit = 0;
} }
public function SetModifierProperty($sPluginClass, $sProperty, $value) public function SetModifierProperty($sPluginClass, $sProperty, $value)
@@ -163,11 +170,11 @@ class ValueSetObjects extends ValueSetDefinition
return new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs); return new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
} }
public function GetValues($aArgs, $sContains = '') public function GetValues($aArgs, $sContains = '', $sOperation = 'contains')
{ {
if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains)) if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains) || ($sOperation != $this->m_sOperation))
{ {
$this->LoadValues($aArgs, $sContains); $this->LoadValues($aArgs, $sContains, $sOperation);
$this->m_bIsLoaded = true; $this->m_bIsLoaded = true;
} }
// The results are already filtered and sorted (on friendly name) // The results are already filtered and sorted (on friendly name)
@@ -175,9 +182,19 @@ class ValueSetObjects extends ValueSetDefinition
return $aRet; return $aRet;
} }
protected function LoadValues($aArgs, $sContains = '') /**
* @param $aArgs
* @param string $sContains
* @param string $sOperation 'contains' or 'equals_start_with'
*
* @return bool
* @throws \CoreException
* @throws \OQLException
*/
protected function LoadValues($aArgs, $sContains = '', $sOperation = 'contains')
{ {
$this->m_sContains = $sContains; $this->m_sContains = $sContains;
$this->m_sOperation = $sOperation;
$this->m_aValues = array(); $this->m_aValues = array();
@@ -202,12 +219,54 @@ class ValueSetObjects extends ValueSetDefinition
} }
} }
$oValueExpr = new ScalarExpression('%'.$sContains.'%'); switch ($sOperation)
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias()); {
$oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr); case 'equals_start_with':
$oFilter->AddConditionExpression($oNewCondition); $aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($oFilter->GetClass());
$sClassAlias = $oFilter->GetClassAlias();
$aFilters = array();
// Equals first
$oValueExpr = new ScalarExpression($sContains);
foreach($aAttributes as $sAttribute)
{
$oNewFilter = $oFilter->DeepClone();
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
$oCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
$oNewFilter->AddConditionExpression($oCondition);
$aFilters[] = $oNewFilter;
}
// start with next
$oValueExpr = new ScalarExpression($sContains.'%');
foreach($aAttributes as $sAttribute)
{
$oNewFilter = $oFilter->DeepClone();
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
$oCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
$oNewFilter->AddConditionExpression($oCondition);
$aFilters[] = $oNewFilter;
}
// Unions are much faster than OR conditions
$oFilter = new DBUnionSearch($aFilters);
break;
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs); default:
$oValueExpr = new ScalarExpression('%'.$sContains.'%');
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
$oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
$oFilter->AddConditionExpression($oNewCondition);
break;
}
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs, null, $this->m_iLimit, 0, $this->m_bSort);
if (empty($this->m_sValueAttCode))
{
$aAttToLoad = array($oFilter->GetClassAlias() => array('friendlyname'));
}
else
{
$aAttToLoad = array($oFilter->GetClassAlias() => array($this->m_sValueAttCode));
}
$oObjects->OptimizeColumnLoad($aAttToLoad);
while ($oObject = $oObjects->Fetch()) while ($oObject = $oObjects->Fetch())
{ {
if (empty($this->m_sValueAttCode)) if (empty($this->m_sValueAttCode))
@@ -231,6 +290,22 @@ class ValueSetObjects extends ValueSetDefinition
{ {
return $this->m_sFilterExpr; return $this->m_sFilterExpr;
} }
/**
* @param $iLimit
*/
public function SetLimit($iLimit)
{
$this->m_iLimit = $iLimit;
}
/**
* @param $bSort
*/
public function SetSort($bSort)
{
$this->m_bSort = $bSort;
}
} }

View File

@@ -15,7 +15,7 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper, sAttCode, bSearchMode) function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper, sAttCode, bSearchMode, bDoSearch)
{ {
this.id = id; this.id = id;
this.sOriginalTargetClass = sTargetClass; this.sOriginalTargetClass = sTargetClass;
@@ -29,6 +29,7 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
this.ajax_request = null; this.ajax_request = null;
this.bSelectMode = bSelectMode; // true if the edited field is a SELECT, false if it's an autocomplete this.bSelectMode = bSelectMode; // true if the edited field is a SELECT, false if it's an autocomplete
this.bSearchMode = bSearchMode; // true if selecting a value in the context of a search form this.bSearchMode = bSearchMode; // true if selecting a value in the context of a search form
this.bDoSearch = bDoSearch; // false if the search is not launched
var me = this; var me = this;
this.Init = function() this.Init = function()
@@ -94,7 +95,13 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
me.UpdateSizes(); me.UpdateSizes();
me.UpdateButtons(); me.UpdateButtons();
me.ajax_request = null; me.ajax_request = null;
me.DoSearchObjects(); $('#count_'+me.id).change(function(){
me.UpdateButtons();
});
if (me.bDoSearch)
{
me.DoSearchObjects();
}
}, },
'html' 'html'
); );
@@ -196,9 +203,6 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
$('#fr_'+me.id+' input:radio').click(function() { me.UpdateButtons(); }); $('#fr_'+me.id+' input:radio').click(function() { me.UpdateButtons(); });
me.UpdateButtons(); me.UpdateButtons();
me.ajax_request = null; me.ajax_request = null;
$('#count_'+me.id).change(function(){
me.UpdateButtons();
});
me.UpdateSizes(); me.UpdateSizes();
}, },
'html' 'html'

View File

@@ -11,6 +11,7 @@ $(function()
input_name: '', input_name: '',
class_name: '', class_name: '',
att_code: '', att_code: '',
do_search: true,
submit_to: '../pages/ajax.render.php', submit_to: '../pages/ajax.render.php',
submit_parameters: {}, submit_parameters: {},
labels: { 'delete': 'Delete', labels: { 'delete': 'Delete',
@@ -225,7 +226,17 @@ $(function()
}); });
me.indicator.html(''); me.indicator.html('');
me.oButtons['add'].removeAttr('disabled'); me.oButtons['add'].removeAttr('disabled');
me._onSearchToAdd(); if (me.options.do_search)
{
me._onSearchToAdd();
}
else
{
$('#count_'+me.id).change(function() {
var c = this.value;
me._onUpdateDlgButtons(c);
});
}
me._updateDlgPosition(); me._updateDlgPosition();
me._onSearchDlgUpdateSize(); me._onSearchDlgUpdateSize();
}); });

View File

@@ -16,7 +16,7 @@
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
// JavaScript Document // JavaScript Document
function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizHelper, sExtKeyToRemote) function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizHelper, sExtKeyToRemote, bDoSearch)
{ {
this.id = id; this.id = id;
this.iInputId = iInputId; this.iInputId = iInputId;
@@ -30,6 +30,7 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH
this.aAdded = []; this.aAdded = [];
this.aRemoved = []; this.aRemoved = [];
this.aModified = {}; this.aModified = {};
this.bDoSearch = bDoSearch; // false if the search is not launched
var me = this; var me = this;
this.Init = function() this.Init = function()
@@ -132,11 +133,22 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH
"data": theMap, "data": theMap,
"dataType": "html" "dataType": "html"
}) })
.done(function (data) { .done(function (data)
{
$('#dlg_'+me.id).html(data); $('#dlg_'+me.id).html(data);
$('#dlg_'+me.id).dialog('open'); $('#dlg_'+me.id).dialog('open');
me.UpdateSizes(null, null); me.UpdateSizes(null, null);
me.SearchObjectsToAdd(); if (me.bDoSearch)
{
me.SearchObjectsToAdd();
}
else
{
$('#count_'+me.id).change(function () {
var c = this.value;
me.UpdateButtons(c);
});
}
$('#'+me.id+'_indicatorAdd').html(''); $('#'+me.id+'_indicatorAdd').html('');
}) })
; ;

View File

@@ -147,32 +147,21 @@ class SearchForm
$bAutoSubmit = true; $bAutoSubmit = true;
$mSubmitParam = utils::GetConfig()->Get('search_manual_submit'); $mSubmitParam = utils::GetConfig()->Get('search_manual_submit');
if (is_array($mSubmitParam)) if ($mSubmitParam !== false)
{
// List of classes
if (isset($mSubmitParam[$sClassName]))
{
$bAutoSubmit = !$mSubmitParam[$sClassName];
}
else
{
// Search for child classes
foreach($mSubmitParam as $sConfigClass => $bFlag)
{
$aChildClasses = MetaModel::EnumChildClasses($sConfigClass);
if (in_array($sClassName, $aChildClasses))
{
$bAutoSubmit = !$bFlag;
break;
}
}
}
}
else if ($mSubmitParam !== false)
{ {
$bAutoSubmit = false; $bAutoSubmit = false;
} }
else
{
$mSubmitParam = utils::GetConfig()->Get('high_cardinality_classes');
if (is_array($mSubmitParam))
{
if (in_array($sClassName, $mSubmitParam))
{
$bAutoSubmit = false;
}
}
}
$sAction = (isset($aExtraParams['action'])) ? $aExtraParams['action'] : utils::GetAbsoluteUrlAppRoot().'pages/UI.php'; $sAction = (isset($aExtraParams['action'])) ? $aExtraParams['action'] : utils::GetAbsoluteUrlAppRoot().'pages/UI.php';
$sStyle = ($bOpen == 'true') ? '' : 'closed'; $sStyle = ($bOpen == 'true') ? '' : 'closed';
@@ -404,6 +393,7 @@ class SearchForm
*/ */
public static function GetFieldAllowedValues($oAttrDef) public static function GetFieldAllowedValues($oAttrDef)
{ {
$iMaxComboLength = MetaModel::GetConfig()->Get('max_combo_length');
if ($oAttrDef->IsExternalKey(EXTKEY_ABSOLUTE)) if ($oAttrDef->IsExternalKey(EXTKEY_ABSOLUTE))
{ {
if ($oAttrDef instanceof AttributeExternalField) if ($oAttrDef instanceof AttributeExternalField)
@@ -426,10 +416,9 @@ class SearchForm
} }
$oSearch->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true); $oSearch->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new DBObjectSet($oSearch); $oSet = new DBObjectSet($oSearch);
$iCount = $oSet->Count(); if ($oSet->CountExceeds($iMaxComboLength))
if ($iCount > MetaModel::GetConfig()->Get('max_combo_length'))
{ {
return array('autocomplete' => true, 'count' => $iCount); return array('autocomplete' => true);
} }
if ($oAttrDef instanceof AttributeExternalField) if ($oAttrDef instanceof AttributeExternalField)
{ {
@@ -438,7 +427,7 @@ class SearchForm
{ {
$aAllowedValues[$oObject->GetKey()] = $oObject->GetName(); $aAllowedValues[$oObject->GetKey()] = $oObject->GetName();
} }
return array('values' => $aAllowedValues, 'count' => $iCount); return array('values' => $aAllowedValues);
} }
} }
else else
@@ -447,18 +436,16 @@ class SearchForm
{ {
/** @var DBObjectSet $oSet */ /** @var DBObjectSet $oSet */
$oSet = $oAttrDef->GetAllowedValuesAsObjectSet(); $oSet = $oAttrDef->GetAllowedValuesAsObjectSet();
$iCount = $oSet->Count(); if ($oSet->CountExceeds($iMaxComboLength))
if ($iCount > MetaModel::GetConfig()->Get('max_combo_length'))
{ {
return array('autocomplete' => true, 'count' => $iCount); return array('autocomplete' => true);
} }
} }
} }
$aAllowedValues = $oAttrDef->GetAllowedValues(); $aAllowedValues = $oAttrDef->GetAllowedValues();
$iCount = is_array($aAllowedValues) ? count($aAllowedValues) : 0; return array('values' => $aAllowedValues);
return array('values' => $aAllowedValues, 'count' => $iCount);
} }
/** /**