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