eZ Publish  [trunk]
eztemplatedesignresource.php
Go to the documentation of this file.
00001 <?php
00002 /**
00003  * File containing the eZTemplateDesignResource class.
00004  *
00005  * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved.
00006  * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2
00007  * @version //autogentag//
00008  * @package kernel
00009  */
00010 
00011 /*!
00012   \class eZTemplatedesignresource eztemplatedesignresource.php
00013   \brief Handles template file loading with override support
00014 
00015 */
00016 
00017 class eZTemplateDesignResource extends eZTemplateFileResource
00018 {
00019     const DESIGN_BASE_CACHE_NAME = 'designbase_';
00020 
00021     /**
00022      * Contains in memory cache of override array used by {@link eZTemplateDesignResource::overrideArray()}
00023      *
00024      * @static
00025      * @protected
00026      * @var $overrideArrayCache null|array
00027      */
00028     protected static $overrideArrayCache = null;
00029 
00030     /*!
00031      Initializes with a default resource name "design".
00032     */
00033     function eZTemplateDesignResource( $name = "design" )
00034     {
00035         $this->eZTemplateFileResource( $name, true );
00036         $this->Keys = array();
00037         $this->KeyStack = array();
00038     }
00039 
00040     function templateNodeTransformation( $functionName, &$node,
00041                                          $tpl, &$resourceData, $parameters, $namespaceValue )
00042     {
00043         if ( $this->Name != 'design' and $this->Name != 'standard' )
00044             return false;
00045 
00046         $file = $resourceData['template-name'];
00047         $matchFileArray = eZTemplateDesignResource::overrideArray( $this->OverrideSiteAccess );
00048         $matchList = array();
00049         foreach ( $matchFileArray as $matchFile )
00050         {
00051             if ( !isset( $matchFile['template'] ) )
00052                 continue;
00053             if ( $matchFile['template'] == ('/' . $file) )
00054             {
00055                 $matchList[] = $matchFile;
00056             }
00057         }
00058 
00059         $resourceName = $resourceData['resource'];
00060         $resourceNameText = eZPHPCreator::variableText( $resourceName );
00061 
00062         $designKeysName = 'dKeys';
00063         if ( $resourceName == 'standard' )
00064             $designKeysName = 'rKeys';
00065 
00066         $newNodes = array();
00067         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "if " . ( $resourceData['use-comments'] ? ( "/*TDR:" . __LINE__ . "*/" ) : "" ) . "( !isset( \$$designKeysName ) )\n" .
00068                                                                "{\n" .
00069                                                                "    \$resH = \$tpl->resourceHandler( $resourceNameText );\n" .
00070                                                                "    \$$designKeysName = \$resH->keys();" .
00071                                                                "\n" .
00072                                                                "}\n" );
00073         foreach ( $matchList as $match )
00074         {
00075             $basedir = $match['base_dir'];
00076             $template = $match['template'];
00077             $file = $basedir . $template;
00078             $spacing = 0;
00079             $addFileResource = true;
00080             if ( isset( $match['custom_match'] ) )
00081             {
00082                 $spacing = 4;
00083                 $customMatchList = $match['custom_match'];
00084                 $matchCount = 0;
00085                 foreach ( $customMatchList as $customMatch )
00086                 {
00087                     $matchConditionCount = count( $customMatch['conditions'] );
00088                     $code = '';
00089                     if ( $matchCount > 0 )
00090                     {
00091                         $code = "else " . ( $resourceData['use-comments'] ? ( "/*TDR:" . __LINE__ . "*/" ) : "" ) . "";
00092                     }
00093                     if ( $matchConditionCount > 0 )
00094                     {
00095                         if ( $matchCount > 0 )
00096                             $code .= " ";
00097                         $code .= "if " . ( $resourceData['use-comments'] ? ( "/*TDR:" . __LINE__ . "*/" ) : "" ) . "( ";
00098                     }
00099                     $ifLength = strlen( $code );
00100                     $conditionCount = 0;
00101                     if ( is_array( $customMatch['conditions'] ) )
00102                     {
00103                         foreach ( $customMatch['conditions'] as $conditionName => $conditionValue )
00104                         {
00105                             if ( $conditionCount > 0 )
00106                                 $code .= " and\n" . str_repeat( ' ', $ifLength );
00107                             $conditionNameText = eZPHPCreator::variableText( $conditionName, 0 );
00108                             $conditionValueText = eZPHPCreator::variableText( $conditionValue, 0 );
00109 
00110                             $code .= "isset( \$" . $designKeysName . "[$conditionNameText] ) and ";
00111                             if ( $conditionName == 'url_alias' )
00112                             {
00113                                 $code .= "(strpos( \$" . $designKeysName . "[$conditionNameText], $conditionValueText ) === 0 )";
00114                             }
00115                             else
00116                             {
00117                                 $code .= "( is_array( \$" . $designKeysName . "[$conditionNameText] ) ? " .
00118                                          "in_array( $conditionValueText, \$" . $designKeysName . "[$conditionNameText] ) : " .
00119                                          "\$" . $designKeysName . "[$conditionNameText] == $conditionValueText )";
00120                             }
00121                             ++$conditionCount;
00122                         }
00123                     }
00124                     if ( $matchConditionCount > 0 )
00125                     {
00126                         $code .= " )\n";
00127                     }
00128                     if ( $matchConditionCount > 0 or $matchCount > 0 )
00129                     {
00130                         $code .= "{";
00131                     }
00132                     $matchFile = $customMatch['match_file'];
00133                     $newNodes[] = eZTemplateNodeTool::createCodePieceNode( $code );
00134                     $newNodes[] = eZTemplateNodeTool::createResourceAcquisitionNode( '',
00135                                                                                      $matchFile, $matchFile,
00136                                                                                      eZTemplate::RESOURCE_FETCH, false,
00137                                                                                      $node[4], array( 'spacing' => $spacing ),
00138                                                                                      $namespaceValue );
00139                     if ( $matchConditionCount > 0 or $matchCount > 0 )
00140                     {
00141                         $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "}" );
00142                     }
00143                     ++$matchCount;
00144                     if ( $matchConditionCount == 0 )
00145                     {
00146                         $addFileResource = false;
00147                         break;
00148                     }
00149                 }
00150                 if ( $addFileResource )
00151                     $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "else" . ( $resourceData['use-comments'] ? ( "/*TDR:" . __LINE__ . "*/" ) : "" ) . "\n{" );
00152             }
00153             if ( $addFileResource )
00154             {
00155                 $newNodes[] = eZTemplateNodeTool::createResourceAcquisitionNode( '',
00156                                                                                  $file, $file,
00157                                                                                  eZTemplate::RESOURCE_FETCH, false,
00158                                                                                  $node[4], array( 'spacing' => $spacing ),
00159                                                                                  $namespaceValue );
00160             }
00161             if ( isset( $match['custom_match'] ) and $addFileResource )
00162                 $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "}" );
00163         }
00164 
00165         return $newNodes;
00166     }
00167 
00168     /*!
00169      \static
00170      \return the sitedesign for the design type \a $type, currently \c standard and \c site is allowed.
00171              If no sitedesign is set it will fetch it from site.ini.
00172     */
00173     static function designSetting( $type = 'standard' )
00174     {
00175         if ( $type != 'standard' and
00176              $type != 'site' )
00177         {
00178             eZDebug::writeWarning( "Cannot retrieve designsetting for type '$type'", __METHOD__ );
00179             return null;
00180         }
00181         if ( $type == 'site' )
00182         {
00183             if ( !empty( $GLOBALS['eZSiteBasics']['site-design-override'] ) )
00184             {
00185                 return $GLOBALS['eZSiteBasics']['site-design-override'];
00186             }
00187         }
00188         if ( isset( $GLOBALS['eZTemplateDesignSetting'][$type] ) )
00189         {
00190             return $GLOBALS['eZTemplateDesignSetting'][$type];
00191         }
00192         $ini = eZINI::instance();
00193         if ( $type == 'standard' )
00194         {
00195             $GLOBALS['eZTemplateDesignSetting'][$type] = $ini->variable( "DesignSettings", "StandardDesign" );
00196         }
00197         else if ( $type == 'site' )
00198         {
00199             $GLOBALS['eZTemplateDesignSetting'][$type] = $ini->variable( "DesignSettings", "SiteDesign" );
00200         }
00201         return $GLOBALS['eZTemplateDesignSetting'][$type];
00202     }
00203 
00204     /*!
00205      Sets the sitedesign for the design type \a $type, currently \c standard and \c site is allowed.
00206      The design is set to \a $designSetting.
00207     */
00208     function setDesignSetting( $designSetting, $type = 'standard' )
00209     {
00210         if ( $type != 'standard' and
00211              $type != 'site' )
00212         {
00213             eZDebug::writeWarning( "Cannot set designsetting '$designSetting' for type '$type'", __METHOD__ );
00214             return;
00215         }
00216         if ( !isset( $GLOBALS['eZTemplateDesignSetting'] ) )
00217         {
00218             $GLOBALS['eZTemplateDesignSetting'] = array();
00219         }
00220         $GLOBALS['eZTemplateDesignSetting'][$type] = $designSetting;
00221     }
00222 
00223     /*!
00224      \static
00225 
00226     */
00227     static function fileMatch( $bases, $element, $path, &$triedFiles )
00228     {
00229         $bases = array_unique( $bases );
00230         foreach ( $bases as $base )
00231         {
00232             $resource = $element != '' ? "$base/$element" : $base;
00233             $possibleMatchFile = $resource . '/' . $path;
00234 
00235             $triedFiles[] = $possibleMatchFile;
00236 
00237             if ( file_exists( $possibleMatchFile ) )
00238             {
00239                 return array( 'resource' => $resource,
00240                               'path' => $possibleMatchFile );
00241             }
00242         }
00243 
00244         return false;
00245     }
00246 
00247     /*!
00248      Loads the template file if it exists, also sets the modification timestamp.
00249      Returns true if the file exists.
00250     */
00251     function handleResource( $tpl, &$resourceData, $method, &$extraParameters )
00252     {
00253         $path = $resourceData['template-name'];
00254 
00255         $matchKeys = $this->Keys;
00256         if ( isset( $GLOBALS['eZDesignKeys'] ) )
00257         {
00258             $matchKeys = array_merge( $matchKeys, $GLOBALS['eZDesignKeys'] );
00259             unset( $GLOBALS['eZDesignKeys'] );
00260             $this->Keys = $matchKeys;
00261         }
00262         if ( is_array( $extraParameters ) and
00263              isset( $extraParameters['ezdesign:keys'] ) )
00264         {
00265             $this->mergeKeys( $matchKeys, $extraParameters['ezdesign:keys'] );
00266         }
00267         $this->KeyStack[] = $this->Keys;
00268         $this->Keys = $matchKeys;
00269 
00270         eZDebug::accumulatorStart( 'override_cache', 'Override', 'Cache load' );
00271 
00272         if( !isset( $GLOBALS['eZOverrideTemplateCacheMap'] ) )
00273         {
00274             $overrideCacheFile = $this->createOverrideCache();
00275 
00276             if ( $overrideCacheFile )
00277             {
00278                 include_once( $overrideCacheFile );
00279             }
00280         }
00281 
00282         if ( isset( $GLOBALS['eZOverrideTemplateCacheMap'] ) )
00283         {
00284             if( isset( $GLOBALS['eZOverrideTemplateCacheMap'][md5( '/' . $path )] ) )
00285             {
00286                 $cacheMap = $GLOBALS['eZOverrideTemplateCacheMap'][md5( '/' . $path )];
00287                 if ( !is_string( $cacheMap ) and trim( $cacheMap['code'] ) )
00288                 {
00289                     eval( "\$matchFile = " . $cacheMap['code'] . ";" );
00290                 }
00291                 else
00292                 {
00293                     $matchFile = $cacheMap;
00294                 }
00295                 $match['file'] = $matchFile;
00296             }
00297         }
00298         else
00299         {
00300             $template = "/" . $path;
00301             $matchFileArray = eZTemplateDesignResource::overrideArray( $this->OverrideSiteAccess );
00302 
00303             $matchFile = $matchFileArray[$template];
00304 
00305             if ( isset( $matchFile['custom_match'] ) )
00306             {
00307                 $matchFound = false;
00308                 foreach ( $matchFile['custom_match'] as $customMatch )
00309                 {
00310                     $matchOverride = true;
00311                     if ( count( $customMatch['conditions'] ) > 0 )
00312                     {
00313                         foreach ( array_keys( $customMatch['conditions'] ) as $conditionKey )
00314                         {
00315                             // Create special substring match for subtree override
00316                             if ( $conditionKey == 'url_alias' )
00317                             {
00318                                 if ( strpos( $matchKeys['url_alias'], $customMatch['conditions'][$conditionKey] ) === 0 )
00319                                 {
00320                                 }
00321                                 else
00322                                 {
00323                                     $matchOverride = false;
00324                                 }
00325                             }
00326                             else if ( isset( $matchKeys[$conditionKey] ) and
00327                                       isset( $customMatch['conditions'][$conditionKey] ) )
00328                             {
00329                                 if ( is_array( $matchKeys[$conditionKey] ) )
00330                                 {
00331                                     if ( !in_array( $customMatch['conditions'][$conditionKey], $matchKeys[$conditionKey] ) )
00332                                     {
00333                                         $matchOverride = false;
00334                                     }
00335                                 }
00336                                 else if ( $matchKeys[$conditionKey] != $customMatch['conditions'][$conditionKey] )
00337                                 {
00338                                     $matchOverride = false;
00339                                 }
00340                             }
00341                             else
00342                             {
00343                                 $matchOverride = false;
00344                             }
00345                         }
00346                         if ( $matchOverride == true )
00347                         {
00348                             $match['file'] = $customMatch['match_file'];
00349                             $matchFound = true;
00350                             break;
00351                         }
00352                         else
00353                         {
00354                         }
00355                     }
00356                     else
00357                     {
00358                         // Default match without conditions
00359                         $match['file'] = $customMatch['match_file'];
00360                         $matchFound = true;
00361                     }
00362                 }
00363                 if ( !$matchFound )
00364                     $match['file'] = $matchFile['base_dir'] . $matchFile['template'];
00365             }
00366             else
00367             {
00368                 $match['file'] = $matchFile['base_dir'] . $matchFile['template'];
00369             }
00370         }
00371         eZDebug::accumulatorStop( 'override_cache' );
00372         if ( isset( $match ) )
00373         {
00374             $file = $match["file"];
00375 
00376             $matchedKeys = array();
00377             $usedKeys = array();
00378             foreach ( $matchKeys as $matchKeyName => $matchKeyValue )
00379             {
00380                 $usedKeys[$matchKeyName] = $matchKeyValue;
00381             }
00382             $extraParameters['ezdesign:used_keys'] = $usedKeys;
00383             $extraParameters['ezdesign:matched_keys'] = $matchedKeys;
00384             $tpl->setVariable( 'used', $usedKeys, 'DesignKeys' );
00385             $tpl->setVariable( 'matched', $matchedKeys, 'DesignKeys' );
00386             $resourceData['template-filename'] = $file;
00387             $result = eZTemplateFileResource::handleResourceData( $tpl, $this, $resourceData, $method, $extraParameters );
00388         }
00389         else
00390         {
00391             $result = false;
00392         }
00393         $this->Keys = array_pop( $this->KeyStack );
00394         return $result;
00395     }
00396 
00397     /*!
00398      Generates the cache for the template override matching.
00399     */
00400     function createOverrideCache()
00401     {
00402         if ( isset( $GLOBALS['eZSiteBasics'] ) )
00403         {
00404             if ( isset( $GLOBALS['eZSiteBasics']['no-cache-adviced'] ) and
00405                  $GLOBALS['eZSiteBasics']['no-cache-adviced'] )
00406                 return false;
00407         }
00408         global $eZTemplateOverrideCacheNoPermission;
00409         if ( $eZTemplateOverrideCacheNoPermission == "nocache" )
00410         {
00411             return false;
00412         }
00413 
00414         $ini = eZINI::instance( 'site.ini' );
00415         $useOverrideCache = true;
00416         if ( $ini->hasVariable( 'OverrideSettings', 'Cache' ) )
00417             $useOverrideCache = $ini->variable( 'OverrideSettings', 'Cache' ) == 'enabled';
00418 
00419         $standardBase = eZTemplateDesignResource::designSetting( 'standard' );
00420         $siteBase = eZTemplateDesignResource::designSetting( 'site' );
00421 
00422         $overrideKeys = $this->overrideKeys();
00423 
00424         $overrideKey = md5( implode( ',', $overrideKeys ) . $siteBase . $standardBase );
00425         $cacheDir = eZSys::cacheDirectory();
00426 
00427         $overrideCacheFile = $cacheDir.'/override/override_'.$overrideKey.'.php';
00428 
00429         // Build matching cache only of it does not already exists,
00430         // or override file has been updated
00431         if ( !$useOverrideCache or
00432              !file_exists( $overrideCacheFile ) )
00433         {
00434             $matchFileArray = eZTemplateDesignResource::overrideArray( $this->OverrideSiteAccess );
00435 
00436             // Generate PHP compiled cache file.
00437             $phpCache = new eZPHPCreator( "$cacheDir/override", "override_$overrideKey.php" );
00438 
00439             $phpCode = "\$GLOBALS['eZOverrideTemplateCacheMap'] = array (\n";
00440             $numMatchFiles = count ( $matchFileArray );
00441             $countMatchFiles = 0;
00442 //            $phpCode .= "switch ( \$matchFile )\n{\n    ";
00443             foreach ( array_keys( $matchFileArray ) as $matchKey )
00444             {
00445                 $countMatchFiles++;
00446                 $phpCode .= '\'' . md5( $matchKey ) . '\' => ';
00447                 if ( isset( $matchFileArray[$matchKey]['custom_match'] ) )
00448                 {
00449                     $baseDir = isset( $matchFileArray[$matchKey]['base_dir'] ) ? $matchFileArray[$matchKey]['base_dir'] : '';
00450                     $defaultMatchFile = $baseDir . $matchKey;
00451                     // Custom override matching
00452 //                    $phpCode .= "    case  \"$matchKey\":\n    {\n";
00453 
00454                     $matchConditionArray = array();
00455                     foreach ( $matchFileArray[$matchKey]['custom_match'] as $customMatch )
00456                     {
00457                         $matchCondition = "";
00458                         $condCount = 0;
00459                         if ( is_array( $customMatch['conditions'] ) )
00460                         {
00461                             foreach ( array_keys( $customMatch['conditions'] ) as $conditionKey )
00462                             {
00463                                 if ( $condCount > 0 )
00464                                     $matchCondition .= " and ";
00465 
00466                                 // Have a special substring match for subtree matching
00467 
00468                                 $matchCondition .= "( isset( \$matchKeys[\\'$conditionKey\\'] ) and ";
00469                                 if ( $conditionKey == 'url_alias' )
00470                                 {
00471                                     $matchCondition .=
00472                                         "( strpos( \$matchKeys[\\'url_alias\\'],  \\'" . $customMatch['conditions']['url_alias'] . "\\' ) === 0 ) )";
00473                                 }
00474                                 else
00475                                 {
00476                                     $matchCondition .=
00477                                         "( is_array( \$matchKeys[\\'$conditionKey\\'] ) ? " .
00478                                         "in_array( \\'" . $customMatch['conditions'][$conditionKey] . "\\', \$matchKeys[\\'$conditionKey\\'] ) : " .
00479                                         "\$matchKeys[\\'$conditionKey\\'] == \\'" . $customMatch['conditions'][$conditionKey] . "\\') )";
00480                                 }
00481 
00482                                 $condCount++;
00483                             }
00484                         }
00485 
00486                         // Only create custom match if conditions are defined
00487                         if ( $matchCondition != "" )
00488                         {
00489 //                            $phpCode .= "        if ( $matchCondition )\n        {\n";
00490 //                            $phpCode .= "            return '" . $customMatch['match_file'] . "';\n        }\n";
00491                             if ( $condCount > 1 )
00492                                 $matchConditionArray[] = array( 'condition' => '(' . $matchCondition . ')',
00493                                                                 'matchFile' => $customMatch['match_file'] );
00494                             else
00495                                 $matchConditionArray[] = array( 'condition' => $matchCondition,
00496                                                                 'matchFile' => $customMatch['match_file'] );
00497                         }
00498                         else
00499                         {
00500                             // No override conditions defined. Override default match file
00501                             $defaultMatchFile = $customMatch['match_file'];
00502                         }
00503                     }
00504 
00505                     $phpCode .= "array ( 'eval' => 1, 'code' => ";
00506 
00507                     $phpCode .= "'";
00508 
00509                     foreach ( array_keys( $matchConditionArray ) as $key )
00510                     {
00511                         $phpCode .= '(' . $matchConditionArray[$key]['condition'] . ' ? ' . "\\'" .  $matchConditionArray[$key]['matchFile'] . "\\'" . ' : ';
00512                     }
00513 
00514                     $phpCode .= "\\'" . $defaultMatchFile . "\\'";
00515 
00516                     for ( $condCount = 0; $condCount < count( $matchConditionArray ); $condCount++)
00517                     {
00518                         $phpCode .= ')';
00519                     }
00520 
00521                     $phpCode .= "' )";
00522                 }
00523                 else
00524                 {
00525                     $phpCode .= "'". $matchFileArray[$matchKey]['base_dir'] . $matchKey . "'";
00526                 }
00527 
00528                 if ( $countMatchFiles < $numMatchFiles )
00529                 {
00530                     $phpCode .= ",\n";
00531                 }
00532                 else
00533                 {
00534                     $phpCode .= ");\n";
00535                 }
00536             }
00537 
00538             $phpCache->addCodePiece( $phpCode );
00539             if ( $useOverrideCache and
00540                  $phpCache->store() )
00541             {
00542 
00543             }
00544             else
00545             {
00546                 if ( $useOverrideCache )
00547                 {
00548                     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__ );
00549                 }
00550                 $eZTemplateOverrideCacheNoPermission = 'nocache';
00551                 $overrideCacheFile = false;
00552             }
00553         }
00554 
00555         return $overrideCacheFile;
00556     }
00557 
00558     /*!
00559      \static
00560      \return an array with keys that define the current override.
00561     */
00562     function overrideKeys( $siteAccess = false )
00563     {
00564 //        print( "<br>" . xdebug_call_function() . "<br>" );
00565         $keys = array();
00566         $designStartPath = eZTemplateDesignResource::designStartPath();
00567         $keys[] = $designStartPath;
00568 
00569         // fetch the override array from a specific siteacces
00570         if ( $siteAccess )
00571         {
00572             // Get the design resources
00573             $ini = eZSiteAccess::getIni( $siteAccess, 'site.ini' );
00574 
00575             $overrideINI = eZINI::instance( 'override.ini', 'settings', null, null, true );
00576 
00577             // overwrite overrideDirs from siteIni instance
00578             $overrideINI->setOverrideDirs( $ini->overrideDirs( false ) );
00579             $overrideINI->load();
00580 
00581             $standardBase = $ini->variable( "DesignSettings", "StandardDesign" );
00582             $keys[] = "siteaccess/$siteAccess";
00583             $keys[] = $standardBase;
00584             $siteBase = $ini->variable( "DesignSettings", "SiteDesign" );
00585             $keys[] = $siteBase;
00586         }
00587         else
00588         {
00589             $ini = eZINI::instance();
00590             if ( $this->OverrideSiteAccess != false )
00591             {
00592                 $overrideINI = eZSiteAccess::getIni( $siteAccess, 'override.ini' );
00593                 $keys[] = "siteaccess/$this->OverrideSiteAccess";
00594             }
00595             else
00596             {
00597                 $overrideINI = eZINI::instance( 'override.ini' );
00598                 $siteAccess = $GLOBALS['eZCurrentAccess']['name'];
00599                 $keys[] = "siteaccess/$siteAccess";
00600             }
00601 
00602             $standardBase = eZTemplateDesignResource::designSetting( 'standard' );
00603             $keys[] = $standardBase;
00604             $siteBase = eZTemplateDesignResource::designSetting( 'site' );
00605             $keys[] = $siteBase;
00606         }
00607 
00608 
00609         $additionalSiteDesignList = $ini->variable( "DesignSettings", "AdditionalSiteDesignList" );
00610         $keys = array_merge( $keys, $additionalSiteDesignList );
00611 
00612         // Add extension paths
00613         $extensionDirectory = eZExtension::baseDirectory();
00614 
00615         $designINI = eZINI::instance( 'design.ini' );
00616         $extensions = $designINI->variable( 'ExtensionSettings', 'DesignExtensions' );
00617 
00618         return  array_merge( $keys, $extensions );
00619     }
00620 
00621     /*!
00622      \static
00623     */
00624     static function serializeOverrides( $siteAccess = false,
00625                                  $matchKeys = array() )
00626     {
00627     }
00628 
00629     /*!
00630      \static
00631      \return An array containing the names of the design extensions that are
00632              currently active
00633     */
00634     static function designExtensions()
00635     {
00636         $designINI = eZINI::instance( 'design.ini' );
00637         $extensions = $designINI->variable( 'ExtensionSettings', 'DesignExtensions' );
00638         return array_reverse( $extensions );
00639     }
00640 
00641     /*!
00642      \static
00643      \return Gives all knows bases for available sitedesign folders.
00644     */
00645     static function allDesignBases( $siteAccess = false )
00646     {
00647         // in memory caching
00648         if ( $siteAccess )
00649         {
00650             if ( isset( $GLOBALS['eZTemplateDesignResourceSiteAccessBases'] ) )
00651             {
00652                 if ( isset( $GLOBALS['eZTemplateDesignResourceSiteAccessBases'][$siteAccess] ) )
00653                 {
00654                     return $GLOBALS['eZTemplateDesignResourceSiteAccessBases'][$siteAccess];
00655                 }
00656             }
00657             else
00658             {
00659                 $GLOBALS['eZTemplateDesignResourceSiteAccessBases'] = array();
00660             }
00661         }
00662         else
00663         {
00664             if ( isset( $GLOBALS['eZTemplateDesignResourceBases'] ) )
00665             {
00666                 return $GLOBALS['eZTemplateDesignResourceBases'];
00667             }
00668         }
00669 
00670         $designLocationCache = false;
00671         $ini = eZINI::instance( 'site.ini' );
00672         if( $ini->variable( 'DesignSettings', 'DesignLocationCache' ) == 'enabled' )
00673             $designLocationCache = true;
00674 
00675         /*
00676          * We disable design cache in case of DB clustering
00677          * because it will add 2 SQL queries per HTTP request
00678          */
00679         $ini = eZINI::instance( 'file.ini' );
00680         if( $ini->variable( 'ClusteringSettings', 'FileHandler' ) == 'eZDBFileHandler')
00681             $designLocationCache = false;
00682 
00683         if( $designLocationCache )
00684         {
00685             $siteAccessName = $GLOBALS['eZCurrentAccess']['name'];
00686 
00687             $cachePath = eZSys::cacheDirectory()
00688                          . '/'
00689                          . self::DESIGN_BASE_CACHE_NAME
00690                          . md5( $siteAccessName )
00691                          . '.php';
00692 
00693             $clusterFileHandler = eZClusterFileHandler::instance( $cachePath );
00694 
00695             if( $clusterFileHandler->fileExists( $cachePath ) )
00696             {
00697                 $designBaseList = unserialize( $clusterFileHandler->fetchContents() );
00698 
00699                 self::savesMemoryCache( $designBaseList, $siteAccess );
00700             }
00701             else
00702             {
00703                 // find design locations
00704                 $designBaseList = self::findDesignBase( $ini, $siteAccess );
00705 
00706                 // stores it on the disk
00707                 $clusterFileHandler->fileStoreContents( $cachePath,
00708                                                         serialize( $designBaseList ),
00709                                                         'designbases',
00710                                                         'php' );
00711 
00712                 self::savesMemoryCache( $designBaseList, $siteAccess );
00713             }
00714         }
00715         else
00716         {
00717             // find design locations
00718             $designBaseList = self::findDesignBase( $ini, $siteAccess );
00719 
00720             self::savesMemoryCache( $designBaseList, $siteAccess );
00721         }
00722 
00723         return $designBaseList;
00724     }
00725 
00726     /**
00727      * Find the location on design bases on the disk
00728      *
00729      * @param $ini an eZINI object
00730      * @param $siteAccess Wether to use siteaccesses or not
00731      * @return array The list of design bases
00732      */
00733     private static function findDesignBase( eZINI $ini, $siteAccess = false )
00734     {
00735         if( $siteAccess )
00736         {
00737             $ini = eZSiteAccess::getIni( $siteAccess, 'site.ini' );
00738 
00739             $standardDesign = $ini->variable( 'DesignSettings', 'StandardDesign' );
00740             $siteDesign     = $ini->variable( 'DesignSettings', 'SiteDesign' );
00741 
00742         }
00743         else
00744         {
00745             $ini = eZINI::instance();
00746             $standardDesign = eZTemplateDesignResource::designSetting( 'standard' );
00747             $siteDesign     = eZTemplateDesignResource::designSetting( 'site' );
00748         }
00749 
00750         $siteDesignList = $ini->variable( 'DesignSettings', 'AdditionalSiteDesignList' );
00751 
00752         array_unshift( $siteDesignList, $siteDesign );
00753         $siteDesignList[] = $standardDesign;
00754         $siteDesignList   = array_unique( $siteDesignList );
00755 
00756         $designBaseList     = array();
00757         $extensionDirectory = eZExtension::baseDirectory();
00758         $designStartPath    = eZTemplateDesignResource::designStartPath();
00759         $extensions         = eZTemplateDesignResource::designExtensions();
00760 
00761         foreach ( $siteDesignList as $design )
00762         {
00763             foreach ( $extensions as $extension )
00764             {
00765                 $path = "$extensionDirectory/$extension/$designStartPath/$design";
00766                 if ( file_exists( $path ) )
00767                 {
00768                     $designBaseList[] = $path;
00769                 }
00770             }
00771 
00772             $path = "$designStartPath/$design";
00773             if ( file_exists( $path ) )
00774             {
00775                 $designBaseList[] = $path;
00776             }
00777         }
00778 
00779         return $designBaseList;
00780     }
00781 
00782     /**
00783      * Stores design base list in memory for the current request
00784      *
00785      * @param $designBaseList An array with the design bases
00786      * @param $siteAccess Whether to use siteaccess or not
00787      * @return void
00788      */
00789     private static function savesMemoryCache( array $designBaseList, $siteAccess = false )
00790     {
00791         // store design base list in memory for the current request
00792         if ( $siteAccess )
00793             $GLOBALS['eZTemplateDesignResourceSiteAccessBases'][$siteAccess] = $designBaseList;
00794         else
00795             $GLOBALS['eZTemplateDesignResourceBases'] = $designBaseList;
00796     }
00797 
00798     /*!
00799      \static
00800      \return The start path of the design directory, by default it will return \c 'design'
00801              To change the directory use setDesignStartPath().
00802     */
00803     static function designStartPath()
00804     {
00805         $designStartPath = false;
00806         if ( isset( $GLOBALS['eZTemplateDesignResourceStartPath'] ) )
00807         {
00808             $designStartPath = $GLOBALS['eZTemplateDesignResourceStartPath'];
00809         }
00810         if ( !$designStartPath )
00811             $designStartPath = 'design';
00812         return $designStartPath;
00813     }
00814 
00815     /*!
00816      \static
00817      Changes the design start path which is used to find design files.
00818      \param $path Must be a string defining the path or \c false to use default start path.
00819      \sa designStartPath();
00820     */
00821     static function setDesignStartPath( $path )
00822     {
00823         $GLOBALS['eZTemplateDesignResourceStartPath'] = $path;
00824     }
00825 
00826     /**
00827      * Get an array of all the current templates and overrides for them.
00828      * The current siteaccess is used if none is specified.
00829      *
00830      * @static
00831      * @return array
00832      */
00833     static function overrideArray( $siteAccess = false )
00834     {
00835 
00836         if ( $siteAccess === false and self::$overrideArrayCache !== null )
00837         {
00838             return self::$overrideArrayCache;
00839         }
00840 
00841         $bases = eZTemplateDesignResource::allDesignBases( $siteAccess );
00842 
00843         // fetch the override array from a specific siteacces
00844         if ( $siteAccess )
00845         {
00846             $overrideINI = eZSiteAccess::getIni( $siteAccess, 'override.ini' );
00847         }
00848         else
00849         {
00850             $overrideINI = eZINI::instance( 'override.ini' );
00851         }
00852 
00853         $designStartPath = eZTemplateDesignResource::designStartPath();
00854 
00855         // Generate match cache for all templates
00856 
00857         // Build arrays of available files, start with standard design and end with most prefered design
00858         $matchFileArray = array();
00859 
00860         $reverseBases = array_reverse( $bases );
00861 
00862         foreach ( $reverseBases as $base )
00863         {
00864             $templateResource = $base . '/templates';
00865             $sourceFileArray = eZDir::recursiveFindRelative( $templateResource, "",  "tpl" );
00866             foreach ( $sourceFileArray as $source )
00867             {
00868                 $matchFileArray[$source]['base_dir'] = $templateResource;
00869                 $matchFileArray[$source]['template'] = $source;
00870             }
00871         }
00872 
00873         // Load override templates
00874         $overrideSettingGroups = $overrideINI->groups();
00875         if ( isset( $GLOBALS['eZDesignOverrides'] ) )
00876         {
00877             $overrideSettingGroups = array_merge( $overrideSettingGroups, $GLOBALS['eZDesignOverrides'] );
00878         }
00879 
00880         foreach ( $overrideSettingGroups as $overrideName => $overrideSetting )
00881         {
00882             $overrideSource = "/" . $overrideSetting['Source'];
00883             $overrideMatchFile = $overrideSetting['MatchFile'];
00884 
00885             // Find the matching file in the available resources
00886             $triedFiles = array();
00887             $fileInfo = eZTemplateDesignResource::fileMatch( $bases, 'override/templates', $overrideMatchFile, $triedFiles );
00888 
00889             $resourceInUse = is_array( $fileInfo ) ? $fileInfo['resource'] : false;
00890             $overrideMatchFilePath = is_array( $fileInfo ) ? $fileInfo['path'] : false;
00891 
00892             // if the override template is not found
00893             // then we probably shouldn't use it
00894             // there should be added a check around the following code
00895             // if ( $overrideMatchFilePath )
00896             // {
00897             $customMatchArray = array();
00898             $customMatchArray['conditions'] = isset( $overrideSetting['Match'] ) ? $overrideSetting['Match'] : null;
00899             $customMatchArray['match_file'] = $overrideMatchFilePath;
00900             $customMatchArray['override_name'] = $overrideName;
00901 
00902             $matchFileArray[$overrideSource]['custom_match'][] = $customMatchArray;
00903             // }
00904 
00905             // if overriding a non-existing template
00906             // then we use the override template as main template
00907             // this code should probably be removed
00908             // because we should not allow an override if the main template is missing
00909             if ( $resourceInUse && !isset( $matchFileArray[$overrideSource]['base_dir'] ) )
00910             {
00911                 $matchFileArray[$overrideSource]['base_dir'] = $resourceInUse;
00912                 $matchFileArray[$overrideSource]['template'] = $overrideSource;
00913             }
00914 
00915             if ( ! $overrideMatchFilePath )
00916             {
00917                 eZDebug::writeError( "Custom match file: path '$overrideMatchFile' not found in any resource. Check the template settings in settings/override.ini", __METHOD__ );
00918                 eZDebug::writeError( implode( ', ', $triedFiles ), __METHOD__ . ' tried files' );
00919             }
00920 
00921         }
00922 
00923         if ( $siteAccess === false )
00924         {
00925             self::$overrideArrayCache = $matchFileArray;
00926         }
00927 
00928         return $matchFileArray;
00929     }
00930 
00931     /**
00932      * Clear in memory override array cache
00933      *
00934      * @static
00935      * @since 4.2
00936      */
00937     static public function clearInMemoryOverrideArray( )
00938     {
00939         self::$overrideArrayCache = null;
00940         unset( $GLOBALS['eZOverrideTemplateCacheMap'] );
00941     }
00942 
00943     /**
00944      * Clear in memory cache (design settings and override cache)
00945      *
00946      * @static
00947      * @since 4.4
00948      */
00949     static public function clearInMemoryCache( )
00950     {
00951         $GLOBALS['eZTemplateDesignSetting'] = array();
00952         self::clearInMemoryOverrideArray();
00953     }
00954 
00955     /*!
00956      Sets the override keys to \a $keys, if some of the keys already exists they are overriden
00957      by the new keys.
00958      \sa clearKeys
00959     */
00960     function setKeys( $keys )
00961     {
00962         $this->mergeKeys( $this->Keys, $keys );
00963     }
00964 
00965     /*!
00966      Removes the given key
00967     */
00968     function removeKey( $key )
00969     {
00970         if ( isset( $this->Keys[$key] ) )
00971         unset( $this->Keys[$key] );
00972     }
00973 
00974     /*!
00975      \private
00976      Merges keys set in \a $keys with the array in \a $originalKeys.
00977     */
00978     function mergeKeys( &$originalKeys, $keys )
00979     {
00980         foreach ( $keys as $key )
00981         {
00982             if ( count( $key ) >= 2 )
00983                 $originalKeys[$key[0]] = $key[1];
00984         }
00985     }
00986 
00987     /*!
00988      Removes all override keys.
00989      \sa setKeys
00990     */
00991     function clearKeys()
00992     {
00993         $this->Keys = array();
00994     }
00995 
00996     /*!
00997      \return the match keys.
00998      \sa setKeys
00999     */
01000     function keys()
01001     {
01002         if ( isset( $GLOBALS['eZDesignKeys'] ) )
01003         {
01004             return array_merge( $this->Keys, $GLOBALS['eZDesignKeys'] );
01005         }
01006         return $this->Keys;
01007     }
01008 
01009     /*!
01010      \static
01011     */
01012     static function addGlobalOverride( $name, $source, $match, $subdir, $matches )
01013     {
01014         if ( !isset( $GLOBALS['eZDesignOverrides'] ) )
01015             $GLOBALS['eZDesignOverrides'] = array();
01016         $GLOBALS['eZDesignOverrides'][$name] = array( 'Source' => $source,
01017                                                       'MatchFile' => $match,
01018                                                       'Subdir' => $subdir,
01019                                                       'Match' => $matches );
01020     }
01021 
01022     /**
01023      * Returns a shared instance of the eZTemplateDesignResource class.
01024      *
01025      * @return eZTemplateDesignResource
01026      */
01027     static function instance()
01028     {
01029         if ( !isset( $GLOBALS['eZTemplateDesignResourceInstance'] ) )
01030         {
01031             $GLOBALS['eZTemplateDesignResourceInstance'] = new eZTemplateDesignResource();
01032         }
01033         return $GLOBALS['eZTemplateDesignResourceInstance'];
01034     }
01035 
01036     /*!
01037      Sets the siteaccess which are to be used for loading the override settings.
01038     */
01039     function setOverrideAccess( $siteAccess )
01040     {
01041         $this->OverrideSiteAccess = $siteAccess;
01042     }
01043 
01044     public $Keys;
01045     public $OverrideSiteAccess = false;
01046 }
01047 
01048 ?>