PageRenderTime 35ms CodeModel.GetById 5ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/cms/layout/file.php

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