[ 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) 2005 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\Helper; 11 12 use Joomla\CMS\Cache\CacheControllerFactoryInterface; 13 use Joomla\CMS\Cache\Controller\CallbackController; 14 use Joomla\CMS\Component\ComponentHelper; 15 use Joomla\CMS\Factory; 16 use Joomla\CMS\Filesystem\Path; 17 use Joomla\CMS\Filter\InputFilter; 18 use Joomla\CMS\Language\LanguageHelper; 19 use Joomla\CMS\Language\Text; 20 use Joomla\CMS\Layout\LayoutHelper; 21 use Joomla\CMS\Log\Log; 22 use Joomla\CMS\Profiler\Profiler; 23 use Joomla\Database\ParameterType; 24 use Joomla\Registry\Registry; 25 26 // phpcs:disable PSR1.Files.SideEffects 27 \defined('JPATH_PLATFORM') or die; 28 // phpcs:enable PSR1.Files.SideEffects 29 30 /** 31 * Module helper class 32 * 33 * @since 1.5 34 */ 35 abstract class ModuleHelper 36 { 37 /** 38 * Get module by name (real, eg 'Breadcrumbs' or folder, eg 'mod_breadcrumbs') 39 * 40 * @param string $name The name of the module 41 * @param string $title The title of the module, optional 42 * 43 * @return \stdClass The Module object 44 * 45 * @since 1.5 46 */ 47 public static function &getModule($name, $title = null) 48 { 49 $result = null; 50 $modules =& static::load(); 51 $total = \count($modules); 52 53 for ($i = 0; $i < $total; $i++) { 54 // Match the name of the module 55 if ($modules[$i]->name === $name || $modules[$i]->module === $name) { 56 // Match the title if we're looking for a specific instance of the module 57 if (!$title || $modules[$i]->title === $title) { 58 // Found it 59 $result = &$modules[$i]; 60 break; 61 } 62 } 63 } 64 65 // If we didn't find it, and the name is mod_something, create a dummy object 66 if ($result === null && strpos($name, 'mod_') === 0) { 67 $result = static::createDummyModule(); 68 $result->module = $name; 69 } 70 71 return $result; 72 } 73 74 /** 75 * Get modules by position 76 * 77 * @param string $position The position of the module 78 * 79 * @return array An array of module objects 80 * 81 * @since 1.5 82 */ 83 public static function &getModules($position) 84 { 85 $position = strtolower($position); 86 $result = array(); 87 $input = Factory::getApplication()->input; 88 $modules = &static::load(); 89 $total = \count($modules); 90 91 for ($i = 0; $i < $total; $i++) { 92 if ($modules[$i]->position === $position) { 93 $result[] = &$modules[$i]; 94 } 95 } 96 97 // Prepend a dummy module for template preview if no module is published in the position 98 if (empty($result) && $input->getBool('tp') && ComponentHelper::getParams('com_templates')->get('template_positions_display')) { 99 $dummy = static::createDummyModule(); 100 $dummy->title = $position; 101 $dummy->position = $position; 102 $dummy->content = $position; 103 $dummy->contentRendered = true; 104 105 array_unshift($result, $dummy); 106 } 107 108 return $result; 109 } 110 111 /** 112 * Checks if a module is enabled. A given module will only be returned 113 * if it meets the following criteria: it is enabled, it is assigned to 114 * the current menu item or all items, and the user meets the access level 115 * requirements. 116 * 117 * @param string $module The module name 118 * 119 * @return boolean See description for conditions. 120 * 121 * @since 1.5 122 */ 123 public static function isEnabled($module) 124 { 125 $result = static::getModule($module); 126 127 return $result !== null && $result->id !== 0; 128 } 129 130 /** 131 * Render the module. 132 * 133 * @param object $module A module object. 134 * @param array $attribs An array of attributes for the module (probably from the XML). 135 * 136 * @return string The HTML content of the module output. 137 * 138 * @since 1.5 139 */ 140 public static function renderModule($module, $attribs = array()) 141 { 142 $app = Factory::getApplication(); 143 144 // Check that $module is a valid module object 145 if (!\is_object($module) || !isset($module->module) || !isset($module->params)) { 146 if (JDEBUG) { 147 Log::addLogger(array('text_file' => 'jmodulehelper.log.php'), Log::ALL, array('modulehelper')); 148 $app->getLogger()->debug( 149 __METHOD__ . '() - The $module parameter should be a module object.', 150 array('category' => 'modulehelper') 151 ); 152 } 153 154 return ''; 155 } 156 157 // Get module parameters 158 $params = new Registry($module->params); 159 160 // Render the module content 161 static::renderRawModule($module, $params, $attribs); 162 163 // Return early if only the content is required 164 if (!empty($attribs['contentOnly'])) { 165 return $module->content; 166 } 167 168 if (JDEBUG) { 169 Profiler::getInstance('Application')->mark('beforeRenderModule ' . $module->module . ' (' . $module->title . ')'); 170 } 171 172 // Record the scope. 173 $scope = $app->scope; 174 175 // Set scope to component name 176 $app->scope = $module->module; 177 178 // Get the template 179 $template = $app->getTemplate(); 180 181 // Check if the current module has a style param to override template module style 182 $paramsChromeStyle = $params->get('style'); 183 $basePath = ''; 184 185 if ($paramsChromeStyle) { 186 $paramsChromeStyle = explode('-', $paramsChromeStyle, 2); 187 $ChromeStyleTemplate = strtolower($paramsChromeStyle[0]); 188 $attribs['style'] = $paramsChromeStyle[1]; 189 190 // Only set $basePath if the specified template isn't the current or system one. 191 if ($ChromeStyleTemplate !== $template && $ChromeStyleTemplate !== 'system') { 192 $basePath = JPATH_THEMES . '/' . $ChromeStyleTemplate . '/html/layouts'; 193 } 194 } 195 196 // Make sure a style is set 197 if (!isset($attribs['style'])) { 198 $attribs['style'] = 'none'; 199 } 200 201 // Dynamically add outline style 202 if ($app->input->getBool('tp') && ComponentHelper::getParams('com_templates')->get('template_positions_display')) { 203 $attribs['style'] .= ' outline'; 204 } 205 206 $module->style = $attribs['style']; 207 208 // If the $module is nulled it will return an empty content, otherwise it will render the module normally. 209 $app->triggerEvent('onRenderModule', array(&$module, &$attribs)); 210 211 if ($module === null || !isset($module->content)) { 212 return ''; 213 } 214 215 $displayData = array( 216 'module' => $module, 217 'params' => $params, 218 'attribs' => $attribs, 219 ); 220 221 foreach (explode(' ', $attribs['style']) as $style) { 222 if ($moduleContent = LayoutHelper::render('chromes.' . $style, $displayData, $basePath)) { 223 $module->content = $moduleContent; 224 } 225 } 226 227 // Revert the scope 228 $app->scope = $scope; 229 230 $app->triggerEvent('onAfterRenderModule', array(&$module, &$attribs)); 231 232 if (JDEBUG) { 233 Profiler::getInstance('Application')->mark('afterRenderModule ' . $module->module . ' (' . $module->title . ')'); 234 } 235 236 return $module->content; 237 } 238 239 /** 240 * Render the module content. 241 * 242 * @param object $module A module object 243 * @param Registry $params A module parameters 244 * @param array $attribs An array of attributes for the module (probably from the XML). 245 * 246 * @return string 247 * 248 * @since 4.0.0 249 */ 250 public static function renderRawModule($module, Registry $params, $attribs = array()) 251 { 252 if (!empty($module->contentRendered)) { 253 return $module->content; 254 } 255 256 if (JDEBUG) { 257 Profiler::getInstance('Application')->mark('beforeRenderRawModule ' . $module->module . ' (' . $module->title . ')'); 258 } 259 260 $app = Factory::getApplication(); 261 262 // Record the scope. 263 $scope = $app->scope; 264 265 // Set scope to component name 266 $app->scope = $module->module; 267 268 // Get module path 269 $module->module = preg_replace('/[^A-Z0-9_\.-]/i', '', $module->module); 270 271 $dispatcher = $app->bootModule($module->module, $app->getName())->getDispatcher($module, $app); 272 273 // Check if we have a dispatcher 274 if ($dispatcher) { 275 ob_start(); 276 $dispatcher->dispatch(); 277 $module->content = ob_get_clean(); 278 } 279 280 // Add the flag that the module content has been rendered 281 $module->contentRendered = true; 282 283 // Revert the scope 284 $app->scope = $scope; 285 286 if (JDEBUG) { 287 Profiler::getInstance('Application')->mark('afterRenderRawModule ' . $module->module . ' (' . $module->title . ')'); 288 } 289 290 return $module->content; 291 } 292 293 /** 294 * Get the path to a layout for a module 295 * 296 * @param string $module The name of the module 297 * @param string $layout The name of the module layout. If alternative layout, in the form template:filename. 298 * 299 * @return string The path to the module layout 300 * 301 * @since 1.5 302 */ 303 public static function getLayoutPath($module, $layout = 'default') 304 { 305 $templateObj = Factory::getApplication()->getTemplate(true); 306 $defaultLayout = $layout; 307 $template = $templateObj->template; 308 309 if (strpos($layout, ':') !== false) { 310 // Get the template and file name from the string 311 $temp = explode(':', $layout); 312 $template = $temp[0] === '_' ? $template : $temp[0]; 313 $layout = $temp[1]; 314 $defaultLayout = $temp[1] ?: 'default'; 315 } 316 317 $dPath = JPATH_BASE . '/modules/' . $module . '/tmpl/default.php'; 318 319 try { 320 // Build the template and base path for the layout 321 $tPath = Path::check(JPATH_THEMES . '/' . $template . '/html/' . $module . '/' . $layout . '.php'); 322 $iPath = Path::check(JPATH_THEMES . '/' . $templateObj->parent . '/html/' . $module . '/' . $layout . '.php'); 323 $bPath = Path::check(JPATH_BASE . '/modules/' . $module . '/tmpl/' . $defaultLayout . '.php'); 324 } catch (\Exception $e) { 325 // On error fallback to the default path 326 return $dPath; 327 } 328 329 // If the template has a layout override use it 330 if (is_file($tPath)) { 331 return $tPath; 332 } 333 334 if (!empty($templateObj->parent) && is_file($iPath)) { 335 return $iPath; 336 } 337 338 if (is_file($bPath)) { 339 return $bPath; 340 } 341 342 return $dPath; 343 } 344 345 /** 346 * Load published modules. 347 * 348 * @return array 349 * 350 * @since 3.2 351 */ 352 protected static function &load() 353 { 354 static $modules; 355 356 if (isset($modules)) { 357 return $modules; 358 } 359 360 $app = Factory::getApplication(); 361 362 $modules = null; 363 364 $app->triggerEvent('onPrepareModuleList', array(&$modules)); 365 366 // If the onPrepareModuleList event returns an array of modules, then ignore the default module list creation 367 if (!\is_array($modules)) { 368 $modules = static::getModuleList(); 369 } 370 371 $app->triggerEvent('onAfterModuleList', array(&$modules)); 372 373 $modules = static::cleanModuleList($modules); 374 375 $app->triggerEvent('onAfterCleanModuleList', array(&$modules)); 376 377 return $modules; 378 } 379 380 /** 381 * Module list 382 * 383 * @return array 384 */ 385 public static function getModuleList() 386 { 387 $app = Factory::getApplication(); 388 $itemId = $app->input->getInt('Itemid', 0); 389 $groups = $app->getIdentity()->getAuthorisedViewLevels(); 390 $clientId = (int) $app->getClientId(); 391 392 // Build a cache ID for the resulting data object 393 $cacheId = implode(',', $groups) . '.' . $clientId . '.' . $itemId; 394 395 $db = Factory::getDbo(); 396 $query = $db->getQuery(true); 397 $nowDate = Factory::getDate()->toSql(); 398 399 $query->select($db->quoteName(['m.id', 'm.title', 'm.module', 'm.position', 'm.content', 'm.showtitle', 'm.params', 'mm.menuid'])) 400 ->from($db->quoteName('#__modules', 'm')) 401 ->join( 402 'LEFT', 403 $db->quoteName('#__modules_menu', 'mm'), 404 $db->quoteName('mm.moduleid') . ' = ' . $db->quoteName('m.id') 405 ) 406 ->join( 407 'LEFT', 408 $db->quoteName('#__extensions', 'e'), 409 $db->quoteName('e.element') . ' = ' . $db->quoteName('m.module') 410 . ' AND ' . $db->quoteName('e.client_id') . ' = ' . $db->quoteName('m.client_id') 411 ) 412 ->where( 413 [ 414 $db->quoteName('m.published') . ' = 1', 415 $db->quoteName('e.enabled') . ' = 1', 416 $db->quoteName('m.client_id') . ' = :clientId', 417 ] 418 ) 419 ->bind(':clientId', $clientId, ParameterType::INTEGER) 420 ->whereIn($db->quoteName('m.access'), $groups) 421 ->extendWhere( 422 'AND', 423 [ 424 $db->quoteName('m.publish_up') . ' IS NULL', 425 $db->quoteName('m.publish_up') . ' <= :publishUp', 426 ], 427 'OR' 428 ) 429 ->bind(':publishUp', $nowDate) 430 ->extendWhere( 431 'AND', 432 [ 433 $db->quoteName('m.publish_down') . ' IS NULL', 434 $db->quoteName('m.publish_down') . ' >= :publishDown', 435 ], 436 'OR' 437 ) 438 ->bind(':publishDown', $nowDate) 439 ->extendWhere( 440 'AND', 441 [ 442 $db->quoteName('mm.menuid') . ' = :itemId', 443 $db->quoteName('mm.menuid') . ' <= 0', 444 ], 445 'OR' 446 ) 447 ->bind(':itemId', $itemId, ParameterType::INTEGER); 448 449 // Filter by language 450 if ($app->isClient('site') && $app->getLanguageFilter() || $app->isClient('administrator') && static::isAdminMultilang()) { 451 $language = $app->getLanguage()->getTag(); 452 453 $query->whereIn($db->quoteName('m.language'), [$language, '*'], ParameterType::STRING); 454 $cacheId .= $language . '*'; 455 } 456 457 $query->order($db->quoteName(['m.position', 'm.ordering'])); 458 459 // Set the query 460 $db->setQuery($query); 461 462 try { 463 /** @var CallbackController $cache */ 464 $cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class) 465 ->createCacheController('callback', ['defaultgroup' => 'com_modules']); 466 467 $modules = $cache->get(array($db, 'loadObjectList'), array(), md5($cacheId), false); 468 } catch (\RuntimeException $e) { 469 $app->getLogger()->warning( 470 Text::sprintf('JLIB_APPLICATION_ERROR_MODULE_LOAD', $e->getMessage()), 471 array('category' => 'jerror') 472 ); 473 474 return array(); 475 } 476 477 return $modules; 478 } 479 480 /** 481 * Clean the module list 482 * 483 * @param array $modules Array with module objects 484 * 485 * @return array 486 */ 487 public static function cleanModuleList($modules) 488 { 489 // Apply negative selections and eliminate duplicates 490 $Itemid = Factory::getApplication()->input->getInt('Itemid'); 491 $negId = $Itemid ? -(int) $Itemid : false; 492 $clean = array(); 493 $dupes = array(); 494 495 foreach ($modules as $i => $module) { 496 // The module is excluded if there is an explicit prohibition 497 $negHit = ($negId === (int) $module->menuid); 498 499 if (isset($dupes[$module->id])) { 500 // If this item has been excluded, keep the duplicate flag set, 501 // but remove any item from the modules array. 502 if ($negHit) { 503 unset($clean[$module->id]); 504 } 505 506 continue; 507 } 508 509 $dupes[$module->id] = true; 510 511 // Only accept modules without explicit exclusions. 512 if ($negHit) { 513 continue; 514 } 515 516 $module->name = substr($module->module, 4); 517 $module->style = null; 518 $module->position = strtolower($module->position); 519 520 $clean[$module->id] = $module; 521 } 522 523 unset($dupes); 524 525 // Return to simple indexing that matches the query order. 526 return array_values($clean); 527 } 528 529 /** 530 * Module cache helper 531 * 532 * Caching modes: 533 * To be set in XML: 534 * 'static' One cache file for all pages with the same module parameters 535 * 'itemid' Changes on itemid change, to be called from inside the module: 536 * 'safeuri' Id created from $cacheparams->modeparams array, 537 * 'id' Module sets own cache id's 538 * 539 * @param object $module Module object 540 * @param object $moduleparams Module parameters 541 * @param object $cacheparams Module cache parameters - id or URL parameters, depending on the module cache mode 542 * 543 * @return string 544 * 545 * @see InputFilter::clean() 546 * @since 1.6 547 */ 548 public static function moduleCache($module, $moduleparams, $cacheparams) 549 { 550 if (!isset($cacheparams->modeparams)) { 551 $cacheparams->modeparams = null; 552 } 553 554 if (!isset($cacheparams->cachegroup)) { 555 $cacheparams->cachegroup = $module->module; 556 } 557 558 if (!isset($cacheparams->cachesuffix)) { 559 $cacheparams->cachesuffix = ''; 560 } 561 562 $user = Factory::getUser(); 563 $app = Factory::getApplication(); 564 565 /** @var CallbackController $cache */ 566 $cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class) 567 ->createCacheController('callback', ['defaultgroup' => $cacheparams->cachegroup]); 568 569 // Turn cache off for internal callers if parameters are set to off and for all logged in users 570 $ownCacheDisabled = $moduleparams->get('owncache') === 0 || $moduleparams->get('owncache') === '0'; 571 $cacheDisabled = $moduleparams->get('cache') === 0 || $moduleparams->get('cache') === '0'; 572 573 if ($ownCacheDisabled || $cacheDisabled || $app->get('caching') == 0 || $user->get('id')) { 574 $cache->setCaching(false); 575 } 576 577 // Module cache is set in seconds, global cache in minutes, setLifeTime works in minutes 578 $cache->setLifeTime($moduleparams->get('cache_time', $app->get('cachetime') * 60) / 60); 579 580 $wrkaroundoptions = array('nopathway' => 1, 'nohead' => 0, 'nomodules' => 1, 'modulemode' => 1, 'mergehead' => 1); 581 582 $wrkarounds = true; 583 $view_levels = md5(serialize($user->getAuthorisedViewLevels())); 584 585 switch ($cacheparams->cachemode) { 586 case 'id': 587 $ret = $cache->get( 588 array($cacheparams->class, $cacheparams->method), 589 $cacheparams->methodparams, 590 $cacheparams->modeparams . $cacheparams->cachesuffix, 591 $wrkarounds, 592 $wrkaroundoptions 593 ); 594 break; 595 596 case 'safeuri': 597 $secureid = null; 598 599 if (\is_array($cacheparams->modeparams)) { 600 $input = $app->input; 601 $uri = $input->getArray(); 602 $safeuri = new \stdClass(); 603 $noHtmlFilter = InputFilter::getInstance(); 604 605 foreach ($cacheparams->modeparams as $key => $value) { 606 // Use int filter for id/catid to clean out spamy slugs 607 if (isset($uri[$key])) { 608 $safeuri->$key = $noHtmlFilter->clean($uri[$key], $value); 609 } 610 } 611 } 612 613 $secureid = md5(serialize(array($safeuri, $cacheparams->method, $moduleparams))); 614 $ret = $cache->get( 615 array($cacheparams->class, $cacheparams->method), 616 $cacheparams->methodparams, 617 $module->id . $view_levels . $secureid . $cacheparams->cachesuffix, 618 $wrkarounds, 619 $wrkaroundoptions 620 ); 621 break; 622 623 case 'static': 624 $ret = $cache->get( 625 array($cacheparams->class, $cacheparams->method), 626 $cacheparams->methodparams, 627 $module->module . md5(serialize($cacheparams->methodparams)) . $cacheparams->cachesuffix, 628 $wrkarounds, 629 $wrkaroundoptions 630 ); 631 break; 632 633 case 'itemid': 634 default: 635 $ret = $cache->get( 636 array($cacheparams->class, $cacheparams->method), 637 $cacheparams->methodparams, 638 $module->id . $view_levels . $app->input->getInt('Itemid', null) . $cacheparams->cachesuffix, 639 $wrkarounds, 640 $wrkaroundoptions 641 ); 642 break; 643 } 644 645 return $ret; 646 } 647 648 /** 649 * Method to determine if filtering by language is enabled in back-end for modules. 650 * 651 * @return boolean True if enabled; false otherwise. 652 * 653 * @since 3.8.0 654 */ 655 public static function isAdminMultilang() 656 { 657 static $enabled = false; 658 659 if (\count(LanguageHelper::getInstalledLanguages(1)) > 1) { 660 $enabled = (bool) ComponentHelper::getParams('com_modules')->get('adminlangfilter', 0); 661 } 662 663 return $enabled; 664 } 665 666 /** 667 * Get module by id 668 * 669 * @param string $id The id of the module 670 * 671 * @return \stdClass The Module object 672 * 673 * @since 3.9.0 674 */ 675 public static function &getModuleById($id) 676 { 677 $modules =& static::load(); 678 679 $total = \count($modules); 680 681 for ($i = 0; $i < $total; $i++) { 682 // Match the id of the module 683 if ((string) $modules[$i]->id === $id) { 684 // Found it 685 return $modules[$i]; 686 } 687 } 688 689 // If we didn't find it, create a dummy object 690 $result = static::createDummyModule(); 691 692 return $result; 693 } 694 695 /** 696 * Method to create a dummy module. 697 * 698 * @return \stdClass The Module object 699 * 700 * @since 4.0.0 701 */ 702 protected static function createDummyModule(): \stdClass 703 { 704 $module = new \stdClass(); 705 $module->id = 0; 706 $module->title = ''; 707 $module->module = ''; 708 $module->position = ''; 709 $module->content = ''; 710 $module->showtitle = 0; 711 $module->control = ''; 712 $module->params = ''; 713 714 return $module; 715 } 716 }
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 |