[ 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) 2012 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\Layout; 11 12 use Joomla\CMS\Application\ApplicationHelper; 13 use Joomla\CMS\Component\ComponentHelper; 14 use Joomla\CMS\Factory; 15 use Joomla\CMS\Filesystem\Path; 16 use Joomla\CMS\Version; 17 18 // phpcs:disable PSR1.Files.SideEffects 19 \defined('JPATH_PLATFORM') or die; 20 // phpcs:enable PSR1.Files.SideEffects 21 22 /** 23 * Base class for rendering a display layout 24 * loaded from from a layout file 25 * 26 * @link https://docs.joomla.org/Special:MyLanguage/Sharing_layouts_across_views_or_extensions_with_JLayout 27 * @since 3.0 28 */ 29 class FileLayout extends BaseLayout 30 { 31 /** 32 * Cached layout paths 33 * 34 * @var array 35 * @since 3.5 36 */ 37 protected static $cache = array(); 38 39 /** 40 * Dot separated path to the layout file, relative to base path 41 * 42 * @var string 43 * @since 3.0 44 */ 45 protected $layoutId = ''; 46 47 /** 48 * Base path to use when loading layout files 49 * 50 * @var string 51 * @since 3.0 52 */ 53 protected $basePath = null; 54 55 /** 56 * Full path to actual layout files, after possible template override check 57 * 58 * @var string 59 * @since 3.0.3 60 */ 61 protected $fullPath = null; 62 63 /** 64 * Paths to search for layouts 65 * 66 * @var array 67 * @since 3.2 68 */ 69 protected $includePaths = array(); 70 71 /** 72 * Method to instantiate the file-based layout. 73 * 74 * @param string $layoutId Dot separated path to the layout file, relative to base path 75 * @param string $basePath Base path to use when loading layout files 76 * @param mixed $options Optional custom options to load. Registry or array format [@since 3.2] 77 * 78 * @since 3.0 79 */ 80 public function __construct($layoutId, $basePath = null, $options = null) 81 { 82 // Initialise / Load options 83 $this->setOptions($options); 84 85 // Main properties 86 $this->setLayoutId($layoutId); 87 $this->basePath = $basePath; 88 89 // Init Environment 90 $this->setComponent($this->options->get('component', 'auto')); 91 $this->setClient($this->options->get('client', 'auto')); 92 } 93 94 /** 95 * Method to render the layout. 96 * 97 * @param array $displayData Array of properties available for use inside the layout file to build the displayed output 98 * 99 * @return string The necessary HTML to display the layout 100 * 101 * @since 3.0 102 */ 103 public function render($displayData = array()) 104 { 105 $this->clearDebugMessages(); 106 107 // Inherit base output from parent class 108 $layoutOutput = ''; 109 110 // Automatically merge any previously data set if $displayData is an array 111 if (\is_array($displayData)) { 112 $displayData = array_merge($this->data, $displayData); 113 } 114 115 // Check possible overrides, and build the full path to layout file 116 $path = $this->getPath(); 117 118 if ($this->isDebugEnabled()) { 119 echo '<pre>' . $this->renderDebugMessages() . '</pre>'; 120 } 121 122 // Nothing to show 123 if (empty($path)) { 124 return $layoutOutput; 125 } 126 127 ob_start(); 128 include $path; 129 $layoutOutput .= ob_get_contents(); 130 ob_end_clean(); 131 132 return $layoutOutput; 133 } 134 135 /** 136 * Method to finds the full real file path, checking possible overrides 137 * 138 * @return string The full path to the layout file 139 * 140 * @since 3.0 141 */ 142 protected function getPath() 143 { 144 $layoutId = $this->getLayoutId(); 145 $includePaths = $this->getIncludePaths(); 146 $suffixes = $this->getSuffixes(); 147 148 $this->addDebugMessage('<strong>Layout:</strong> ' . $this->layoutId); 149 150 if (!$layoutId) { 151 $this->addDebugMessage('<strong>There is no active layout</strong>'); 152 153 return; 154 } 155 156 if (!$includePaths) { 157 $this->addDebugMessage('<strong>There are no folders to search for layouts:</strong> ' . $layoutId); 158 159 return; 160 } 161 162 $hash = md5( 163 json_encode( 164 array( 165 'paths' => $includePaths, 166 'suffixes' => $suffixes, 167 ) 168 ) 169 ); 170 171 if (!empty(static::$cache[$layoutId][$hash])) { 172 $this->addDebugMessage('<strong>Cached path:</strong> ' . static::$cache[$layoutId][$hash]); 173 174 return static::$cache[$layoutId][$hash]; 175 } 176 177 $this->addDebugMessage('<strong>Include Paths:</strong> ' . print_r($includePaths, true)); 178 179 // Search for suffixed versions. Example: tags.j31.php 180 if ($suffixes) { 181 $this->addDebugMessage('<strong>Suffixes:</strong> ' . print_r($suffixes, true)); 182 183 foreach ($suffixes as $suffix) { 184 $rawPath = str_replace('.', '/', $this->layoutId) . '.' . $suffix . '.php'; 185 $this->addDebugMessage('<strong>Searching layout for:</strong> ' . $rawPath); 186 187 if ($foundLayout = Path::find($this->includePaths, $rawPath)) { 188 $this->addDebugMessage('<strong>Found layout:</strong> ' . $this->fullPath); 189 190 static::$cache[$layoutId][$hash] = $foundLayout; 191 192 return static::$cache[$layoutId][$hash]; 193 } 194 } 195 } 196 197 // Standard version 198 $rawPath = str_replace('.', '/', $this->layoutId) . '.php'; 199 $this->addDebugMessage('<strong>Searching layout for:</strong> ' . $rawPath); 200 201 $foundLayout = Path::find($this->includePaths, $rawPath); 202 203 if (!$foundLayout) { 204 $this->addDebugMessage('<strong>Unable to find layout: </strong> ' . $layoutId); 205 206 return; 207 } 208 209 $this->addDebugMessage('<strong>Found layout:</strong> ' . $foundLayout); 210 211 static::$cache[$layoutId][$hash] = $foundLayout; 212 213 return static::$cache[$layoutId][$hash]; 214 } 215 216 /** 217 * Add one path to include in layout search. Proxy of addIncludePaths() 218 * 219 * @param string|string[] $path The path to search for layouts 220 * 221 * @return self 222 * 223 * @since 3.2 224 */ 225 public function addIncludePath($path) 226 { 227 $this->addIncludePaths($path); 228 229 return $this; 230 } 231 232 /** 233 * Add one or more paths to include in layout search 234 * 235 * @param string|string[] $paths The path or array of paths to search for layouts 236 * 237 * @return self 238 * 239 * @since 3.2 240 */ 241 public function addIncludePaths($paths) 242 { 243 if (empty($paths)) { 244 return $this; 245 } 246 247 $includePaths = $this->getIncludePaths(); 248 249 if (\is_array($paths)) { 250 $includePaths = array_unique(array_merge($paths, $includePaths)); 251 } else { 252 array_unshift($includePaths, $paths); 253 } 254 255 $this->setIncludePaths($includePaths); 256 257 return $this; 258 } 259 260 /** 261 * Clear the include paths 262 * 263 * @return self 264 * 265 * @since 3.5 266 */ 267 public function clearIncludePaths() 268 { 269 $this->includePaths = array(); 270 271 return $this; 272 } 273 274 /** 275 * Get the active include paths 276 * 277 * @return array 278 * 279 * @since 3.5 280 */ 281 public function getIncludePaths() 282 { 283 if (empty($this->includePaths)) { 284 $this->includePaths = $this->getDefaultIncludePaths(); 285 } 286 287 return $this->includePaths; 288 } 289 290 /** 291 * Get the active layout id 292 * 293 * @return string 294 * 295 * @since 3.5 296 */ 297 public function getLayoutId() 298 { 299 return $this->layoutId; 300 } 301 302 /** 303 * Get the active suffixes 304 * 305 * @return array 306 * 307 * @since 3.5 308 */ 309 public function getSuffixes() 310 { 311 return $this->getOptions()->get('suffixes', array()); 312 } 313 314 /** 315 * Load the automatically generated language suffixes. 316 * Example: array('es-ES', 'es', 'ltr') 317 * 318 * @return self 319 * 320 * @since 3.5 321 */ 322 public function loadLanguageSuffixes() 323 { 324 $lang = Factory::getLanguage(); 325 326 $langTag = $lang->getTag(); 327 $langParts = explode('-', $langTag); 328 329 $suffixes = array($langTag, $langParts[0]); 330 $suffixes[] = $lang->isRtl() ? 'rtl' : 'ltr'; 331 332 $this->setSuffixes($suffixes); 333 334 return $this; 335 } 336 337 /** 338 * Load the automatically generated version suffixes. 339 * Example: array('j311', 'j31', 'j3') 340 * 341 * @return self 342 * 343 * @since 3.5 344 */ 345 public function loadVersionSuffixes() 346 { 347 $cmsVersion = new Version(); 348 349 // Example j311 350 $fullVersion = 'j' . str_replace('.', '', $cmsVersion->getShortVersion()); 351 352 // Create suffixes like array('j311', 'j31', 'j3') 353 $suffixes = array( 354 $fullVersion, 355 substr($fullVersion, 0, 3), 356 substr($fullVersion, 0, 2), 357 ); 358 359 $this->setSuffixes(array_unique($suffixes)); 360 361 return $this; 362 } 363 364 /** 365 * Remove one path from the layout search 366 * 367 * @param string $path The path to remove from the layout search 368 * 369 * @return self 370 * 371 * @since 3.2 372 */ 373 public function removeIncludePath($path) 374 { 375 $this->removeIncludePaths($path); 376 377 return $this; 378 } 379 380 /** 381 * Remove one or more paths to exclude in layout search 382 * 383 * @param string $paths The path or array of paths to remove for the layout search 384 * 385 * @return self 386 * 387 * @since 3.2 388 */ 389 public function removeIncludePaths($paths) 390 { 391 if (!empty($paths)) { 392 $paths = (array) $paths; 393 394 $this->includePaths = array_diff($this->includePaths, $paths); 395 } 396 397 return $this; 398 } 399 400 /** 401 * Validate that the active component is valid 402 * 403 * @param string $option URL Option of the component. Example: com_content 404 * 405 * @return boolean 406 * 407 * @since 3.2 408 */ 409 protected function validComponent($option = null) 410 { 411 // By default we will validate the active component 412 $component = $option ?? $this->options->get('component', null); 413 414 // Valid option format 415 if (!empty($component) && substr_count($component, 'com_')) { 416 // Latest check: component exists and is enabled 417 return ComponentHelper::isEnabled($component); 418 } 419 420 return false; 421 } 422 423 /** 424 * Method to change the component where search for layouts 425 * 426 * @param string $option URL Option of the component. Example: com_content 427 * 428 * @return mixed Component option string | null for none 429 * 430 * @since 3.2 431 */ 432 public function setComponent($option) 433 { 434 $component = null; 435 436 switch ((string) $option) { 437 case 'none': 438 $component = null; 439 break; 440 441 case 'auto': 442 $component = ApplicationHelper::getComponentName(); 443 break; 444 445 default: 446 $component = $option; 447 break; 448 } 449 450 // Extra checks 451 if (!$this->validComponent($component)) { 452 $component = null; 453 } 454 455 $this->options->set('component', $component); 456 457 // Refresh include paths 458 $this->clearIncludePaths(); 459 } 460 461 /** 462 * Function to initialise the application client 463 * 464 * @param mixed $client Frontend: 'site' or 0 | Backend: 'admin' or 1 465 * 466 * @return void 467 * 468 * @since 3.2 469 */ 470 public function setClient($client) 471 { 472 // Force string conversion to avoid unexpected states 473 switch ((string) $client) { 474 case 'site': 475 case '0': 476 $client = 0; 477 break; 478 479 case 'admin': 480 case '1': 481 $client = 1; 482 break; 483 484 default: 485 $client = (int) Factory::getApplication()->isClient('administrator'); 486 break; 487 } 488 489 $this->options->set('client', $client); 490 491 // Refresh include paths 492 $this->clearIncludePaths(); 493 } 494 495 /** 496 * Set the active layout id 497 * 498 * @param string $layoutId Layout identifier 499 * 500 * @return self 501 * 502 * @since 3.5 503 */ 504 public function setLayoutId($layoutId) 505 { 506 $this->layoutId = $layoutId; 507 $this->fullPath = null; 508 509 return $this; 510 } 511 512 /** 513 * Get the default array of include paths 514 * 515 * @return array 516 * 517 * @since 3.5 518 */ 519 public function getDefaultIncludePaths() 520 { 521 // Get the template 522 $template = Factory::getApplication()->getTemplate(true); 523 524 // Reset includePaths 525 $paths = array(); 526 527 // (1 - highest priority) Received a custom high priority path 528 if ($this->basePath !== null) { 529 $paths[] = rtrim($this->basePath, DIRECTORY_SEPARATOR); 530 } 531 532 // Component layouts & overrides if exist 533 $component = $this->options->get('component', null); 534 535 if (!empty($component)) { 536 // (2) Component template overrides path 537 $paths[] = JPATH_THEMES . '/' . $template->template . '/html/layouts/' . $component; 538 539 if (!empty($template->parent)) { 540 // (2.a) Component template overrides path for an inherited template using the parent 541 $paths[] = JPATH_THEMES . '/' . $template->parent . '/html/layouts/' . $component; 542 } 543 544 // (3) Component path 545 if ($this->options->get('client') == 0) { 546 $paths[] = JPATH_SITE . '/components/' . $component . '/layouts'; 547 } else { 548 $paths[] = JPATH_ADMINISTRATOR . '/components/' . $component . '/layouts'; 549 } 550 } 551 552 // (4) Standard Joomla! layouts overridden 553 $paths[] = JPATH_THEMES . '/' . $template->template . '/html/layouts'; 554 555 if (!empty($template->parent)) { 556 // (4.a) Component template overrides path for an inherited template using the parent 557 $paths[] = JPATH_THEMES . '/' . $template->parent . '/html/layouts'; 558 } 559 560 // (5 - lower priority) Frontend base layouts 561 $paths[] = JPATH_ROOT . '/layouts'; 562 563 return $paths; 564 } 565 566 /** 567 * Set the include paths to search for layouts 568 * 569 * @param array $paths Array with paths to search in 570 * 571 * @return self 572 * 573 * @since 3.5 574 */ 575 public function setIncludePaths($paths) 576 { 577 $this->includePaths = (array) $paths; 578 579 return $this; 580 } 581 582 /** 583 * Set suffixes to search layouts 584 * 585 * @param mixed $suffixes String with a single suffix or 'auto' | 'none' or array of suffixes 586 * 587 * @return self 588 * 589 * @since 3.5 590 */ 591 public function setSuffixes(array $suffixes) 592 { 593 $this->options->set('suffixes', $suffixes); 594 595 return $this; 596 } 597 598 /** 599 * Render a layout with the same include paths & options 600 * 601 * @param string $layoutId The identifier for the sublayout to be searched in a subfolder with the name of the current layout 602 * @param mixed $displayData Data to be rendered 603 * 604 * @return string The necessary HTML to display the layout 605 * 606 * @since 3.2 607 */ 608 public function sublayout($layoutId, $displayData) 609 { 610 // Sublayouts are searched in a subfolder with the name of the current layout 611 if (!empty($this->layoutId)) { 612 $layoutId = $this->layoutId . '.' . $layoutId; 613 } 614 615 $sublayout = new static($layoutId, $this->basePath, $this->options); 616 $sublayout->includePaths = $this->includePaths; 617 618 return $sublayout->render($displayData); 619 } 620 }
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 |