00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 define( 'EZ_CODE_TEMPLATE_STATUS_FAILED', 0 );
00042
00043 define( 'EZ_CODE_TEMPLATE_STATUS_OK', 1 );
00044
00045 define( 'EZ_CODE_TEMPLATE_STATUS_NO_CHANGE', 2 );
00046
00047 class eZCodeTemplate
00048 {
00049
00050
00051
00052 function eZCodeTemplate()
00053 {
00054 $ini =& eZINI::instance( 'codetemplate.ini' );
00055 $this->Templates = array();
00056 $templates = $ini->variable( 'Files', 'Templates' );
00057 foreach ( $templates as $key => $template )
00058 {
00059 $this->Templates[$key] = array( 'filepath' => $template );
00060 }
00061 }
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 function apply( $filePath, $checkOnly = false )
00072 {
00073 if ( !file_exists( $filePath ) )
00074 {
00075 eZDebug::writeError( "File $filePath does not exists",
00076 'eZCodeTemplate::apply' );
00077 return EZ_CODE_TEMPLATE_STATUS_FAILED;
00078 }
00079
00080 $text = file_get_contents( $filePath );
00081 $tempFile = dirname( $filePath ) . '/#' . basename( $filePath ) . '#';
00082 $fd = fopen( $tempFile, 'wb' );
00083 if ( !$fd )
00084 {
00085 eZDebug::writeError( "Failed to open temporary file $tempFile",
00086 'eZCodeTemplate::apply' );
00087 return EZ_CODE_TEMPLATE_STATUS_FAILED;
00088 }
00089
00090 $createTag = 'code-template::create-block:';
00091 $createTagLen = strlen( $createTag );
00092
00093 $error = false;
00094
00095 $ok = true;
00096 $offset = 0;
00097 $len = strlen( $text );
00098 while ( $offset < $len )
00099 {
00100 $createPos = strpos( $text, $createTag, $offset );
00101 if ( $createPos !== false )
00102 {
00103 $endPos = strpos( $text, "\n", $createPos + $createTagLen );
00104 if ( $endPos === false )
00105 {
00106 $createText = substr( $text, $createPos + $createTagLen );
00107 $end = $len;
00108 }
00109 else
00110 {
00111 $start = $createPos + $createTagLen;
00112 $createText = substr( $text, $start, $endPos - $start );
00113 $end = $endPos + 1;
00114 }
00115
00116
00117
00118 $indentText = '';
00119 $subText = substr( $text, $offset, $createPos - $offset );
00120 $startOfLine = strrpos( $subText, "\n" );
00121 if ( $startOfLine !== false )
00122 {
00123 if ( preg_match( '#^([ \t]+)#', substr( $subText, $startOfLine + 1 ), $matches ) )
00124 {
00125 $indentText = $matches[1];
00126 }
00127 }
00128 unset( $subText );
00129
00130
00131 $createText = trim( $createText );
00132 $elements = explode( ',', $createText );
00133 if ( count( $elements ) < 1 )
00134 {
00135 eZDebug::writeError( "No template name found in file $filePath at offset $offset",
00136 'eZCodeTemplate::apply' );
00137 $offset = $end;
00138 $error = true;
00139 continue;
00140 }
00141
00142 $templateName = trim( $elements[0] );
00143
00144 $templateFile = $this->templateFile( $templateName );
00145 if ( $templateFile === false )
00146 {
00147 eZDebug::writeError( "No template file for template $templateName used in file $filePath at offset $offset",
00148 'eZCodeTemplate::apply' );
00149 $offset = $end;
00150 $error = true;
00151 continue;
00152 }
00153
00154 if ( !file_exists( $templateFile ) )
00155 {
00156 eZDebug::writeError( "Template file $templateFile for template $templateName does not exist",
00157 'eZCodeTemplate::apply' );
00158 $offset = $end;
00159 $error = true;
00160 continue;
00161 }
00162
00163 $parameters = array_splice( $elements, 1 );
00164 foreach ( $parameters as $key => $parameter )
00165 {
00166 $parameters[$key] = trim( $parameter );
00167 }
00168
00169 if ( !file_exists( $templateFile ) )
00170 {
00171 eZDebug::writeError( "Template file $templateFile was not found while workin on $filePath at offset $offset",
00172 'eZCodeTemplate::apply' );
00173 $offset = $end;
00174 $error = true;
00175 continue;
00176 }
00177
00178
00179
00180 $templateText = file_get_contents( $templateFile );
00181
00182 $tagSplit = '#((?:<|/\*)(?:START|END):code-template::(?:[a-zA-Z]+[a-zA-Z0-9_|&-]*)(?:>|\*/)[\n]?)#';
00183 $tagRegexp = '#(?:<|/\*)(START|END):code-template::([a-zA-Z]+[a-zA-Z0-9_|&-]*)[\n]?(?:>|\*/)#';
00184
00185 $split = preg_split( $tagSplit, $templateText, -1, PREG_SPLIT_DELIM_CAPTURE );
00186
00187 $currentBlocks = array();
00188 $blocks = array();
00189 $currentTag = false;
00190 for ( $i = 0; $i < count( $split ); ++$i )
00191 {
00192 $part = $split[$i];
00193 if ( ( $i % 2 ) == 1 )
00194 {
00195
00196 if ( $currentTag === false )
00197 {
00198 preg_match( $tagRegexp, trim( $part ), $matches );
00199 $currentTag = $matches[2];
00200 if ( $matches[1] == 'END' )
00201 {
00202 eZDebug::writeError( "Tag $currentTag was finished before it was started, skipping it",
00203 'eZCodeTemplate::apply' );
00204 $currentTag = false;
00205 $error = true;
00206 }
00207 else
00208 {
00209 if ( count( $currentBlocks ) > 0 )
00210 $blocks[] = array( 'blocks' => $currentBlocks );
00211 $currentBlocks = array();
00212 }
00213 }
00214 else
00215 {
00216 preg_match( $tagRegexp, trim( $part ), $matches );
00217 $tag = $matches[2];
00218 if ( $matches[1] == 'END' )
00219 {
00220 if ( $tag == $currentTag )
00221 {
00222 if ( count( $currentBlocks ) > 0 )
00223 $blocks[] = array( 'tag' => $currentTag,
00224 'blocks' => $currentBlocks );
00225 $currentTag = false;
00226 $currentBlocks = array();
00227 }
00228 else
00229 {
00230 eZDebug::writeError( "End tag $tag does not match start tag $currentTag, skipping it",
00231 'eZCodeTemplate::apply' );
00232 $error = true;
00233 }
00234 }
00235 else
00236 {
00237 eZDebug::writeError( "Start tag $tag found while $currentTag is active, skipping it",
00238 'eZCodeTemplate::apply' );
00239 $error = true;
00240 }
00241 }
00242 }
00243 else
00244 {
00245
00246 $currentBlocks[] = $part;
00247 }
00248 }
00249 if ( $currentTag === false )
00250 {
00251 if ( count( $currentBlocks ) > 0 )
00252 $blocks[] = array( 'blocks' => $currentBlocks );
00253 }
00254 else
00255 {
00256 if ( count( $currentBlocks ) > 0 )
00257 $blocks[] = array( 'tag' => $currentTag,
00258 'blocks' => $currentBlocks );
00259 }
00260
00261
00262 $resultText = '';
00263 foreach ( $blocks as $block )
00264 {
00265 if ( isset( $block['tag'] ) )
00266 {
00267 $tagText = $block['tag'];
00268 if ( strpos( $tagText, '&' ) !== false )
00269 {
00270 $tags = explode( '&', $tagText );
00271
00272 if ( count( array_intersect( $parameters, $tags ) ) == count( $tags ) )
00273 {
00274 $resultText .= implode( '', $block['blocks'] );
00275 }
00276 }
00277 else if ( strpos( $tagText, '|' ) !== false )
00278 {
00279 $tags = explode( '|', $tagText );
00280
00281 if ( count( array_intersect( $parameters, $tags ) ) == count( $tags ) )
00282 {
00283 $resultText .= implode( '', $block['blocks'] );
00284 }
00285 }
00286 else
00287 {
00288 if ( in_array( $tagText, $parameters ) )
00289 {
00290 $resultText .= implode( '', $block['blocks'] );
00291 }
00292 }
00293 }
00294 else
00295 {
00296 $resultText .= implode( '', $block['blocks'] );
00297 }
00298 }
00299
00300
00301 if ( !in_array( 'keep-whitespace', $parameters ) )
00302 $resultText = preg_replace( '#[ \t]+$#m', '', $resultText );
00303
00304
00305 fwrite( $fd, substr( $text, $offset, $createPos - $offset ) );
00306 fwrite( $fd, substr( $text, $createPos, $end - $createPos ) );
00307
00308 $offset = $end;
00309
00310
00311 $autogenRegexp = '#^[ \t]*// code-template::auto-generated:START ' . $templateName . '.+[ \t]*// code-template::auto-generated:END ' . $templateName . '\n#ms';
00312 $postText = substr( $text, $offset );
00313 $postText = preg_replace( $autogenRegexp, '', $postText );
00314 $text = substr( $text, 0, $offset ) . $postText;
00315 unset( $postText );
00316
00317
00318 fwrite( $fd, ( "$indentText// code-template::auto-generated:START $templateName\n" .
00319 "$indentText// This code is automatically generated from $templateFile\n" .
00320 "$indentText// DO NOT EDIT THIS CODE DIRECTLY, CHANGE THE TEMPLATE FILE INSTEAD\n" .
00321 "\n" ) );
00322
00323 fwrite( $fd, $resultText );
00324 fwrite( $fd, ( "\n$indentText// This code is automatically generated from $templateFile\n" .
00325 "$indentText// code-template::auto-generated:END $templateName\n" ) );
00326
00327 }
00328 else
00329 {
00330 fwrite( $fd, substr( $text, $offset ) );
00331 break;
00332 }
00333 }
00334
00335 fclose( $fd );
00336 if ( !$error )
00337 {
00338 $originalMD5 = md5_file( $filePath );
00339 $updatedMD5 = md5_file( $tempFile );
00340 if ( $originalMD5 == $updatedMD5 )
00341 {
00342 unlink( $tempFile );
00343 return EZ_CODE_TEMPLATE_STATUS_NO_CHANGE;
00344 }
00345 else if ( $checkOnly )
00346 {
00347 unlink( $tempFile );
00348 return EZ_CODE_TEMPLATE_STATUS_OK;
00349 }
00350 else
00351 {
00352 $backupFile = $filePath . eZSys::backupFilename();
00353
00354 if ( file_exists( $backupFile ) )
00355 unlink( $backupFile );
00356 rename( $filePath, $backupFile );
00357 rename( $tempFile, $filePath );
00358 return EZ_CODE_TEMPLATE_STATUS_OK;
00359 }
00360 }
00361 unlink( $tempFile );
00362 return EZ_CODE_TEMPLATE_STATUS_FAILED;
00363 }
00364
00365
00366
00367
00368
00369 function templateFile( $templateName )
00370 {
00371 if ( isset( $this->Templates[$templateName] ) )
00372 {
00373 return $this->Templates[$templateName]['filepath'];
00374 }
00375 return false;
00376 }
00377
00378
00379
00380
00381
00382
00383
00384 function allCodeFiles()
00385 {
00386 $ini =& eZINI::instance( 'codetemplate.ini' );
00387 return $ini->variable( 'Files', 'PHPFiles' );
00388 }
00389
00390
00391 var $Templates;
00392 }
00393
00394 ?>