eZ Publish  [4.0]
eznamepatternresolver.php
Go to the documentation of this file.
00001 <?php
00002 /**
00003  * File containing the eZNamePatternResolver class
00004  *
00005  * @copyright Copyright (C) 2005-2008 eZ Systems AS. All rights reserved.
00006  * @license http://ez.no/licenses/gnu_gpl GNU GPL v2
00007  * @version //autogentag//
00008  * @package kernel
00009  *
00010  */
00011 
00012 /**
00013  * eZNamePatternResolver is a utility class for resolving object name and url alias patterns.
00014  * This code supports object name pattern groups.
00015  *
00016  * Syntax:
00017  * <code>
00018  * &lt;attribute_identifier&gt;
00019  * &lt;attribute_identifier&gt; &lt;2nd-identifier&gt;
00020  * User text &lt;attribute_identifier&gt;|(&lt;2nd-identifier&gt;&lt;3rd-identifier&gt;)
00021  * </code>
00022  *
00023  * Example:
00024  * <code>
00025  * &lt;nickname|(&lt;firstname&gt; &lt;lastname&gt;)&gt;
00026  * </code>
00027  *
00028  * Tokens are looked up from left to right. If a match is found for the
00029  * leftmost token, the 2nd token will not be used. Tokens are representations
00030  * of atttributes. So a match means that that the current attribute has data.
00031  *
00032  * tokens are the class attribute identifiers which are used in the class
00033  * edit-interface.
00034  *
00035  * @package kernel
00036  * @version //autogentag//
00037  */
00038 class eZNamePatternResolver
00039 {
00040     /**
00041      * Holds token groups
00042      *
00043      * @var array
00044      */
00045     private $groupLookupTable;
00046 
00047     /**
00048      * Contains the original name pattern entered
00049      *
00050      * @var string
00051      */
00052     private $origNamePattern;
00053 
00054     /**
00055      * Holds the filtered name pattern where token groups are replaced with
00056      * meta strings
00057      *
00058      * @var string
00059      */
00060     private $namePattern;
00061 
00062     /**
00063      * The content object which holds the attributes used to resolve name pattern.
00064      *
00065      * @var eZContentObject
00066      */
00067     private $contentObject;
00068 
00069     /**
00070      * Version number of the content object to fetch attributes from.
00071      *
00072      * @var int
00073      */
00074     private $version;
00075 
00076     /**
00077      * Contains the language locale for which to fetch attributes.
00078      *
00079      * @var string
00080      */
00081     private $translation;
00082 
00083     /**
00084      * Holds data fetched from content object attributes
00085      *
00086      * @var array(string=>string)
00087      */
00088     private $attributeArray;
00089 
00090 
00091     /**
00092      * The string to use to signify group tokens.
00093      *
00094      * @var string
00095      */
00096     private $metaString = 'EZMETAGROUP_';
00097 
00098     /**
00099      * Constructs a object to resolve $namePattern. $contentVersion and
00100      * $contentTranslation specify which version and translation respectively
00101      * of the content object to use.
00102      *
00103      * @param string $namePattern
00104      * @param eZContentObject $contentObject
00105      * @param int $contentVersion
00106      * @param string $contentTranslation
00107      */
00108     public function __construct( $namePattern, $contentObject, $contentVersion = false, $contentTranslation = false )
00109     {
00110         $this->origNamePattern = $namePattern;
00111         $this->contentObject = $contentObject;
00112         $this->version = $contentVersion;
00113         $this->translation = $contentTranslation;
00114 
00115         $this->namePattern = $this->filterNamePattern( $namePattern);
00116     }
00117 
00118     /**
00119      * Return the real name for an object name pattern
00120      *
00121      * @param string $namePattern
00122      * @return string
00123      */
00124     public function resolveNamePattern()
00125     {
00126         // Fetch attributes for present identifiers
00127         $this->fetchContentAttributes();
00128 
00129         // Replace tokens with real values
00130         $objectName = $this->translatePattern();
00131 
00132         return $objectName;
00133     }
00134 
00135     /**
00136      * Fetches the list of available class-identifiers in the token, and it
00137      * will only fetch the attributes which appear amongst the identifiers
00138      * found in tokens.
00139      *
00140      * @return void
00141      */
00142     private function fetchContentAttributes()
00143     {
00144         $returnAttributeArray = array();
00145 
00146         $identifierArray = $this->getIdentifiers( $this->origNamePattern );
00147 
00148         $attributes = $this->contentObject->fetchAttributesByIdentifier( $identifierArray, $this->version, array( $this->translation ) );
00149 
00150         if ( is_array( $attributes ) )
00151         {
00152             foreach ( $attributes as $attribute )
00153             {
00154                 $identifier = $attribute->contentClassAttributeIdentifier();
00155                 $returnAttributeArray[$identifier] = $attribute->title();
00156             }
00157         }
00158         else
00159         {
00160             $returnAttributeArray = array();
00161         }
00162         $this->attributeArray = $returnAttributeArray;
00163     }
00164 
00165 
00166     /**
00167      * Replaces tokens in the name pattern with their resolved values.
00168      *
00169      * @return string
00170      */
00171     private function translatePattern()
00172     {
00173         $tokenArray = $this->extractTokens( $this->namePattern );
00174         $objectName = $this->namePattern;
00175 
00176         foreach( $tokenArray as $token )
00177         {
00178             $string = $this->resolveToken( $token );
00179             $objectName = str_replace( $token, $string, $objectName );
00180         }
00181 
00182         return $objectName;
00183     }
00184 
00185     /**
00186      * Extract all tokens from $namePattern
00187      *
00188      * Example:
00189      * <code>
00190      * Text &lt;token&gt; more text ==&gt; &lt;token&gt;
00191      * </code>
00192      *
00193      * @param string $namePattern
00194      * @return array
00195      */
00196     private function extractTokens( $namePattern )
00197     {
00198         $foundTokens = preg_match_all( "|<([^>]+)>|U", $namePattern,
00199                                                        $tokenArray );
00200 
00201         return $tokenArray[0];
00202     }
00203 
00204     /**
00205      * Looks up the value $token should be replaced with and returns this as
00206      * a string. Meta strings denothing token groups are automatically
00207      * inferred.
00208      *
00209      * @param string $token
00210      * @return string
00211      */
00212     private function resolveToken( $token )
00213     {
00214         $replaceString = "";
00215         $tokenParts = $this->tokenParts( $token );
00216 
00217         foreach ( $tokenParts as $tokenPart )
00218         {
00219             if ( $this->isTokenGroup( $tokenPart ) )
00220             {
00221                 $groupTokenArray = $this->extractTokens( $this->groupLookupTable[$tokenPart] );
00222                 $replaceString = $this->groupLookupTable[$tokenPart];
00223 
00224                 foreach ( $groupTokenArray as $groupToken )
00225                 {
00226                     $replaceString = str_replace( $groupToken, $this->resolveToken( $groupToken ), $replaceString );
00227                 }
00228                 // We want to stop after the first matching token part / identifier is found
00229                 // <id1|id2> if id1 has a value, id2 will not be used.
00230                 // In this case id1 or id1 is a token group.
00231                 break;
00232             }
00233             else
00234             {
00235                 if ( array_key_exists( $tokenPart, $this->attributeArray ) and $this->attributeArray[$tokenPart] !== '' and $this->attributeArray[$tokenPart] !== NULL )
00236                 {
00237                     $replaceString = $this->attributeArray[$tokenPart];
00238                     // We want to stop after the first matching token part / identifier is found
00239                     // <id1|id2> if id1 has a value, id2 will not be used.
00240                     break;
00241                 }
00242             }
00243         }
00244         return $replaceString;
00245     }
00246 
00247 
00248     /**
00249      * Checks whether $identifier is a placeholder for a token group.
00250      *
00251      * @param string $identifier
00252      * @return void
00253      */
00254     private function isTokenGroup( $identifier )
00255     {
00256         if ( strpos( $identifier, $this->metaString ) === false )
00257         {
00258             return false;
00259         }
00260         return true;
00261     }
00262 
00263     /**
00264      * Return the different constituents of $token in an array.
00265      * The normal case here is that the different identifiers within one token
00266      * will be tokenized and returned.
00267      *
00268      * Example:
00269      * <code>
00270      * "&lt;title|text&gt;" ==&gt; array( 'title', 'text' )
00271      * </code>
00272      *
00273      * @param string $token
00274      * @return array
00275      */
00276     private function tokenParts( $token )
00277     {
00278         $tokenParts = preg_split( '#\W#', $token, -1, PREG_SPLIT_NO_EMPTY );
00279         return $tokenParts;
00280     }
00281 
00282     /**
00283      * Builds a lookup / translation table for groups in the $namePattern.
00284      * The groups are referenced with a generated meta-token in the original
00285      * name pattern.
00286      *
00287      * Returns intermediate name pattern where groups are replaced with meta-
00288      * tokens.
00289      *
00290      * @param string $namePattern
00291      * @return string
00292      */
00293     private function filterNamePattern( $namePattern )
00294     {
00295         $retNamePattern = "";
00296         $foundGroups = preg_match_all( "/[<|\|](\(.+\))[\||>]/U", $namePattern, $groupArray );
00297 
00298         if ( $foundGroups )
00299         {
00300             $i = 0;
00301             foreach ( $groupArray[1] as $group )
00302             {
00303                 // Create meta-token for group
00304                 $metaToken = $this->metaString . $i;
00305 
00306                 // Insert the group with its placeholder token
00307                 $retNamePattern = str_replace( $group, $metaToken, $namePattern );
00308 
00309                 // Remove the pattern "(" ")" from the tokens
00310                 $group = str_replace( array( '(', ')' ), '', $group );
00311 
00312                 $this->groupLookupTable[$metaToken] = $group;
00313                 ++$i;
00314             }
00315             return $retNamePattern;
00316         }
00317         return $namePattern;
00318 
00319     }
00320 
00321     /**
00322      * Returns all identifiers from all tokens in the name pattern.
00323      *
00324      * @param string $patternString
00325      * @return array
00326      */
00327     private function getIdentifiers( $patternString )
00328     {
00329         $allTokens = '#<(.*)>#U';
00330         $identifiers = '#\W#';
00331 
00332         $tmpArray = array();
00333         preg_match_all( $allTokens, $patternString, $matches );
00334 
00335         foreach ( $matches[1] as $match )
00336         {
00337             $tmpArray[] = preg_split( $identifiers, $match, -1, PREG_SPLIT_NO_EMPTY );
00338         }
00339 
00340         $retArray = array();
00341         foreach ( $tmpArray as $matchGroup )
00342         {
00343             if ( is_array( $matchGroup ) )
00344             {
00345                 foreach ( $matchGroup as $item )
00346                 {
00347                     $retArray[] = $item;
00348                 }
00349             }
00350             else
00351             {
00352                 $retArray[] = $matchGroup;
00353             }
00354         }
00355         return $retArray;
00356     }
00357 }
00358 ?>