PageRenderTime 66ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/kernel/common/eztemplatedesignresource.php

https://github.com/granitegreg/ezpublish
PHP | 1071 lines | 757 code | 116 blank | 198 comment | 118 complexity | 2bac61d1838968f77db2ecfb3fb46347 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. //
  3. // Definition of eZTemplatedesignresource class
  4. //
  5. // Created on: <14-Sep-2002 15:37:17 amos>
  6. //
  7. // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
  8. // SOFTWARE NAME: eZ Publish
  9. // SOFTWARE RELEASE: 4.1.x
  10. // COPYRIGHT NOTICE: Copyright (C) 1999-2011 eZ Systems AS
  11. // SOFTWARE LICENSE: GNU General Public License v2.0
  12. // NOTICE: >
  13. // This program is free software; you can redistribute it and/or
  14. // modify it under the terms of version 2.0 of the GNU General
  15. // Public License as published by the Free Software Foundation.
  16. //
  17. // This program is distributed in the hope that it will be useful,
  18. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. // GNU General Public License for more details.
  21. //
  22. // You should have received a copy of version 2.0 of the GNU General
  23. // Public License along with this program; if not, write to the Free
  24. // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  25. // MA 02110-1301, USA.
  26. //
  27. //
  28. // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
  29. //
  30. /*! \file
  31. */
  32. /*!
  33. \class eZTemplatedesignresource eztemplatedesignresource.php
  34. \brief Handles template file loading with override support
  35. */
  36. class eZTemplateDesignResource extends eZTemplateFileResource
  37. {
  38. const DESIGN_BASE_CACHE_NAME = 'designbase_';
  39. /**
  40. * Contains in memory cache of override array used by {@link eZTemplateDesignResource::overrideArray()}
  41. *
  42. * @static
  43. * @protected
  44. * @var $overrideArrayCache null|array
  45. */
  46. protected static $overrideArrayCache = null;
  47. /*!
  48. Initializes with a default resource name "design".
  49. */
  50. function eZTemplateDesignResource( $name = "design" )
  51. {
  52. $this->eZTemplateFileResource( $name, true );
  53. $this->Keys = array();
  54. $this->KeyStack = array();
  55. }
  56. function templateNodeTransformation( $functionName, &$node,
  57. $tpl, &$resourceData, $parameters, $namespaceValue )
  58. {
  59. if ( $this->Name != 'design' and $this->Name != 'standard' )
  60. return false;
  61. $file = $resourceData['template-name'];
  62. $matchFileArray = eZTemplateDesignResource::overrideArray( $this->OverrideSiteAccess );
  63. $matchList = array();
  64. foreach ( $matchFileArray as $matchFile )
  65. {
  66. if ( !isset( $matchFile['template'] ) )
  67. continue;
  68. if ( $matchFile['template'] == ('/' . $file) )
  69. {
  70. $matchList[] = $matchFile;
  71. }
  72. }
  73. $resourceName = $resourceData['resource'];
  74. $resourceNameText = eZPHPCreator::variableText( $resourceName );
  75. $designKeysName = 'dKeys';
  76. if ( $resourceName == 'standard' )
  77. $designKeysName = 'rKeys';
  78. $newNodes = array();
  79. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "if " . ( $resourceData['use-comments'] ? ( "/*TDR:" . __LINE__ . "*/" ) : "" ) . "( !isset( \$$designKeysName ) )\n" .
  80. "{\n" .
  81. " \$resH = \$tpl->resourceHandler( $resourceNameText );\n" .
  82. " \$$designKeysName = \$resH->keys();" .
  83. "\n" .
  84. "}\n" );
  85. foreach ( $matchList as $match )
  86. {
  87. $basedir = $match['base_dir'];
  88. $template = $match['template'];
  89. $file = $basedir . $template;
  90. $spacing = 0;
  91. $addFileResource = true;
  92. if ( isset( $match['custom_match'] ) )
  93. {
  94. $spacing = 4;
  95. $customMatchList = $match['custom_match'];
  96. $matchCount = 0;
  97. foreach ( $customMatchList as $customMatch )
  98. {
  99. $matchConditionCount = count( $customMatch['conditions'] );
  100. $code = '';
  101. if ( $matchCount > 0 )
  102. {
  103. $code = "else " . ( $resourceData['use-comments'] ? ( "/*TDR:" . __LINE__ . "*/" ) : "" ) . "";
  104. }
  105. if ( $matchConditionCount > 0 )
  106. {
  107. if ( $matchCount > 0 )
  108. $code .= " ";
  109. $code .= "if " . ( $resourceData['use-comments'] ? ( "/*TDR:" . __LINE__ . "*/" ) : "" ) . "( ";
  110. }
  111. $ifLength = strlen( $code );
  112. $conditionCount = 0;
  113. if ( is_array( $customMatch['conditions'] ) )
  114. {
  115. foreach ( $customMatch['conditions'] as $conditionName => $conditionValue )
  116. {
  117. if ( $conditionCount > 0 )
  118. $code .= " and\n" . str_repeat( ' ', $ifLength );
  119. $conditionNameText = eZPHPCreator::variableText( $conditionName, 0 );
  120. $conditionValueText = eZPHPCreator::variableText( $conditionValue, 0 );
  121. $code .= "isset( \$" . $designKeysName . "[$conditionNameText] ) and ";
  122. if ( $conditionName == 'url_alias' )
  123. {
  124. $code .= "(strpos( \$" . $designKeysName . "[$conditionNameText], $conditionValueText ) === 0 )";
  125. }
  126. else
  127. {
  128. $code .= "( is_array( \$" . $designKeysName . "[$conditionNameText] ) ? " .
  129. "in_array( $conditionValueText, \$" . $designKeysName . "[$conditionNameText] ) : " .
  130. "\$" . $designKeysName . "[$conditionNameText] == $conditionValueText )";
  131. }
  132. ++$conditionCount;
  133. }
  134. }
  135. if ( $matchConditionCount > 0 )
  136. {
  137. $code .= " )\n";
  138. }
  139. if ( $matchConditionCount > 0 or $matchCount > 0 )
  140. {
  141. $code .= "{";
  142. }
  143. $matchFile = $customMatch['match_file'];
  144. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( $code );
  145. $newNodes[] = eZTemplateNodeTool::createResourceAcquisitionNode( '',
  146. $matchFile, $matchFile,
  147. eZTemplate::RESOURCE_FETCH, false,
  148. $node[4], array( 'spacing' => $spacing ),
  149. $namespaceValue );
  150. if ( $matchConditionCount > 0 or $matchCount > 0 )
  151. {
  152. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "}" );
  153. }
  154. ++$matchCount;
  155. if ( $matchConditionCount == 0 )
  156. {
  157. $addFileResource = false;
  158. break;
  159. }
  160. }
  161. if ( $addFileResource )
  162. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "else" . ( $resourceData['use-comments'] ? ( "/*TDR:" . __LINE__ . "*/" ) : "" ) . "\n{" );
  163. }
  164. if ( $addFileResource )
  165. {
  166. $newNodes[] = eZTemplateNodeTool::createResourceAcquisitionNode( '',
  167. $file, $file,
  168. eZTemplate::RESOURCE_FETCH, false,
  169. $node[4], array( 'spacing' => $spacing ),
  170. $namespaceValue );
  171. }
  172. if ( isset( $match['custom_match'] ) and $addFileResource )
  173. $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "}" );
  174. }
  175. return $newNodes;
  176. }
  177. /*!
  178. \static
  179. \return the sitedesign for the design type \a $type, currently \c standard and \c site is allowed.
  180. If no sitedesign is set it will fetch it from site.ini.
  181. */
  182. static function designSetting( $type = 'standard' )
  183. {
  184. if ( $type != 'standard' and
  185. $type != 'site' )
  186. {
  187. eZDebug::writeWarning( "Cannot retrieve designsetting for type '$type'", __METHOD__ );
  188. return null;
  189. }
  190. if ( $type == 'site' )
  191. {
  192. if ( !empty( $GLOBALS['eZSiteBasics']['site-design-override'] ) )
  193. {
  194. return $GLOBALS['eZSiteBasics']['site-design-override'];
  195. }
  196. }
  197. if ( isset( $GLOBALS['eZTemplateDesignSetting'][$type] ) )
  198. {
  199. return $GLOBALS['eZTemplateDesignSetting'][$type];
  200. }
  201. $ini = eZINI::instance();
  202. if ( $type == 'standard' )
  203. {
  204. $GLOBALS['eZTemplateDesignSetting'][$type] = $ini->variable( "DesignSettings", "StandardDesign" );
  205. }
  206. else if ( $type == 'site' )
  207. {
  208. $GLOBALS['eZTemplateDesignSetting'][$type] = $ini->variable( "DesignSettings", "SiteDesign" );
  209. }
  210. return $GLOBALS['eZTemplateDesignSetting'][$type];
  211. }
  212. /*!
  213. Sets the sitedesign for the design type \a $type, currently \c standard and \c site is allowed.
  214. The design is set to \a $designSetting.
  215. */
  216. function setDesignSetting( $designSetting, $type = 'standard' )
  217. {
  218. if ( $type != 'standard' and
  219. $type != 'site' )
  220. {
  221. eZDebug::writeWarning( "Cannot set designsetting '$designSetting' for type '$type'", __METHOD__ );
  222. return;
  223. }
  224. if ( !isset( $GLOBALS['eZTemplateDesignSetting'] ) )
  225. {
  226. $GLOBALS['eZTemplateDesignSetting'] = array();
  227. }
  228. $GLOBALS['eZTemplateDesignSetting'][$type] = $designSetting;
  229. }
  230. /*!
  231. \static
  232. */
  233. static function fileMatch( $bases, $element, $path, &$triedFiles )
  234. {
  235. $bases = array_unique( $bases );
  236. foreach ( $bases as $base )
  237. {
  238. $resource = $element != '' ? "$base/$element" : $base;
  239. $possibleMatchFile = $resource . '/' . $path;
  240. $triedFiles[] = $possibleMatchFile;
  241. if ( file_exists( $possibleMatchFile ) )
  242. {
  243. return array( 'resource' => $resource,
  244. 'path' => $possibleMatchFile );
  245. }
  246. }
  247. return false;
  248. }
  249. /*!
  250. Loads the template file if it exists, also sets the modification timestamp.
  251. Returns true if the file exists.
  252. */
  253. function handleResource( $tpl, &$resourceData, $method, &$extraParameters )
  254. {
  255. $path = $resourceData['template-name'];
  256. $matchKeys = $this->Keys;
  257. if ( isset( $GLOBALS['eZDesignKeys'] ) )
  258. {
  259. $matchKeys = array_merge( $matchKeys, $GLOBALS['eZDesignKeys'] );
  260. unset( $GLOBALS['eZDesignKeys'] );
  261. $this->Keys = $matchKeys;
  262. }
  263. if ( is_array( $extraParameters ) and
  264. isset( $extraParameters['ezdesign:keys'] ) )
  265. {
  266. $this->mergeKeys( $matchKeys, $extraParameters['ezdesign:keys'] );
  267. }
  268. $this->KeyStack[] = $this->Keys;
  269. $this->Keys = $matchKeys;
  270. eZDebug::accumulatorStart( 'override_cache', 'override', 'Cache load' );
  271. if( !isset( $GLOBALS['eZOverrideTemplateCacheMap'] ) )
  272. {
  273. $overrideCacheFile = $this->createOverrideCache();
  274. if ( $overrideCacheFile )
  275. {
  276. include_once( $overrideCacheFile );
  277. }
  278. }
  279. if ( isset( $GLOBALS['eZOverrideTemplateCacheMap'] ) )
  280. {
  281. if( isset( $GLOBALS['eZOverrideTemplateCacheMap'][md5( '/' . $path )] ) )
  282. {
  283. $cacheMap = $GLOBALS['eZOverrideTemplateCacheMap'][md5( '/' . $path )];
  284. if ( !is_string( $cacheMap ) and trim( $cacheMap['code'] ) )
  285. {
  286. eval( "\$matchFile = " . $cacheMap['code'] . ";" );
  287. }
  288. else
  289. {
  290. $matchFile = $cacheMap;
  291. }
  292. $match['file'] = $matchFile;
  293. }
  294. }
  295. else
  296. {
  297. $template = "/" . $path;
  298. $matchFileArray = eZTemplateDesignResource::overrideArray( $this->OverrideSiteAccess );
  299. $matchFile = $matchFileArray[$template];
  300. if ( isset( $matchFile['custom_match'] ) )
  301. {
  302. $matchFound = false;
  303. foreach ( $matchFile['custom_match'] as $customMatch )
  304. {
  305. $matchOverride = true;
  306. if ( count( $customMatch['conditions'] ) > 0 )
  307. {
  308. foreach ( array_keys( $customMatch['conditions'] ) as $conditionKey )
  309. {
  310. // Create special substring match for subtree override
  311. if ( $conditionKey == 'url_alias' )
  312. {
  313. if ( strpos( $matchKeys['url_alias'], $customMatch['conditions'][$conditionKey] ) === 0 )
  314. {
  315. }
  316. else
  317. {
  318. $matchOverride = false;
  319. }
  320. }
  321. else if ( isset( $matchKeys[$conditionKey] ) and
  322. isset( $customMatch['conditions'][$conditionKey] ) )
  323. {
  324. if ( is_array( $matchKeys[$conditionKey] ) )
  325. {
  326. if ( !in_array( $customMatch['conditions'][$conditionKey], $matchKeys[$conditionKey] ) )
  327. {
  328. $matchOverride = false;
  329. }
  330. }
  331. else if ( $matchKeys[$conditionKey] != $customMatch['conditions'][$conditionKey] )
  332. {
  333. $matchOverride = false;
  334. }
  335. }
  336. else
  337. {
  338. $matchOverride = false;
  339. }
  340. }
  341. if ( $matchOverride == true )
  342. {
  343. $match['file'] = $customMatch['match_file'];
  344. $matchFound = true;
  345. break;
  346. }
  347. else
  348. {
  349. }
  350. }
  351. else
  352. {
  353. // Default match without conditions
  354. $match['file'] = $customMatch['match_file'];
  355. $matchFound = true;
  356. }
  357. }
  358. if ( !$matchFound )
  359. $match['file'] = $matchFile['base_dir'] . $matchFile['template'];
  360. }
  361. else
  362. {
  363. $match['file'] = $matchFile['base_dir'] . $matchFile['template'];
  364. }
  365. }
  366. eZDebug::accumulatorStop( 'override_cache' );
  367. if ( isset( $match ) )
  368. {
  369. $file = $match["file"];
  370. $matchedKeys = array();
  371. $usedKeys = array();
  372. foreach ( $matchKeys as $matchKeyName => $matchKeyValue )
  373. {
  374. $usedKeys[$matchKeyName] = $matchKeyValue;
  375. }
  376. $extraParameters['ezdesign:used_keys'] = $usedKeys;
  377. $extraParameters['ezdesign:matched_keys'] = $matchedKeys;
  378. $tpl->setVariable( 'used', $usedKeys, 'DesignKeys' );
  379. $tpl->setVariable( 'matched', $matchedKeys, 'DesignKeys' );
  380. $resourceData['template-filename'] = $file;
  381. $result = eZTemplateFileResource::handleResourceData( $tpl, $this, $resourceData, $method, $extraParameters );
  382. }
  383. else
  384. {
  385. $result = false;
  386. }
  387. $this->Keys = array_pop( $this->KeyStack );
  388. return $result;
  389. }
  390. /*!
  391. Generates the cache for the template override matching.
  392. */
  393. function createOverrideCache()
  394. {
  395. if ( isset( $GLOBALS['eZSiteBasics'] ) )
  396. {
  397. if ( isset( $GLOBALS['eZSiteBasics']['no-cache-adviced'] ) and
  398. $GLOBALS['eZSiteBasics']['no-cache-adviced'] )
  399. return false;
  400. }
  401. global $eZTemplateOverrideCacheNoPermission;
  402. if ( $eZTemplateOverrideCacheNoPermission == "nocache" )
  403. {
  404. return false;
  405. }
  406. $ini = eZINI::instance( 'site.ini' );
  407. $useOverrideCache = true;
  408. if ( $ini->hasVariable( 'OverrideSettings', 'Cache' ) )
  409. $useOverrideCache = $ini->variable( 'OverrideSettings', 'Cache' ) == 'enabled';
  410. $standardBase = eZTemplateDesignResource::designSetting( 'standard' );
  411. $siteBase = eZTemplateDesignResource::designSetting( 'site' );
  412. $overrideKeys = $this->overrideKeys();
  413. $overrideKey = md5( implode( ',', $overrideKeys ) . $siteBase . $standardBase );
  414. $cacheDir = eZSys::cacheDirectory();
  415. $overrideCacheFile = $cacheDir.'/override/override_'.$overrideKey.'.php';
  416. // Build matching cache only of it does not already exists,
  417. // or override file has been updated
  418. if ( !$useOverrideCache or
  419. !file_exists( $overrideCacheFile ) )
  420. {
  421. $matchFileArray = eZTemplateDesignResource::overrideArray( $this->OverrideSiteAccess );
  422. // Generate PHP compiled cache file.
  423. $phpCache = new eZPHPCreator( "$cacheDir/override", "override_$overrideKey.php" );
  424. $phpCode = "\$GLOBALS['eZOverrideTemplateCacheMap'] = array (\n";
  425. $numMatchFiles = count ( $matchFileArray );
  426. $countMatchFiles = 0;
  427. // $phpCode .= "switch ( \$matchFile )\n{\n ";
  428. foreach ( array_keys( $matchFileArray ) as $matchKey )
  429. {
  430. $countMatchFiles++;
  431. $phpCode .= '\'' . md5( $matchKey ) . '\' => ';
  432. if ( isset( $matchFileArray[$matchKey]['custom_match'] ) )
  433. {
  434. $baseDir = isset( $matchFileArray[$matchKey]['base_dir'] ) ? $matchFileArray[$matchKey]['base_dir'] : '';
  435. $defaultMatchFile = $baseDir . $matchKey;
  436. // Custom override matching
  437. // $phpCode .= " case \"$matchKey\":\n {\n";
  438. $matchConditionArray = array();
  439. foreach ( $matchFileArray[$matchKey]['custom_match'] as $customMatch )
  440. {
  441. $matchCondition = "";
  442. $condCount = 0;
  443. if ( is_array( $customMatch['conditions'] ) )
  444. {
  445. foreach ( array_keys( $customMatch['conditions'] ) as $conditionKey )
  446. {
  447. if ( $condCount > 0 )
  448. $matchCondition .= " and ";
  449. // Have a special substring match for subtree matching
  450. $matchCondition .= "( isset( \$matchKeys[\\'$conditionKey\\'] ) and ";
  451. if ( $conditionKey == 'url_alias' )
  452. {
  453. $matchCondition .=
  454. "( strpos( \$matchKeys[\\'url_alias\\'], \\'" . $customMatch['conditions']['url_alias'] . "\\' ) === 0 ) )";
  455. }
  456. else
  457. {
  458. $matchCondition .=
  459. "( is_array( \$matchKeys[\\'$conditionKey\\'] ) ? " .
  460. "in_array( \\'" . $customMatch['conditions'][$conditionKey] . "\\', \$matchKeys[\\'$conditionKey\\'] ) : " .
  461. "\$matchKeys[\\'$conditionKey\\'] == \\'" . $customMatch['conditions'][$conditionKey] . "\\') )";
  462. }
  463. $condCount++;
  464. }
  465. }
  466. // Only create custom match if conditions are defined
  467. if ( $matchCondition != "" )
  468. {
  469. // $phpCode .= " if ( $matchCondition )\n {\n";
  470. // $phpCode .= " return '" . $customMatch['match_file'] . "';\n }\n";
  471. if ( $condCount > 1 )
  472. $matchConditionArray[] = array( 'condition' => '(' . $matchCondition . ')',
  473. 'matchFile' => $customMatch['match_file'] );
  474. else
  475. $matchConditionArray[] = array( 'condition' => $matchCondition,
  476. 'matchFile' => $customMatch['match_file'] );
  477. }
  478. else
  479. {
  480. // No override conditions defined. Override default match file
  481. $defaultMatchFile = $customMatch['match_file'];
  482. }
  483. }
  484. $phpCode .= "array ( 'eval' => 1, 'code' => ";
  485. $phpCode .= "'";
  486. foreach ( array_keys( $matchConditionArray ) as $key )
  487. {
  488. $phpCode .= '(' . $matchConditionArray[$key]['condition'] . ' ? ' . "\\'" . $matchConditionArray[$key]['matchFile'] . "\\'" . ' : ';
  489. }
  490. $phpCode .= "\\'" . $defaultMatchFile . "\\'";
  491. for ( $condCount = 0; $condCount < count( $matchConditionArray ); $condCount++)
  492. {
  493. $phpCode .= ')';
  494. }
  495. $phpCode .= "' )";
  496. }
  497. else
  498. {
  499. $phpCode .= "'". $matchFileArray[$matchKey]['base_dir'] . $matchKey . "'";
  500. }
  501. if ( $countMatchFiles < $numMatchFiles )
  502. {
  503. $phpCode .= ",\n";
  504. }
  505. else
  506. {
  507. $phpCode .= ");\n";
  508. }
  509. }
  510. $phpCache->addCodePiece( $phpCode );
  511. if ( $useOverrideCache and
  512. $phpCache->store() )
  513. {
  514. }
  515. else
  516. {
  517. if ( $useOverrideCache )
  518. {
  519. eZDebug::writeError( "Could not write template override cache file, check permissions in $cacheDir/override/.\nRunning eZ Publish without this cache will have a performance impact.", __METHOD__ );
  520. }
  521. $eZTemplateOverrideCacheNoPermission = 'nocache';
  522. $overrideCacheFile = false;
  523. }
  524. }
  525. return $overrideCacheFile;
  526. }
  527. /*!
  528. \static
  529. \return an array with keys that define the current override.
  530. */
  531. function overrideKeys( $siteAccess = false )
  532. {
  533. // print( "<br>" . xdebug_call_function() . "<br>" );
  534. $keys = array();
  535. $designStartPath = eZTemplateDesignResource::designStartPath();
  536. $keys[] = $designStartPath;
  537. // fetch the override array from a specific siteacces
  538. if ( $siteAccess )
  539. {
  540. // Get the design resources
  541. $ini = eZSiteAccess::getIni( $siteAccess, 'site.ini' );
  542. $overrideINI = eZINI::instance( 'override.ini', 'settings', null, null, true );
  543. // overwrite overrideDirs from siteIni instance
  544. $overrideINI->setOverrideDirs( $ini->overrideDirs( false ) );
  545. $overrideINI->load();
  546. $standardBase = $ini->variable( "DesignSettings", "StandardDesign" );
  547. $keys[] = "siteaccess/$siteAccess";
  548. $keys[] = $standardBase;
  549. $siteBase = $ini->variable( "DesignSettings", "SiteDesign" );
  550. $keys[] = $siteBase;
  551. }
  552. else
  553. {
  554. $ini = eZINI::instance();
  555. if ( $this->OverrideSiteAccess != false )
  556. {
  557. $overrideINI = eZSiteAccess::getIni( $siteAccess, 'override.ini' );
  558. $keys[] = "siteaccess/$this->OverrideSiteAccess";
  559. }
  560. else
  561. {
  562. $overrideINI = eZINI::instance( 'override.ini' );
  563. $siteAccess = $GLOBALS['eZCurrentAccess']['name'];
  564. $keys[] = "siteaccess/$siteAccess";
  565. }
  566. $standardBase = eZTemplateDesignResource::designSetting( 'standard' );
  567. $keys[] = $standardBase;
  568. $siteBase = eZTemplateDesignResource::designSetting( 'site' );
  569. $keys[] = $siteBase;
  570. }
  571. $additionalSiteDesignList = $ini->variable( "DesignSettings", "AdditionalSiteDesignList" );
  572. $keys = array_merge( $keys, $additionalSiteDesignList );
  573. // Add extension paths
  574. $extensionDirectory = eZExtension::baseDirectory();
  575. $designINI = eZINI::instance( 'design.ini' );
  576. $extensions = $designINI->variable( 'ExtensionSettings', 'DesignExtensions' );
  577. return array_merge( $keys, $extensions );
  578. }
  579. /*!
  580. \static
  581. */
  582. static function serializeOverrides( $siteAccess = false,
  583. $matchKeys = array() )
  584. {
  585. }
  586. /*!
  587. \static
  588. \return An array containing the names of the design extensions that are
  589. currently active
  590. */
  591. static function designExtensions()
  592. {
  593. $designINI = eZINI::instance( 'design.ini' );
  594. $extensions = $designINI->variable( 'ExtensionSettings', 'DesignExtensions' );
  595. return array_reverse( $extensions );
  596. }
  597. /*!
  598. \static
  599. \return Gives all knows bases for available sitedesign folders.
  600. */
  601. static function allDesignBases( $siteAccess = false )
  602. {
  603. // in memory caching
  604. if ( $siteAccess )
  605. {
  606. if ( isset( $GLOBALS['eZTemplateDesignResourceSiteAccessBases'] ) )
  607. {
  608. if ( isset( $GLOBALS['eZTemplateDesignResourceSiteAccessBases'][$siteAccess] ) )
  609. {
  610. return $GLOBALS['eZTemplateDesignResourceSiteAccessBases'][$siteAccess];
  611. }
  612. }
  613. else
  614. {
  615. $GLOBALS['eZTemplateDesignResourceSiteAccessBases'] = array();
  616. }
  617. }
  618. else
  619. {
  620. if ( isset( $GLOBALS['eZTemplateDesignResourceBases'] ) )
  621. {
  622. return $GLOBALS['eZTemplateDesignResourceBases'];
  623. }
  624. }
  625. $designLocationCache = false;
  626. $ini = eZINI::instance( 'site.ini' );
  627. if( $ini->variable( 'DesignSettings', 'DesignLocationCache' ) == 'enabled' )
  628. $designLocationCache = true;
  629. /*
  630. * We disable design cache in case of DB clustering
  631. * because it will add 2 SQL queries per HTTP request
  632. */
  633. $ini = eZINI::instance( 'file.ini' );
  634. if( $ini->variable( 'ClusteringSettings', 'FileHandler' ) == 'eZDBFileHandler')
  635. $designLocationCache = false;
  636. if( $designLocationCache )
  637. {
  638. $siteAccessName = $GLOBALS['eZCurrentAccess']['name'];
  639. $cachePath = eZSys::cacheDirectory()
  640. . '/'
  641. . self::DESIGN_BASE_CACHE_NAME
  642. . md5( $siteAccessName )
  643. . '.php';
  644. $clusterFileHandler = eZClusterFileHandler::instance( $cachePath );
  645. if( $clusterFileHandler->fileExists( $cachePath ) )
  646. {
  647. $designBaseList = unserialize( $clusterFileHandler->fetchContents() );
  648. self::savesMemoryCache( $designBaseList, $siteAccess );
  649. }
  650. else
  651. {
  652. // find design locations
  653. $designBaseList = self::findDesignBase( $ini, $siteAccess );
  654. // stores it on the disk
  655. $clusterFileHandler->fileStoreContents( $cachePath,
  656. serialize( $designBaseList ),
  657. 'designbases',
  658. 'php' );
  659. self::savesMemoryCache( $designBaseList, $siteAccess );
  660. }
  661. }
  662. else
  663. {
  664. // find design locations
  665. $designBaseList = self::findDesignBase( $ini, $siteAccess );
  666. self::savesMemoryCache( $designBaseList, $siteAccess );
  667. }
  668. return $designBaseList;
  669. }
  670. /**
  671. * Find the location on design bases on the disk
  672. *
  673. * @param $ini an eZINI object
  674. * @param $siteAccess Wether to use siteaccesses or not
  675. * @return array The list of design bases
  676. */
  677. private static function findDesignBase( eZINI $ini, $siteAccess = false )
  678. {
  679. if( $siteAccess )
  680. {
  681. $ini = eZSiteAccess::getIni( $siteAccess, 'site.ini' );
  682. $standardDesign = $ini->variable( 'DesignSettings', 'StandardDesign' );
  683. $siteDesign = $ini->variable( 'DesignSettings', 'SiteDesign' );
  684. }
  685. else
  686. {
  687. $ini = eZINI::instance();
  688. $standardDesign = eZTemplateDesignResource::designSetting( 'standard' );
  689. $siteDesign = eZTemplateDesignResource::designSetting( 'site' );
  690. }
  691. $siteDesignList = $ini->variable( 'DesignSettings', 'AdditionalSiteDesignList' );
  692. array_unshift( $siteDesignList, $siteDesign );
  693. $siteDesignList[] = $standardDesign;
  694. $siteDesignList = array_unique( $siteDesignList );
  695. $designBaseList = array();
  696. $extensionDirectory = eZExtension::baseDirectory();
  697. $designStartPath = eZTemplateDesignResource::designStartPath();
  698. $extensions = eZTemplateDesignResource::designExtensions();
  699. foreach ( $siteDesignList as $design )
  700. {
  701. foreach ( $extensions as $extension )
  702. {
  703. $path = "$extensionDirectory/$extension/$designStartPath/$design";
  704. if ( file_exists( $path ) )
  705. {
  706. $designBaseList[] = $path;
  707. }
  708. }
  709. $path = "$designStartPath/$design";
  710. if ( file_exists( $path ) )
  711. {
  712. $designBaseList[] = $path;
  713. }
  714. }
  715. return $designBaseList;
  716. }
  717. /**
  718. * Stores design base list in memory for the current request
  719. *
  720. * @param $designBaseList An array with the design bases
  721. * @param $siteAccess Whether to use siteaccess or not
  722. * @return void
  723. */
  724. private static function savesMemoryCache( array $designBaseList, $siteAccess = false )
  725. {
  726. // store design base list in memory for the current request
  727. if ( $siteAccess )
  728. $GLOBALS['eZTemplateDesignResourceSiteAccessBases'][$siteAccess] = $designBaseList;
  729. else
  730. $GLOBALS['eZTemplateDesignResourceBases'] = $designBaseList;
  731. }
  732. /*!
  733. \static
  734. \return The start path of the design directory, by default it will return \c 'design'
  735. To change the directory use setDesignStartPath().
  736. */
  737. static function designStartPath()
  738. {
  739. $designStartPath = false;
  740. if ( isset( $GLOBALS['eZTemplateDesignResourceStartPath'] ) )
  741. {
  742. $designStartPath = $GLOBALS['eZTemplateDesignResourceStartPath'];
  743. }
  744. if ( !$designStartPath )
  745. $designStartPath = 'design';
  746. return $designStartPath;
  747. }
  748. /*!
  749. \static
  750. Changes the design start path which is used to find design files.
  751. \param $path Must be a string defining the path or \c false to use default start path.
  752. \sa designStartPath();
  753. */
  754. static function setDesignStartPath( $path )
  755. {
  756. $GLOBALS['eZTemplateDesignResourceStartPath'] = $path;
  757. }
  758. /**
  759. * Get an array of all the current templates and overrides for them.
  760. * The current siteaccess is used if none is specified.
  761. *
  762. * @static
  763. * @return array
  764. */
  765. static function overrideArray( $siteAccess = false )
  766. {
  767. if ( $siteAccess === false and self::$overrideArrayCache !== null )
  768. {
  769. return self::$overrideArrayCache;
  770. }
  771. $bases = eZTemplateDesignResource::allDesignBases( $siteAccess );
  772. // fetch the override array from a specific siteacces
  773. if ( $siteAccess )
  774. {
  775. $overrideINI = eZSiteAccess::getIni( $siteAccess, 'override.ini' );
  776. }
  777. else
  778. {
  779. $overrideINI = eZINI::instance( 'override.ini' );
  780. }
  781. $designStartPath = eZTemplateDesignResource::designStartPath();
  782. // Generate match cache for all templates
  783. // Build arrays of available files, start with standard design and end with most prefered design
  784. $matchFilesArray = array();
  785. $reverseBases = array_reverse( $bases );
  786. foreach ( $reverseBases as $base )
  787. {
  788. $templateResource = $base . '/templates';
  789. $sourceFileArray = eZDir::recursiveFindRelative( $templateResource, "", "tpl" );
  790. foreach ( $sourceFileArray as $source )
  791. {
  792. $matchFileArray[$source]['base_dir'] = $templateResource;
  793. $matchFileArray[$source]['template'] = $source;
  794. }
  795. }
  796. // Load override templates
  797. $overrideSettingGroups = $overrideINI->groups();
  798. if ( isset( $GLOBALS['eZDesignOverrides'] ) )
  799. {
  800. $overrideSettingGroups = array_merge( $overrideSettingGroups, $GLOBALS['eZDesignOverrides'] );
  801. }
  802. foreach ( $overrideSettingGroups as $overrideName => $overrideSetting )
  803. {
  804. $overrideSource = "/" . $overrideSetting['Source'];
  805. $overrideMatchFile = $overrideSetting['MatchFile'];
  806. // Find the matching file in the available resources
  807. $triedFiles = array();
  808. $fileInfo = eZTemplateDesignResource::fileMatch( $bases, 'override/templates', $overrideMatchFile, $triedFiles );
  809. $resourceInUse = is_array( $fileInfo ) ? $fileInfo['resource'] : false;
  810. $overrideMatchFilePath = is_array( $fileInfo ) ? $fileInfo['path'] : false;
  811. // if the override template is not found
  812. // then we probably shouldn't use it
  813. // there should be added a check around the following code
  814. // if ( $overrideMatchFilePath )
  815. // {
  816. $customMatchArray = array();
  817. $customMatchArray['conditions'] = isset( $overrideSetting['Match'] ) ? $overrideSetting['Match'] : null;
  818. $customMatchArray['match_file'] = $overrideMatchFilePath;
  819. $customMatchArray['override_name'] = $overrideName;
  820. $matchFileArray[$overrideSource]['custom_match'][] = $customMatchArray;
  821. // }
  822. // if overriding a non-existing template
  823. // then we use the override template as main template
  824. // this code should probably be removed
  825. // because we should not allow an override if the main template is missing
  826. if ( $resourceInUse && !isset( $matchFileArray[$overrideSource]['base_dir'] ) )
  827. {
  828. $matchFileArray[$overrideSource]['base_dir'] = $resourceInUse;
  829. $matchFileArray[$overrideSource]['template'] = $overrideSource;
  830. }
  831. if ( ! $overrideMatchFilePath )
  832. {
  833. eZDebug::writeError( "Custom match file: path '$overrideMatchFile' not found in any resource. Check the template settings in settings/override.ini", __METHOD__ );
  834. eZDebug::writeError( implode( ', ', $triedFiles ), __METHOD__ . ' tried files' );
  835. }
  836. }
  837. if ( $siteAccess === false )
  838. {
  839. self::$overrideArrayCache = $matchFileArray;
  840. }
  841. return $matchFileArray;
  842. }
  843. /**
  844. * Clear in memory override array cache
  845. *
  846. * @static
  847. * @since 4.2
  848. */
  849. static public function clearInMemoryOverrideArray( )
  850. {
  851. self::$overrideArrayCache = null;
  852. unset( $GLOBALS['eZOverrideTemplateCacheMap'] );
  853. }
  854. /**
  855. * Clear in memory cache (design settings and override cache)
  856. *
  857. * @static
  858. * @since 4.4
  859. */
  860. static public function clearInMemoryCache( )
  861. {
  862. $GLOBALS['eZTemplateDesignSetting'] = array();
  863. self::clearInMemoryOverrideArray();
  864. }
  865. /*!
  866. Sets the override keys to \a $keys, if some of the keys already exists they are overriden
  867. by the new keys.
  868. \sa clearKeys
  869. */
  870. function setKeys( $keys )
  871. {
  872. $this->mergeKeys( $this->Keys, $keys );
  873. }
  874. /*!
  875. Removes the given key
  876. */
  877. function removeKey( $key )
  878. {
  879. if ( isset( $this->Keys[$key] ) )
  880. unset( $this->Keys[$key] );
  881. }
  882. /*!
  883. \private
  884. Merges keys set in \a $keys with the array in \a $originalKeys.
  885. */
  886. function mergeKeys( &$originalKeys, $keys )
  887. {
  888. foreach ( $keys as $key )
  889. {
  890. if ( count( $key ) >= 2 )
  891. $originalKeys[$key[0]] = $key[1];
  892. }
  893. }
  894. /*!
  895. Removes all override keys.
  896. \sa setKeys
  897. */
  898. function clearKeys()
  899. {
  900. $this->Keys = array();
  901. }
  902. /*!
  903. \return the match keys.
  904. \sa setKeys
  905. */
  906. function keys()
  907. {
  908. if ( isset( $GLOBALS['eZDesignKeys'] ) )
  909. {
  910. return array_merge( $this->Keys, $GLOBALS['eZDesignKeys'] );
  911. }
  912. return $this->Keys;
  913. }
  914. /*!
  915. \static
  916. */
  917. static function addGlobalOverride( $name, $source, $match, $subdir, $matches )
  918. {
  919. if ( !isset( $GLOBALS['eZDesignOverrides'] ) )
  920. $GLOBALS['eZDesignOverrides'] = array();
  921. $GLOBALS['eZDesignOverrides'][$name] = array( 'Source' => $source,
  922. 'MatchFile' => $match,
  923. 'Subdir' => $subdir,
  924. 'Match' => $matches );
  925. }
  926. /**
  927. * Returns a shared instance of the eZTemplateDesignResource class.
  928. *
  929. * @return eZTemplateDesignResource
  930. */
  931. static function instance()
  932. {
  933. if ( !isset( $GLOBALS['eZTemplateDesignResourceInstance'] ) )
  934. {
  935. $GLOBALS['eZTemplateDesignResourceInstance'] = new eZTemplateDesignResource();
  936. }
  937. return $GLOBALS['eZTemplateDesignResourceInstance'];
  938. }
  939. /*!
  940. Sets the siteaccess which are to be used for loading the override settings.
  941. */
  942. function setOverrideAccess( $siteAccess )
  943. {
  944. $this->OverrideSiteAccess = $siteAccess;
  945. }
  946. public $Keys;
  947. public $OverrideSiteAccess = false;
  948. }
  949. ?>