PageRenderTime 65ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/joomlapp.com/plugins/system/t3/includes/joomla4/FileLayout.php

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