diff --git a/libraries/src/Form/Field/TagField.php b/libraries/src/Form/Field/TagField.php index 5bda35b0e3259..70679f797e7dd 100644 --- a/libraries/src/Form/Field/TagField.php +++ b/libraries/src/Form/Field/TagField.php @@ -130,12 +130,11 @@ protected function getOptions() $published = $this->element['published'] ?: array(0, 1); $app = Factory::getApplication(); $language = null; + $options = []; - // Return only basic options, everything else will be searched via AJAX - if ($this->isRemoteSearch() && !$this->value) - { - return parent::getOptions(); - } + // This limit is only used with isRemoteSearch + $prefillLimit = 30; + $isRemoteSearch = $this->isRemoteSearch(); $db = Factory::getDbo(); $query = $db->getQuery(true) @@ -184,12 +183,6 @@ protected function getOptions() $query->where($db->quoteName('a.lft') . ' > 0'); - // Preload only active values, everything else will be searched via AJAX - if ($this->isRemoteSearch() && $this->value) - { - $query->whereIn($db->quoteName('a.id'), $this->value); - } - // Filter on the published state if (is_numeric($published)) { @@ -205,16 +198,74 @@ protected function getOptions() $query->order($db->quoteName('a.lft') . ' ASC'); - // Get the options. - $db->setQuery($query); - - try + // Preload only active values and 30 most used tags or fill up + if ($isRemoteSearch) { - $options = $db->loadObjectList(); + // Load the most $prefillLimit used tags + $topQuery = $db->getQuery(true) + ->select($db->quoteName('tag_id')) + ->from($db->quoteName('#__contentitem_tag_map')) + ->group($db->quoteName('tag_id')) + ->order('count(*)') + ->setLimit($prefillLimit); + + $db->setQuery($topQuery); + $topIds = $db->loadColumn(); + + // Merge the used values into the most used tags + if (!empty($this->value) && is_array($this->value)) + { + $topIds = array_merge($topIds, $this->value); + $topIds = array_keys(array_flip($topIds)); + } + + // Set the default limit for the main query + $query->setLimit($prefillLimit); + + if (!empty($topIds)) + { + // Filter the ids to the most used tags and the selected tags + $preQuery = clone $query; + $preQuery->whereIn($db->quoteName('a.id'), $topIds); + + $db->setQuery($preQuery); + + try + { + $options = $db->loadObjectList(); + } + catch (\RuntimeException $e) + { + return array(); + } + + // Limit the main query to the missing amount of tags + $count = count($options); + $prefillLimit = $prefillLimit - $count; + $query->setLimit($prefillLimit); + + // Exclude the already loaded tags from the main query + if ($count > 0) + { + $query->whereNotIn($db->quoteName('a.id'), ArrayHelper::getColumn($options, 'value')); + } + } } - catch (\RuntimeException $e) + + // Only execute the query if we need more tags not already loaded by the $preQuery query + if (!$isRemoteSearch || $prefillLimit > 0) { - return array(); + // Get the options. + $db->setQuery($query); + + try + { + $options = array_merge($options, $db->loadObjectList()); + } + catch (\RuntimeException $e) + { + return array(); + } } // Block the possibility to set a tag as it own parent