[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @package Joomla.Administrator 5 * @subpackage com_finder 6 * 7 * @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> 8 * @license GNU General Public License version 2 or later; see LICENSE.txt 9 */ 10 11 namespace Joomla\Component\Finder\Administrator\Service\HTML; 12 13 use Joomla\CMS\Factory; 14 use Joomla\CMS\Filter\OutputFilter; 15 use Joomla\CMS\HTML\HTMLHelper; 16 use Joomla\CMS\Language\Multilanguage; 17 use Joomla\CMS\Language\Text; 18 use Joomla\Component\Finder\Administrator\Helper\LanguageHelper; 19 use Joomla\Component\Finder\Administrator\Indexer\Query; 20 use Joomla\Database\DatabaseAwareTrait; 21 use Joomla\Registry\Registry; 22 23 // phpcs:disable PSR1.Files.SideEffects 24 \defined('_JEXEC') or die; 25 // phpcs:enable PSR1.Files.SideEffects 26 27 /** 28 * Filter HTML Behaviors for Finder. 29 * 30 * @since 2.5 31 */ 32 class Filter 33 { 34 use DatabaseAwareTrait; 35 36 /** 37 * Method to generate filters using the slider widget and decorated 38 * with the FinderFilter JavaScript behaviors. 39 * 40 * @param array $options An array of configuration options. [optional] 41 * 42 * @return mixed A rendered HTML widget on success, null otherwise. 43 * 44 * @since 2.5 45 */ 46 public function slider($options = array()) 47 { 48 $db = $this->getDatabase(); 49 $query = $db->getQuery(true); 50 $user = Factory::getUser(); 51 $groups = implode(',', $user->getAuthorisedViewLevels()); 52 $html = ''; 53 $filter = null; 54 55 // Get the configuration options. 56 $filterId = $options['filter_id'] ?? null; 57 $activeNodes = array_key_exists('selected_nodes', $options) ? $options['selected_nodes'] : array(); 58 $classSuffix = array_key_exists('class_suffix', $options) ? $options['class_suffix'] : ''; 59 60 // Load the predefined filter if specified. 61 if (!empty($filterId)) { 62 $query->select('f.data, f.params') 63 ->from($db->quoteName('#__finder_filters') . ' AS f') 64 ->where('f.filter_id = ' . (int) $filterId); 65 66 // Load the filter data. 67 $db->setQuery($query); 68 69 try { 70 $filter = $db->loadObject(); 71 } catch (\RuntimeException $e) { 72 return null; 73 } 74 75 // Initialize the filter parameters. 76 if ($filter) { 77 $filter->params = new Registry($filter->params); 78 } 79 } 80 81 // Build the query to get the branch data and the number of child nodes. 82 $query->clear() 83 ->select('t.*, count(c.id) AS children') 84 ->from($db->quoteName('#__finder_taxonomy') . ' AS t') 85 ->join('INNER', $db->quoteName('#__finder_taxonomy') . ' AS c ON c.parent_id = t.id') 86 ->where('t.parent_id = 1') 87 ->where('t.state = 1') 88 ->where('t.access IN (' . $groups . ')') 89 ->group('t.id, t.parent_id, t.state, t.access, t.title, c.parent_id') 90 ->order('t.lft, t.title'); 91 92 // Limit the branch children to a predefined filter. 93 if ($filter) { 94 $query->where('c.id IN(' . $filter->data . ')'); 95 } 96 97 // Load the branches. 98 $db->setQuery($query); 99 100 try { 101 $branches = $db->loadObjectList('id'); 102 } catch (\RuntimeException $e) { 103 return null; 104 } 105 106 // Check that we have at least one branch. 107 if (count($branches) === 0) { 108 return null; 109 } 110 111 $branch_keys = array_keys($branches); 112 $html .= HTMLHelper::_('bootstrap.startAccordion', 'accordion', array('active' => 'accordion-' . $branch_keys[0])); 113 114 // Load plugin language files. 115 LanguageHelper::loadPluginLanguage(); 116 117 // Iterate through the branches and build the branch groups. 118 foreach ($branches as $bk => $bv) { 119 // If the multi-lang plugin is enabled then drop the language branch. 120 if ($bv->title === 'Language' && Multilanguage::isEnabled()) { 121 continue; 122 } 123 124 // Build the query to get the child nodes for this branch. 125 $query->clear() 126 ->select('t.*') 127 ->from($db->quoteName('#__finder_taxonomy') . ' AS t') 128 ->where('t.lft > ' . (int) $bv->lft) 129 ->where('t.rgt < ' . (int) $bv->rgt) 130 ->where('t.state = 1') 131 ->where('t.access IN (' . $groups . ')') 132 ->order('t.lft, t.title'); 133 134 // Self-join to get the parent title. 135 $query->select('e.title AS parent_title') 136 ->join('LEFT', $db->quoteName('#__finder_taxonomy', 'e') . ' ON ' . $db->quoteName('e.id') . ' = ' . $db->quoteName('t.parent_id')); 137 138 // Load the branches. 139 $db->setQuery($query); 140 141 try { 142 $nodes = $db->loadObjectList('id'); 143 } catch (\RuntimeException $e) { 144 return null; 145 } 146 147 // Translate node titles if possible. 148 $lang = Factory::getLanguage(); 149 150 foreach ($nodes as $nk => $nv) { 151 if (trim($nv->parent_title, '*') === 'Language') { 152 $title = LanguageHelper::branchLanguageTitle($nv->title); 153 } else { 154 $key = LanguageHelper::branchPlural($nv->title); 155 $title = $lang->hasKey($key) ? Text::_($key) : $nv->title; 156 } 157 158 $nodes[$nk]->title = $title; 159 } 160 161 // Adding slides 162 $html .= HTMLHelper::_( 163 'bootstrap.addSlide', 164 'accordion', 165 Text::sprintf( 166 'COM_FINDER_FILTER_BRANCH_LABEL', 167 Text::_(LanguageHelper::branchSingular($bv->title)) . ' - ' . count($nodes) 168 ), 169 'accordion-' . $bk 170 ); 171 172 // Populate the toggle button. 173 $html .= '<button class="btn btn-secondary js-filter" type="button" data-id="tax-' . $bk . '"><span class="icon-square" aria-hidden="true"></span> ' 174 . Text::_('JGLOBAL_SELECTION_INVERT') . '</button><hr>'; 175 176 // Populate the group with nodes. 177 foreach ($nodes as $nk => $nv) { 178 // Determine if the node should be checked. 179 $checked = in_array($nk, $activeNodes) ? ' checked="checked"' : ''; 180 181 // Build a node. 182 $html .= '<div class="form-check">'; 183 $html .= '<label class="form-check-label">'; 184 $html .= '<input type="checkbox" class="form-check-input selector filter-node' . $classSuffix 185 . ' tax-' . $bk . '" value="' . $nk . '" name="t[]"' . $checked . '> ' . str_repeat('—', $nv->level - 2) . $nv->title; 186 $html .= '</label>'; 187 $html .= '</div>'; 188 } 189 190 $html .= HTMLHelper::_('bootstrap.endSlide'); 191 } 192 193 $html .= HTMLHelper::_('bootstrap.endAccordion'); 194 195 return $html; 196 } 197 198 /** 199 * Method to generate filters using select box dropdown controls. 200 * 201 * @param Query $idxQuery A Query object. 202 * @param array $options An array of options. 203 * 204 * @return mixed A rendered HTML widget on success, null otherwise. 205 * 206 * @since 2.5 207 */ 208 public function select($idxQuery, $options) 209 { 210 $user = Factory::getUser(); 211 $groups = implode(',', $user->getAuthorisedViewLevels()); 212 $filter = null; 213 214 // Get the configuration options. 215 $classSuffix = $options->get('class_suffix', null); 216 $showDates = $options->get('show_date_filters', false); 217 218 // Try to load the results from cache. 219 $cache = Factory::getCache('com_finder', ''); 220 $cacheId = 'filter_select_' . serialize(array($idxQuery->filter, $options, $groups, Factory::getLanguage()->getTag())); 221 222 // Check the cached results. 223 if ($cache->contains($cacheId)) { 224 $branches = $cache->get($cacheId); 225 } else { 226 $db = $this->getDatabase(); 227 $query = $db->getQuery(true); 228 229 // Load the predefined filter if specified. 230 if (!empty($idxQuery->filter)) { 231 $query->select('f.data, ' . $db->quoteName('f.params')) 232 ->from($db->quoteName('#__finder_filters') . ' AS f') 233 ->where('f.filter_id = ' . (int) $idxQuery->filter); 234 235 // Load the filter data. 236 $db->setQuery($query); 237 238 try { 239 $filter = $db->loadObject(); 240 } catch (\RuntimeException $e) { 241 return null; 242 } 243 244 // Initialize the filter parameters. 245 if ($filter) { 246 $filter->params = new Registry($filter->params); 247 } 248 } 249 250 // Build the query to get the branch data and the number of child nodes. 251 $query->clear() 252 ->select('t.*, count(c.id) AS children') 253 ->from($db->quoteName('#__finder_taxonomy') . ' AS t') 254 ->join('INNER', $db->quoteName('#__finder_taxonomy') . ' AS c ON c.parent_id = t.id') 255 ->where('t.parent_id = 1') 256 ->where('t.state = 1') 257 ->where('t.access IN (' . $groups . ')') 258 ->where('c.state = 1') 259 ->where('c.access IN (' . $groups . ')') 260 ->group($db->quoteName('t.id')) 261 ->group($db->quoteName('t.parent_id')) 262 ->group('t.title, t.state, t.access, t.lft') 263 ->order('t.lft, t.title'); 264 265 // Limit the branch children to a predefined filter. 266 if (!empty($filter->data)) { 267 $query->where('c.id IN(' . $filter->data . ')'); 268 } 269 270 // Load the branches. 271 $db->setQuery($query); 272 273 try { 274 $branches = $db->loadObjectList('id'); 275 } catch (\RuntimeException $e) { 276 return null; 277 } 278 279 // Check that we have at least one branch. 280 if (count($branches) === 0) { 281 return null; 282 } 283 284 // Iterate through the branches and build the branch groups. 285 foreach ($branches as $bk => $bv) { 286 // If the multi-lang plugin is enabled then drop the language branch. 287 if ($bv->title === 'Language' && Multilanguage::isEnabled()) { 288 continue; 289 } 290 291 // Build the query to get the child nodes for this branch. 292 $query->clear() 293 ->select('t.*') 294 ->from($db->quoteName('#__finder_taxonomy') . ' AS t') 295 ->where('t.lft > ' . (int) $bv->lft) 296 ->where('t.rgt < ' . (int) $bv->rgt) 297 ->where('t.state = 1') 298 ->where('t.access IN (' . $groups . ')') 299 ->order('t.title'); 300 301 // Self-join to get the parent title. 302 $query->select('e.title AS parent_title') 303 ->join('LEFT', $db->quoteName('#__finder_taxonomy', 'e') . ' ON ' . $db->quoteName('e.id') . ' = ' . $db->quoteName('t.parent_id')); 304 305 // Limit the nodes to a predefined filter. 306 if (!empty($filter->data)) { 307 $query->where('t.id IN(' . $filter->data . ')'); 308 } 309 310 // Load the branches. 311 $db->setQuery($query); 312 313 try { 314 $branches[$bk]->nodes = $db->loadObjectList('id'); 315 } catch (\RuntimeException $e) { 316 return null; 317 } 318 319 // Translate branch nodes if possible. 320 $language = Factory::getLanguage(); 321 322 foreach ($branches[$bk]->nodes as $node_id => $node) { 323 if (trim($node->parent_title, '*') === 'Language') { 324 $title = LanguageHelper::branchLanguageTitle($node->title); 325 } else { 326 $key = LanguageHelper::branchPlural($node->title); 327 $title = $language->hasKey($key) ? Text::_($key) : $node->title; 328 } 329 330 if ($node->level > 2) { 331 $branches[$bk]->nodes[$node_id]->title = str_repeat('-', $node->level - 2) . $title; 332 } else { 333 $branches[$bk]->nodes[$node_id]->title = $title; 334 } 335 } 336 337 // Add the Search All option to the branch. 338 array_unshift($branches[$bk]->nodes, array('id' => null, 'title' => Text::_('COM_FINDER_FILTER_SELECT_ALL_LABEL'))); 339 } 340 341 // Store the data in cache. 342 $cache->store($branches, $cacheId); 343 } 344 345 $html = ''; 346 347 // Add the dates if enabled. 348 if ($showDates) { 349 $html .= HTMLHelper::_('filter.dates', $idxQuery, $options); 350 } 351 352 $html .= '<div class="filter-branch' . $classSuffix . '">'; 353 354 // Iterate through all branches and build code. 355 foreach ($branches as $bk => $bv) { 356 // If the multi-lang plugin is enabled then drop the language branch. 357 if ($bv->title === 'Language' && Multilanguage::isEnabled()) { 358 continue; 359 } 360 361 $active = null; 362 363 // Check if the branch is in the filter. 364 if (array_key_exists($bv->title, $idxQuery->filters)) { 365 // Get the request filters. 366 $temp = Factory::getApplication()->input->request->get('t', array(), 'array'); 367 368 // Search for active nodes in the branch and get the active node. 369 $active = array_intersect($temp, $idxQuery->filters[$bv->title]); 370 $active = count($active) === 1 ? array_shift($active) : null; 371 } 372 373 // Build a node. 374 $html .= '<div class="control-group">'; 375 $html .= '<div class="control-label">'; 376 $html .= '<label for="tax-' . OutputFilter::stringURLSafe($bv->title) . '">'; 377 $html .= Text::sprintf('COM_FINDER_FILTER_BRANCH_LABEL', Text::_(LanguageHelper::branchSingular($bv->title))); 378 $html .= '</label>'; 379 $html .= '</div>'; 380 $html .= '<div class="controls">'; 381 $html .= HTMLHelper::_( 382 'select.genericlist', 383 $branches[$bk]->nodes, 384 't[]', 385 'class="form-select advancedSelect"', 386 'id', 387 'title', 388 $active, 389 'tax-' . OutputFilter::stringURLSafe($bv->title) 390 ); 391 $html .= '</div>'; 392 $html .= '</div>'; 393 } 394 395 $html .= '</div>'; 396 397 return $html; 398 } 399 400 /** 401 * Method to generate fields for filtering dates 402 * 403 * @param Query $idxQuery A Query object. 404 * @param array $options An array of options. 405 * 406 * @return mixed A rendered HTML widget on success, null otherwise. 407 * 408 * @since 2.5 409 */ 410 public function dates($idxQuery, $options) 411 { 412 $html = ''; 413 414 // Get the configuration options. 415 $classSuffix = $options->get('class_suffix', null); 416 $loadMedia = $options->get('load_media', true); 417 $showDates = $options->get('show_date_filters', false); 418 419 if (!empty($showDates)) { 420 // Build the date operators options. 421 $operators = array(); 422 $operators[] = HTMLHelper::_('select.option', 'before', Text::_('COM_FINDER_FILTER_DATE_BEFORE')); 423 $operators[] = HTMLHelper::_('select.option', 'exact', Text::_('COM_FINDER_FILTER_DATE_EXACTLY')); 424 $operators[] = HTMLHelper::_('select.option', 'after', Text::_('COM_FINDER_FILTER_DATE_AFTER')); 425 426 // Load the CSS/JS resources. 427 if ($loadMedia) { 428 /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ 429 $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); 430 $wa->useStyle('com_finder.dates'); 431 } 432 433 // Open the widget. 434 $html .= '<ul id="finder-filter-select-dates">'; 435 436 // Start date filter. 437 $attribs['class'] = 'input-medium'; 438 $html .= '<li class="filter-date float-start' . $classSuffix . '">'; 439 $html .= '<label for="filter_date1" class="hasTooltip" title ="' . Text::_('COM_FINDER_FILTER_DATE1_DESC') . '">'; 440 $html .= Text::_('COM_FINDER_FILTER_DATE1'); 441 $html .= '</label>'; 442 $html .= '<br>'; 443 $html .= HTMLHelper::_( 444 'select.genericlist', 445 $operators, 446 'w1', 447 'class="inputbox filter-date-operator advancedSelect form-select w-auto mb-2"', 448 'value', 449 'text', 450 $idxQuery->when1, 451 'finder-filter-w1' 452 ); 453 $html .= HTMLHelper::_('calendar', $idxQuery->date1, 'd1', 'filter_date1', '%Y-%m-%d', $attribs); 454 $html .= '</li>'; 455 456 // End date filter. 457 $html .= '<li class="filter-date float-end' . $classSuffix . '">'; 458 $html .= '<label for="filter_date2" class="hasTooltip" title ="' . Text::_('COM_FINDER_FILTER_DATE2_DESC') . '">'; 459 $html .= Text::_('COM_FINDER_FILTER_DATE2'); 460 $html .= '</label>'; 461 $html .= '<br>'; 462 $html .= HTMLHelper::_( 463 'select.genericlist', 464 $operators, 465 'w2', 466 'class="inputbox filter-date-operator advancedSelect form-select w-auto mb-2"', 467 'value', 468 'text', 469 $idxQuery->when2, 470 'finder-filter-w2' 471 ); 472 $html .= HTMLHelper::_('calendar', $idxQuery->date2, 'd2', 'filter_date2', '%Y-%m-%d', $attribs); 473 $html .= '</li>'; 474 475 // Close the widget. 476 $html .= '</ul>'; 477 } 478 479 return $html; 480 } 481 }
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 |