[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Joomla! Content Management System 5 * 6 * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10 namespace Joomla\CMS\Form\Field; 11 12 use Joomla\CMS\Component\ComponentHelper; 13 use Joomla\CMS\Factory; 14 use Joomla\CMS\Helper\TagsHelper; 15 use Joomla\CMS\Language\Multilanguage; 16 use Joomla\Database\ParameterType; 17 use Joomla\Utilities\ArrayHelper; 18 19 // phpcs:disable PSR1.Files.SideEffects 20 \defined('JPATH_PLATFORM') or die; 21 // phpcs:enable PSR1.Files.SideEffects 22 23 /** 24 * List of Tags field. 25 * 26 * @since 3.1 27 */ 28 class TagField extends ListField 29 { 30 /** 31 * A flexible tag list that respects access controls 32 * 33 * @var string 34 * @since 3.1 35 */ 36 public $type = 'Tag'; 37 38 /** 39 * Flag to work with nested tag field 40 * 41 * @var boolean 42 * @since 3.1 43 */ 44 public $isNested = null; 45 46 /** 47 * com_tags parameters 48 * 49 * @var \Joomla\Registry\Registry 50 * @since 3.1 51 */ 52 protected $comParams = null; 53 54 /** 55 * Name of the layout being used to render the field 56 * 57 * @var string 58 * @since 4.0.0 59 */ 60 protected $layout = 'joomla.form.field.tag'; 61 62 /** 63 * Constructor 64 * 65 * @since 3.1 66 */ 67 public function __construct() 68 { 69 parent::__construct(); 70 71 // Load com_tags config 72 $this->comParams = ComponentHelper::getParams('com_tags'); 73 } 74 75 /** 76 * Method to get the field input for a tag field. 77 * 78 * @return string The field input. 79 * 80 * @since 3.1 81 */ 82 protected function getInput() 83 { 84 $data = $this->getLayoutData(); 85 86 if (!\is_array($this->value) && !empty($this->value)) { 87 if ($this->value instanceof TagsHelper) { 88 if (empty($this->value->tags)) { 89 $this->value = array(); 90 } else { 91 $this->value = $this->value->tags; 92 } 93 } 94 95 // String in format 2,5,4 96 if (\is_string($this->value)) { 97 $this->value = explode(',', $this->value); 98 } 99 100 // Integer is given 101 if (\is_int($this->value)) { 102 $this->value = array($this->value); 103 } 104 105 $data['value'] = $this->value; 106 } 107 108 $data['remoteSearch'] = $this->isRemoteSearch(); 109 $data['options'] = $this->getOptions(); 110 $data['isNested'] = $this->isNested(); 111 $data['allowCustom'] = $this->allowCustom(); 112 $data['minTermLength'] = (int) $this->comParams->get('min_term_length', 3); 113 114 return $this->getRenderer($this->layout)->render($data); 115 } 116 117 /** 118 * Method to get a list of tags 119 * 120 * @return array The field option objects. 121 * 122 * @since 3.1 123 */ 124 protected function getOptions() 125 { 126 $published = (string) $this->element['published'] ?: array(0, 1); 127 $app = Factory::getApplication(); 128 $language = null; 129 $options = []; 130 131 // This limit is only used with isRemoteSearch 132 $prefillLimit = 30; 133 $isRemoteSearch = $this->isRemoteSearch(); 134 135 $db = $this->getDatabase(); 136 $query = $db->getQuery(true) 137 ->select( 138 [ 139 $db->quoteName('a.id', 'value'), 140 $db->quoteName('a.path'), 141 $db->quoteName('a.title', 'text'), 142 $db->quoteName('a.level'), 143 $db->quoteName('a.published'), 144 $db->quoteName('a.lft'), 145 ] 146 ) 147 ->from($db->quoteName('#__tags', 'a')); 148 149 // Limit Options in multilanguage 150 if ($app->isClient('site') && Multilanguage::isEnabled()) { 151 if (ComponentHelper::getParams('com_tags')->get('tag_list_language_filter') === 'current_language') { 152 $language = [$app->getLanguage()->getTag(), '*']; 153 } 154 } elseif (!empty($this->element['language'])) { 155 // Filter language 156 if (strpos($this->element['language'], ',') !== false) { 157 $language = explode(',', $this->element['language']); 158 } else { 159 $language = [$this->element['language']]; 160 } 161 } 162 163 if ($language) { 164 $query->whereIn($db->quoteName('a.language'), $language, ParameterType::STRING); 165 } 166 167 $query->where($db->quoteName('a.lft') . ' > 0'); 168 169 // Filter on the published state 170 if (is_numeric($published)) { 171 $published = (int) $published; 172 $query->where($db->quoteName('a.published') . ' = :published') 173 ->bind(':published', $published, ParameterType::INTEGER); 174 } elseif (\is_array($published)) { 175 $published = ArrayHelper::toInteger($published); 176 $query->whereIn($db->quoteName('a.published'), $published); 177 } 178 179 $query->order($db->quoteName('a.lft') . ' ASC'); 180 181 // Preload only active values and 30 most used tags or fill up 182 if ($isRemoteSearch) { 183 // Load the most $prefillLimit used tags 184 $topQuery = $db->getQuery(true) 185 ->select($db->quoteName('tag_id')) 186 ->from($db->quoteName('#__contentitem_tag_map')) 187 ->group($db->quoteName('tag_id')) 188 ->order('count(*)') 189 ->setLimit($prefillLimit); 190 191 $db->setQuery($topQuery); 192 $topIds = $db->loadColumn(); 193 194 // Merge the used values into the most used tags 195 if (!empty($this->value) && is_array($this->value)) { 196 $topIds = array_merge($topIds, $this->value); 197 $topIds = array_keys(array_flip($topIds)); 198 } 199 200 // Set the default limit for the main query 201 $query->setLimit($prefillLimit); 202 203 if (!empty($topIds)) { 204 // Filter the ids to the most used tags and the selected tags 205 $preQuery = clone $query; 206 $preQuery->whereIn($db->quoteName('a.id'), $topIds); 207 208 $db->setQuery($preQuery); 209 210 try { 211 $options = $db->loadObjectList(); 212 } catch (\RuntimeException $e) { 213 return array(); 214 } 215 216 // Limit the main query to the missing amount of tags 217 $count = count($options); 218 $prefillLimit = $prefillLimit - $count; 219 $query->setLimit($prefillLimit); 220 221 // Exclude the already loaded tags from the main query 222 if ($count > 0) { 223 $query->whereNotIn($db->quoteName('a.id'), ArrayHelper::getColumn($options, 'value')); 224 } 225 } 226 } 227 228 // Only execute the query if we need more tags not already loaded by the $preQuery query 229 if (!$isRemoteSearch || $prefillLimit > 0) { 230 // Get the options. 231 $db->setQuery($query); 232 233 try { 234 $options = array_merge($options, $db->loadObjectList()); 235 } catch (\RuntimeException $e) { 236 return array(); 237 } 238 } 239 240 // Block the possibility to set a tag as it own parent 241 if ($this->form->getName() === 'com_tags.tag') { 242 $id = (int) $this->form->getValue('id', 0); 243 244 foreach ($options as $option) { 245 if ($option->value == $id) { 246 $option->disable = true; 247 } 248 } 249 } 250 251 // Merge any additional options in the XML definition. 252 $options = array_merge(parent::getOptions(), $options); 253 254 // Prepare nested data 255 if ($this->isNested()) { 256 $this->prepareOptionsNested($options); 257 } else { 258 $options = TagsHelper::convertPathsToNames($options); 259 } 260 261 return $options; 262 } 263 264 /** 265 * Add "-" before nested tags, depending on level 266 * 267 * @param array &$options Array of tags 268 * 269 * @return array The field option objects. 270 * 271 * @since 3.1 272 */ 273 protected function prepareOptionsNested(&$options) 274 { 275 if ($options) { 276 foreach ($options as &$option) { 277 $repeat = (isset($option->level) && $option->level - 1 >= 0) ? $option->level - 1 : 0; 278 $option->text = str_repeat('- ', $repeat) . $option->text; 279 } 280 } 281 282 return $options; 283 } 284 285 /** 286 * Determine if the field has to be tagnested 287 * 288 * @return boolean 289 * 290 * @since 3.1 291 */ 292 public function isNested() 293 { 294 if ($this->isNested === null) { 295 // If mode="nested" || ( mode not set & config = nested ) 296 if ( 297 isset($this->element['mode']) && (string) $this->element['mode'] === 'nested' 298 || !isset($this->element['mode']) && $this->comParams->get('tag_field_ajax_mode', 1) == 0 299 ) { 300 $this->isNested = true; 301 } 302 } 303 304 return $this->isNested; 305 } 306 307 /** 308 * Determines if the field allows or denies custom values 309 * 310 * @return boolean 311 */ 312 public function allowCustom() 313 { 314 if ($this->element['custom'] && \in_array((string) $this->element['custom'], array('0', 'false', 'deny'))) { 315 return false; 316 } 317 318 return Factory::getUser()->authorise('core.create', 'com_tags'); 319 } 320 321 /** 322 * Check whether need to enable AJAX search 323 * 324 * @return boolean 325 * 326 * @since 4.0.0 327 */ 328 public function isRemoteSearch() 329 { 330 if ($this->element['remote-search']) { 331 return !\in_array((string) $this->element['remote-search'], array('0', 'false', '')); 332 } 333 334 return $this->comParams->get('tag_field_ajax_mode', 1) == 1; 335 } 336 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |