eZ Publish  [4.0]
eztemplatedebugfunction.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZTemplateDebugFunction class
00004 //
00005 // Created on: <01-Mar-2002 13:50:33 amos>
00006 //
00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00008 // SOFTWARE NAME: eZ Publish
00009 // SOFTWARE RELEASE: 4.0.x
00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS
00011 // SOFTWARE LICENSE: GNU General Public License v2.0
00012 // NOTICE: >
00013 //   This program is free software; you can redistribute it and/or
00014 //   modify it under the terms of version 2.0  of the GNU General
00015 //   Public License as published by the Free Software Foundation.
00016 //
00017 //   This program is distributed in the hope that it will be useful,
00018 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 //   GNU General Public License for more details.
00021 //
00022 //   You should have received a copy of version 2.0 of the GNU General
00023 //   Public License along with this program; if not, write to the Free
00024 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00025 //   MA 02110-1301, USA.
00026 //
00027 //
00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00029 //
00030 
00031 /*!
00032   \class eZTemplateDebugFunction eztemplatedebugfunction.php
00033   \ingroup eZTemplateFunctions
00034   \brief Advanced debug handling
00035 
00036   debug-timing-point
00037   Starts a timing point, executes body and ends the timing point.
00038   This is useful if you want to figure out how fast a piece of
00039   template code goes or to see all debug entries that occur
00040   between these two points.
00041 
00042   \code
00043   {debug-timing-point id=""}
00044   {$item} - {$item2}
00045   {/debug-timing-point}
00046   \endcode
00047 
00048   debug-accumulator
00049   Executes the body and performs statistics.
00050   The number of calls, total time and average time will be shown in debug.
00051 
00052   \code
00053   {debug-accumulator}
00054   {section var=error loop=$errors}{$error}{/section}
00055   {/debug-accumulator}
00056   \endcode
00057 
00058   debug-log
00059   Does exactly the same as eZDebug::writeDebug() method.
00060   Has two parameters:
00061   - var: variable to dump
00062   - msg: text message
00063 
00064   \code
00065   {debug-log var=$object msg='object contents'}
00066   {debug-log msg='hello world'}
00067   {debug-log var=array(1,2,3)}
00068   \endcode
00069 
00070   debug-trace
00071   Executes the body while tracing the result using XDebug.
00072   The result will a trace file made by XDebug which can be analyzed.
00073   Note: This will not do anything when XDebug is not available
00074 
00075   \code
00076   {debug-trace id="loop"}
00077   {section var=error loop=$errors}{$error}{/section}
00078   {/debug-trace}
00079   \endcode
00080 */
00081 
00082 class eZTemplateDebugFunction
00083 {
00084     /*!
00085      Initializes the object with names.
00086     */
00087     function eZTemplateDebugFunction( $timingPoint = 'debug-timing-point',
00088                                       $accumulator = 'debug-accumulator',
00089                                       $log = 'debug-log',
00090                                       $trace = 'debug-trace' )
00091     {
00092         $this->TimingPointName = $timingPoint;
00093         $this->AccumulatorName = $accumulator;
00094         $this->LogName = $log;
00095         $this->TraceName = $trace;
00096     }
00097 
00098     /*!
00099      Return the list of available functions.
00100     */
00101     function functionList()
00102     {
00103         return array( $this->TimingPointName, $this->AccumulatorName, $this->LogName, $this->TraceName );
00104     }
00105 
00106     /*!
00107      * Returns the attribute list.
00108      * key:   parameter name
00109      * value: can have children
00110      */
00111     function attributeList()
00112     {
00113         return array(
00114             $this->TimingPointName => true,
00115             $this->AccumulatorName => true,
00116             $this->LogName => false,
00117             $this->TraceName => true
00118         );
00119     }
00120 
00121     function functionTemplateHints()
00122     {
00123         return array( $this->TimingPointName => array( 'parameters' => true,
00124                                                        'static' => false,
00125                                                        'transform-children' => true,
00126                                                        'tree-transformation' => true,
00127                                                        'transform-parameters' => true ),
00128                       $this->AccumulatorName => array( 'parameters' => true,
00129                                                        'static' => false,
00130                                                        'transform-children' => true,
00131                                                        'tree-transformation' => true,
00132                                                        'transform-parameters' => true ),
00133                       $this->LogName => array( 'parameters' => true,
00134                                                'static' => false,
00135                                                'transform-children' => true,
00136                                                'tree-transformation' => true,
00137                                                'transform-parameters' => true ),
00138                       $this->TraceName => array( 'parameters' => true,
00139                                                  'static' => false,
00140                                                  'transform-children' => true,
00141                                                  'tree-transformation' => true,
00142                                                  'transform-parameters' => true ) );
00143     }
00144 
00145     function templateNodeTransformation( $functionName, &$node,
00146                                          $tpl, $parameters, $privateData )
00147     {
00148         if ( $functionName == $this->TimingPointName )
00149         {
00150             $id = false;
00151             if ( isset( $parameters['id'] ) )
00152             {
00153                 if ( !eZTemplateNodeTool::isConstantElement( $parameters['id'] ) )
00154                     return false;
00155                 $id = eZTemplateNodeTool::elementConstantValue( $parameters['id'] );
00156             }
00157 
00158             $newNodes = array();
00159 
00160             $startDescription = "debug-timing-point START: $id";
00161             $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "eZDebug::addTimingPoint( " . var_export( $startDescription, true ) . " );" );
00162 
00163             $children = eZTemplateNodeTool::extractFunctionNodeChildren( $node );
00164             $newNodes = array_merge( $newNodes, $children );
00165 
00166             $endDescription = "debug-timing-point END: $id";
00167             $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "eZDebug::addTimingPoint( " . var_export( $endDescription, true ) . " );" );
00168 
00169             return $newNodes;
00170         }
00171         else if ( $functionName == $this->AccumulatorName )
00172         {
00173             $id = false;
00174             if ( isset( $parameters['id'] ) )
00175             {
00176                 if ( !eZTemplateNodeTool::isConstantElement( $parameters['id'] ) )
00177                     return false;
00178                 $id = eZTemplateNodeTool::elementConstantValue( $parameters['id'] );
00179             }
00180 
00181             $name = false;
00182             if ( isset( $parameters['name'] ) )
00183             {
00184                 if ( !eZTemplateNodeTool::isConstantElement( $parameters['name'] ) )
00185                     return false;
00186                 $name = eZTemplateNodeTool::elementConstantValue( $parameters['name'] );
00187             }
00188             // Assign a name (as $functionName) which will be used in the debug output.
00189             $name = ( $name === false and $id === false ) ?  $functionName : $name;
00190             // To uniquely identify this accumulator.
00191             $id = $id === false ? uniqID( $functionName . '_' ): $id;
00192             $newNodes = array();
00193 
00194             if ( $name )
00195             {
00196                 $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "eZDebug::accumulatorStart( " . var_export( $id, true ) . ", 'Debug-Accumulator', " . var_export( $name, true ) . " );" );
00197             }
00198             else
00199             {
00200                 $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "eZDebug::accumulatorStart( " . var_export( $id, true ) . ", 'Debug-Accumulator' );" );
00201             }
00202 
00203             $children = eZTemplateNodeTool::extractFunctionNodeChildren( $node );
00204             $newNodes = array_merge( $newNodes, $children );
00205 
00206             $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "eZDebug::accumulatorStop( " . var_export( $id, true ) . " );" );
00207 
00208             return $newNodes;
00209         }
00210         else if ( $functionName == $this->LogName )
00211         {
00212             $nodePlacement  = eZTemplateNodeTool::extractFunctionNodePlacement( $node );
00213             $newNodes = array();
00214 
00215             $varIsSet = $msgIsSet = false;
00216             if ( isset( $parameters['var'] ) )
00217             {
00218                 $varIsSet = true;
00219                 $var = $parameters['var'];
00220             }
00221             if ( isset( $parameters['msg'] ) )
00222             {
00223                 $msgIsSet = true;
00224                 $msg = $parameters['msg'];
00225             }
00226 
00227             $newNodes[]= eZTemplateNodeTool::createCodePieceNode( "// debug-log starts\n" );
00228 
00229             if ( $varIsSet )
00230                 $newNodes[] = eZTemplateNodeTool::createVariableNode( false, $var, $nodePlacement, array( 'treat-value-as-non-object' => true ), 'debug_log_var' );
00231             if ( $msgIsSet )
00232                 $newNodes[] = eZTemplateNodeTool::createVariableNode( false, $msg, $nodePlacement, array( 'treat-value-as-non-object' => true ), 'debug_log_msg' );
00233 
00234             if ( $varIsSet && $msgIsSet )
00235                  $newNodes[]= eZTemplateNodeTool::createCodePieceNode( "eZDebug::writeDebug( \$debug_log_var, \$debug_log_msg );\n" );
00236             elseif ( $msgIsSet )
00237                 $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "eZDebug::writeDebug( \$debug_log_msg );\n" );
00238             elseif ( $varIsSet )
00239                 $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "eZDebug::writeDebug( \$debug_log_var );\n" );
00240 
00241             if ( $varIsSet )
00242                 $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "unset( \$debug_log_var );" );
00243             if ( $msgIsSet )
00244                 $newNodes[] = eZTemplateNodeTool::createCodePieceNode( "unset( \$debug_log_msg );" );
00245 
00246             $newNodes[]= eZTemplateNodeTool::createCodePieceNode( "// debug-log ends\n" );
00247 
00248             return $newNodes;
00249         }
00250         else if ( $functionName == $this->TraceName )
00251         {
00252             $id = false;
00253             if ( isset( $parameters['id'] ) )
00254             {
00255                 if ( !eZTemplateNodeTool::isConstantElement( $parameters['id'] ) )
00256                     return false;
00257                 $id = eZTemplateNodeTool::elementConstantValue( $parameters['id'] );
00258             }
00259 
00260             if ( !$id )
00261                 $id = 'template-debug';
00262 
00263             $newNodes = array();
00264 
00265             $code = ( "if ( extension_loaded( 'xdebug' ) )\n" .
00266                       "{\n" .
00267                       "if ( file_exists( " . var_export( $id . '.xt', true ) . " ) )\n" .
00268                       "{\n" .
00269                       "\$fd = fopen( " . var_export( $id . '.xt', true ) . ", 'w' ); fclose( \$fd ); unset( \$fd );\n" .
00270                       "}\n" .
00271                       "xdebug_start_trace( " . var_export( $id, true ) . " );\n" .
00272                       "}\n" );
00273             $newNodes[] = eZTemplateNodeTool::createCodePieceNode( $code );
00274 
00275             $children = eZTemplateNodeTool::extractFunctionNodeChildren( $node );
00276             $newNodes = array_merge( $newNodes, $children );
00277 
00278             $code = ( "if ( extension_loaded( 'xdebug' ) )\n" .
00279                       "xdebug_stop_trace();\n" );
00280             $newNodes[] = eZTemplateNodeTool::createCodePieceNode( $code );
00281 
00282             return $newNodes;
00283         }
00284         return false;
00285     }
00286 
00287     /*!
00288      Processes the function with all it's children.
00289     */
00290     function process( $tpl, &$textElements, $functionName, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace )
00291     {
00292         switch ( $functionName )
00293         {
00294             case $this->TimingPointName:
00295             {
00296                 $children = $functionChildren;
00297                 $parameters = $functionParameters;
00298 
00299                 $id = false;
00300                 if ( isset( $parameters["id"] ) )
00301                 {
00302                     $id = $tpl->elementValue( $parameters["id"], $rootNamespace, $currentNamespace, $functionPlacement );
00303                 }
00304 
00305 
00306                 $startDescription = "debug-timing-point START: $id";
00307                 eZDebug::addTimingPoint( $startDescription );
00308 
00309                 if ( is_array( $children ) )
00310                 {
00311                     foreach ( array_keys( $children ) as $childKey )
00312                     {
00313                         $child =& $children[$childKey];
00314                         $tpl->processNode( $child, $textElements, $rootNamespace, $currentNamespace );
00315                     }
00316                 }
00317 
00318                 $endDescription = "debug-timing-point END: $id";
00319                 eZDebug::addTimingPoint( $endDescription );
00320 
00321             } break;
00322 
00323             case $this->AccumulatorName:
00324             {
00325                 $children = $functionChildren;
00326                 $parameters = $functionParameters;
00327 
00328                 $id = false;
00329                 if ( isset( $parameters["id"] ) )
00330                 {
00331                     $id = $tpl->elementValue( $parameters["id"], $rootNamespace, $currentNamespace, $functionPlacement );
00332                 }
00333 
00334                 $name = false;
00335                 if ( isset( $parameters["name"] ) )
00336                 {
00337                     $name = $tpl->elementValue( $parameters["name"], $rootNamespace, $currentNamespace, $functionPlacement );
00338                 }
00339 
00340                 // Assign a name (as $functionName) which will be used in the debug output.
00341                 $name = ( $name === false and $id === false ) ?  $functionName : $name;
00342                 // To uniquely identify this accumulator.
00343                 $id = $id === false ? uniqID( $functionName . '_' ): $id;
00344 
00345                 eZDebug::accumulatorStart( $id, 'Debug-Accumulator', $name );
00346 
00347                 if ( is_array( $children ) )
00348                 {
00349                     foreach ( array_keys( $children ) as $childKey )
00350                     {
00351                         $child =& $children[$childKey];
00352                         $tpl->processNode( $child, $textElements, $rootNamespace, $currentNamespace );
00353                     }
00354                 }
00355 
00356                 eZDebug::accumulatorStop( $id, 'Debug-Accumulator', $name );
00357 
00358             } break;
00359 
00360             case $this->LogName:
00361             {
00362                 $parameters = $functionParameters;
00363 
00364                 if ( isset( $parameters['var'] ) )
00365                     $var = $tpl->elementValue( $parameters['var'], $rootNamespace, $currentNamespace, $functionPlacement );
00366                 if ( isset( $parameters['msg'] ) )
00367                     $msg = $tpl->elementValue( $parameters['msg'], $rootNamespace, $currentNamespace, $functionPlacement );
00368 
00369                 if ( isset( $var ) && isset( $msg ) )
00370                     eZDebug::writeDebug( $var, $msg );
00371                 elseif ( isset( $msg ) )
00372                     eZDebug::writeDebug( $msg );
00373                 elseif ( isset( $var ) )
00374                     eZDebug::writeDebug( $var );
00375             } break;
00376 
00377             case $this->TraceName:
00378             {
00379                 $children = $functionChildren;
00380 
00381                 $id = false;
00382                 // If we have XDebug we start the trace, execute children and stop it
00383                 // if not we just execute the children as normal
00384                 if ( extension_loaded( 'xdebug' ) )
00385                 {
00386                     $parameters = $functionParameters;
00387                     if ( isset( $parameters["id"] ) )
00388                     {
00389                         $id = $tpl->elementValue( $parameters["id"], $rootNamespace, $currentNamespace, $functionPlacement );
00390                     }
00391 
00392                     if ( !$id )
00393                         $id = 'template-debug';
00394 
00395                     // If we already have a file, make sure it is truncated
00396                     if ( file_exists( $id . '.xt' ) )
00397                     {
00398                         $fd = fopen( $id, '.xt', 'w' ); fclose( $fd );
00399                     }
00400                     xdebug_start_trace( $id );
00401 
00402                     if ( is_array( $children ) )
00403                     {
00404                         foreach ( array_keys( $children ) as $childKey )
00405                         {
00406                             $child =& $children[$childKey];
00407                             $tpl->processNode( $child, $textElements, $rootNamespace, $currentNamespace );
00408                         }
00409                     }
00410 
00411                     xdebug_stop_trace();
00412                 }
00413                 elseif ( is_array( $children ) )
00414                 {
00415                     foreach ( array_keys( $children ) as $childKey )
00416                     {
00417                         $child =& $children[$childKey];
00418                         $tpl->processNode( $child, $textElements, $rootNamespace, $currentNamespace );
00419                     }
00420                 }
00421 
00422             } break;
00423         }
00424     }
00425 
00426     /*!
00427      Returns true.
00428     */
00429     function hasChildren()
00430     {
00431         return $this->attributeList();
00432     }
00433 
00434     /// \privatesection
00435     /// Name of the function
00436     public $DebugName;
00437     public $AppendDebugName;
00438     public $OnceName;
00439 }
00440 
00441 ?>