[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/src/Form/Field/ -> TagField.php (source)

   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  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer