root/trunk/examples/patExampleGen/patExampleGen.php

Revision 117, 23.4 kB (checked in by argh, 4 years ago)

Massive update of the examples collection; added the patExampleGen examples framework; commented all examples; reworked all the templates...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 <?php
2 /**
3  * The pat examples framework class - manages the navigation and
4  * functionality of the examples collection of our tools.
5  *
6  * $Id$
7  *
8  * @package        patExampleGen
9  * @author        Sebastian Mordziol <argh@php-tools.net>
10  */
11
12  // global flag needed for the error handling output
13  $GLOBALS['errorStylesRendered'] = false;
14  
15 /**
16  * The pat examples framework class - manages the navigation and
17  * functionality of the examples collection of our tools.
18  *
19  * $Id$
20  *
21  * @package        patExampleGen
22  * @version        0.9
23  * @author        Sebastian Mordziol <argh@php-tools.net>
24  * @license        LGPL
25  * @link        http://www.php-tools.de
26  */
27 class patExampleGen
28 {
29    /**
30     * Stores all request variables
31     *
32     * @access    private
33     * @var        array
34     * @see        setSections()
35     */
36     var $vars = array();
37     
38    /**
39     * Stores the sections collection to generate
40     * the examples navigation from
41     *
42     * @access    private
43     * @var        array
44     */
45     var $sections = array();
46     
47    /**
48     * The XML_Beautifier class - used if installed to display
49     * XML output in a nice readable format with indentation.
50     *
51     * @access    private
52     * @var        object
53     */
54     var $beautifier = false;
55     
56    /**
57     * Stores the tabs configuration used to create the tabnavigation
58     * for each example.
59     *
60     * @access    private
61     * @var        array
62     * @see        setTabs()
63     */
64     var $tabs = array();
65     
66    /**
67     * Stores the name of the application
68     *
69     * @access    private
70     * @var        string
71     * @see        setAppName()
72     */
73     var $appName = 'Unknown';
74     
75    /**
76     * Stores the description of the application
77     *
78     * @access    private
79     * @var        string
80     * @see        setAppDescription()
81     */
82     var $appDescription = '';
83
84    /**
85     * Stores the ID of the application's forum
86     *
87     * @access    private
88     * @var        int
89     * @see        setAppForumId()
90     */
91     var $appForumId = 0;
92     
93    /**
94     * Main process method that dispatches needed tasks according
95     * to the given action.
96     *
97     * @access    public
98     */
99     function process()
100     {
101         $this->vars = $this->getRequestVars();
102     
103         $action = 'frameset';
104         if( isset( $this->vars['action'] ) )
105             $action = strtolower( $this->vars['action'] );
106         
107         switch( $action )
108         {
109             case 'frameset':
110                 $this->displayFrameset();
111                 break;
112                 
113             case 'navigation':
114                 $this->displayNavigation();
115                 break;
116                 
117             case 'overview':
118                 $this->displayOverview();
119                 break;
120                 
121             case 'example':
122                 $this->displayExample();
123                 break;
124         }
125     }
126     
127    /**
128     * Retrieves the request variables from POST and GET
129     *
130     * @access    public
131     * @return    array    $requestVars    The request vars
132     */
133     function getRequestVars()
134     {
135         return array_merge( $_POST, $_GET );
136     }
137     
138    /**
139     * Sets the default tab configuration that will be used for
140     * each example page. Additional tabs can be defined for each
141     * example within the section definition.
142     *
143     * @access    public
144     * @param    array    $tabs    The tab configuration
145     * @see        $tabs
146     */
147     function setTabs( $tabs )
148     {
149         $this->tabs = $tabs;
150     }
151     
152    /**
153     * Sets the name of the application
154     *
155     * @access    public
156     * @param    string    $appName    The name
157     * @see        $appName
158     */
159     function setAppName( $appName )
160     {
161         $this->appName = $appName;
162     }
163     
164    /**
165     * Sets the description of the application
166     *
167     * @access    public
168     * @param    string    $desc    The description text
169     * @see        $appDescription
170     */
171     function setAppDescription( $desc )
172     {
173         $this->appDescription = $desc;
174     }
175     
176    /**
177     * Sets the ID of the application's forum. Needed to display
178     * the correct link to the forum.
179     *
180     * @access    public
181     * @param    int        $id        The forum ID
182     * @see        $appForumId
183     */
184     function setAppForumId( $id )
185     {
186         $this->appForumId = $id;
187     }
188     
189    /**
190     * Retrieves the default example view tab, the one
191     * that is active when the page is loaded.
192     *
193     * @access    public
194     * @return    string    $tabId    The ID of the tab
195     */
196     function getDefaultTab( $tabs )
197     {
198         foreach( $tabs as $tabId => $tabDef )
199         {
200             if( $tabDef['default'] )
201             {
202                 return $tabId;
203             }
204         }
205         
206         reset( $tabs );
207         
208         return key( $tabs );
209     }
210     
211    /**
212     * Custom error handler that is set automatically to display
213     * any patError error objets within the examples collection.
214     *
215     * Displays:
216     * - Error level
217     * - Error Message
218     * - Error info
219     * - Error file
220     * - Error line
221     * - plus the call stack that lead to the error
222     *
223     * @author    Sebastian Mordziol <argh@php-tools.net>
224     * @access    public
225     * @static
226     * @param    object        error object
227     * @return    object        error object
228     */
229     function &displayError( &$error )
230     {
231         $prefix = 'arghDebug';
232         
233         // display the needed styles and scripts, but only once.
234         if( !$GLOBALS['errorStylesRendered'] )
235         {
236             echo '<style>';
237             echo '.'.$prefix.'Frame{';
238             echo '    background-color:#FEFCF3;';
239             echo '    padding:8px;';
240             echo '    border:solid 1px #000000;';
241             echo '    margin-top:13px;';
242             echo '    margin-bottom:25px;';
243             echo '    width:100%;';
244             echo '}';
245             echo '.'.$prefix.'Table{';
246             echo '    border-collapse:collapse;';
247             echo '    margin-top:13px;';
248             echo '    width:100%;';
249             echo '}';
250             echo '.'.$prefix.'TD{';
251             echo '    padding:3px;';
252             echo '    padding-left:5px;';
253             echo '    padding-right:5px;';
254             echo '    border:solid 1px #bbbbbb;';
255             echo '}';
256             echo '.'.$prefix.'Type{';
257             echo '    background-color:#cc0000;';
258             echo '    color:#ffffff;';
259             echo '    font-weight:bold;';
260             echo '    padding:3px;';
261             echo '}';
262             echo '</style>';
263             echo '<script language="javascript" type="text/javascript">';
264             echo 'function '.$prefix.'displayBacktrace( eid )';
265             echo '{';
266             echo '    document.getElementById( "'.$prefix.'" + eid + "backtrace" ).style.display = "block";';
267             echo '}';
268             echo '</script>';
269             
270             $GLOBALS['errorStylesRendered'] = true;
271         }
272
273         $errorID = md5( $error->getFile().$error->getLine() );
274         
275         echo    '<div class="'.$prefix.'Frame">';
276         printf(
277                 '<div style="margin-bottom:8px;"><span class="'.$prefix.'Type">%s:</span> %s in %s on line %s</div>Details: %s (<a href="javascript:'.$prefix.'displayBacktrace( \''.$errorID.'\' );">show backtrace</a>)',
278                 patErrorManager::translateErrorLevel( $error->getLevel() ),
279                 $error->getMessage(),
280                 $error->getFile(),
281                 $error->getLine(),
282                 $error->getInfo()
283             );
284
285         $backtrace    =    $error->getBacktrace();
286         if( is_array( $backtrace ) )
287         {
288             $j    =    1;
289             echo    '<table id="'.$prefix.$errorID.'backtrace" border="0" cellpadding="0" cellspacing="0" class="'.$prefix.'Table" style="display:none;">';
290             echo    '    <tr>';
291             echo    '        <td colspan="3" align="left" class="'.$prefix.'TD"><strong>Call stack</strong></td>';
292             echo    '    </tr>';
293             echo    '    <tr>';
294             echo    '        <td class="'.$prefix.'TD"><strong>#</strong></td>';
295             echo    '        <td class="'.$prefix.'TD"><strong>Function</strong></td>';
296             echo    '        <td class="'.$prefix.'TD"><strong>Location</strong></td>';
297             echo    '    </tr>';
298             for( $i = count( $backtrace )-1; $i >= 0 ; $i-- )
299             {
300                 echo    '    <tr>';
301                 echo    '        <td class="'.$prefix.'TD">'.$j.'</td>';
302                 if( isset( $backtrace[$i]['class'] ) )
303                 {
304                     echo    '    <td class="'.$prefix.'TD">'.$backtrace[$i]['class'].$backtrace[$i]['type'].$backtrace[$i]['function'].'()</td>';
305                 }
306                 else
307                 {
308                     echo    '    <td class="'.$prefix.'TD">'.$backtrace[$i]['function'].'()</td>';
309                 }
310                 if( isset( $backtrace[$i]['file'] ) )
311                 {
312                     echo    '        <td class="'.$prefix.'TD">'.$backtrace[$i]['file'].':'.$backtrace[$i]['line'].'</td>';
313                 }
314                 else
315                 {
316                     echo    '        <td class="'.$prefix.'TD">&nbsp;</td>';
317                 }
318                 echo    '    </tr>';
319                 $j++;
320             }
321             echo    '</table>';
322         }
323         echo    '</div>';
324         
325         $level    =    $error->getLevel();
326         
327         if( $level != E_ERROR )
328             return    $error;
329             
330         exit();
331     }
332
333    /**
334     * Displays an example page along with all defined tabs
335     *
336     * @access    public
337     */
338     function displayExample()
339     {
340         if( !isset( $this->vars['example'] ) )
341             die( 'No example selected.' );
342         
343         $exampleId        =    $this->vars['example'];
344         $section        =    $this->getExampleSection( $exampleId );
345         $example        =    $this->getExample( $exampleId );
346         $exampleFile    =    $exampleId.'.php';
347         $tabs            =    $this->getTabs( $exampleId );
348         $defaultTab        =    $this->getDefaultTab( $tabs );
349         
350         $this->displayHead( 'Example', 'displayTab( \''.$defaultTab.'\' );' );
351         
352         echo '<script type="text/javascript" language="JavaScript1.2">';
353         echo 'var tabs = new Array( \''.implode( "', '", array_keys( $tabs ) ).'\' );';
354         echo 'var actTab = false;';
355         echo 'function hiTab( tabID )';
356         echo '{';
357         echo '    document.getElementById( tabID + \'Tab\' ).className = \'tabA\';';
358         echo '}';
359         echo 'function loTab( tabID )';
360         echo '{';
361         echo '    if( tabID == actTab )';
362         echo '        return true;';
363         echo '    document.getElementById( tabID + \'Tab\' ).className = \'tabN\';';
364         echo '}';
365         echo 'function displayTab( tabID )';
366         echo '{';
367         echo '    for( var i = 0; i < tabs.length; i++ )';
368         echo '    {';
369         echo '        if( tabID == tabs[i] )';
370         echo '            document.getElementById( tabs[i] ).style.display = \'block\';';
371         echo '        else';
372         echo '            document.getElementById( tabs[i] ).style.display = \'none\';';
373         echo '    }';
374         echo '    var oldAct = actTab;';
375         echo '    actTab = tabID;';
376         echo '    hiTab( actTab );';
377         echo '    if( oldAct !== false )';
378         echo '        loTab( oldAct );';
379         echo '}';
380         echo '</script>';
381         echo '<div style="padding:20px;padding-bottom:5px;">';
382         echo '    <div class="head"><b>'.$this->appName.' '.$section.' :: '.$example['title'].'</b></div>';
383         echo '    <div class="abstract">'.htmlentities( $example['descr'] ).'</div>';
384         echo '</div>';
385
386         // the tabs
387         echo '<table border="0" cellpadding="0" cellspacing="0" class="tabs" width="100%">';
388         echo '    <tr>';
389         echo '        <td style="padding-left:15px;">&nbsp;</td>';
390         foreach( $tabs as $tabId => $tabDef )
391         {
392             echo '<td class="tabN" id="'.$tabId.'Tab" onclick="displayTab( \''.$tabId.'\' );" onmouseover="hiTab( \''.$tabId.'\' );" onmouseout="loTab( \''.$tabId.'\' );">'.$tabDef['title'].'</td>';
393             echo '<td>&nbsp;</td>';
394         }
395         echo '        <td width="100%">&nbsp;</td>';
396         echo '    </tr>';
397         echo '</table>';
398         
399         // the tab contents
400         foreach( $tabs as $tabId => $tabDef )
401         {
402             // replace variables in the file string with
403             // the corresponding local variables
404             if( isset( $tabDef['file'] ) )
405             {
406                 // possible vars
407                 $needles = array(
408                     '$exampleFile',
409                     '$exampleId',
410                 );
411                 
412                 // store values
413                 $replace = array();
414                 foreach( $needles as $n )
415                     array_push( $replace, ${substr( $n, 1 )} );
416                 
417                 // replace
418                 $tabDef['file'] = str_replace( $needles, $replace, $tabDef['file'] );
419             }
420         
421             // what kind of tab is this?
422             switch( strtolower( $tabDef['type'] ) )
423             {
424                 case 'phpsource':
425                     $this->displayPHPSource( $tabId, $tabDef['file'] );
426                     break;
427                     
428                 case 'output':
429                     $this->displayOutput( $tabId, $tabDef['file'] );
430                     break;
431                     
432                 case 'xmlsource':
433                     $this->displayXMLSource( $tabId, $tabDef['file'] );
434                     break;
435                 
436                 case 'text':
437                     $this->displayText( $tabId, $tabDef['text'] );
438                     break;
439
440                 case 'guide':
441                     $this->displayGuide( $tabId, $tabDef['file'], $tabDef['guide'] );
442                     break;
443             }
444         }
445         
446         $this->displayFooter();
447     }
448     
449    /**
450     * Display an example's output in an example tab via an iframe
451     *
452     * @access    public
453     * @param    string    $tabId    The ID of the tab
454     * @param    string    $file    The file to show
455     */
456     function displayOutput( $tabId, $file )
457     {
458         echo '<iframe class="exampleContent" style="display:none;" id="'.$tabId.'" src="'.$file.'"></iframe>';
459     }
460     
461     function displayGuide( $tabId, $file, $guide )
462     {
463         $file = explode( "\n", $this->file_get_contents( $file ) );
464
465         echo '    <div class="exampleContent" id="'.$tabId.'">
466                 <style>
467                     .guideEntryTitle{
468                         font-weight:bold;
469                         font-size:12px;
470                         margin-bottom:6px;
471                     }
472                     .guideEntry{
473                         padding:8px;
474                         border:solid 1px #cfcfcf;
475                         background-color:#fafafa;
476                         margin-bottom:20px;
477                     }
478                 </style>';
479
480         foreach( $guide as $row => $entry )
481         {
482             $slice = explode( '-', $entry['lines'] );
483             $hilight = implode( "\n", array_slice( $file, ( $slice[0] -1 ), ( $slice[1] - $slice[0] ) + 1 ) );
484
485             ob_start();
486             highlight_string( '<?php'.$hilight.'?>' );
487             $content = ob_get_contents();
488             ob_end_clean();
489             
490             $content = str_replace( '&lt;?php', '', $content );
491             $content = str_replace( '?&gt;', '', $content );
492             
493             $numbers = '';
494             for( $i=$slice[0]; $i <= $slice[1]; $i++ )
495             {
496                 $numbers .= $i.'.<br>';
497             }
498             
499             echo '    <div class="guideEntryTitle">'.$entry['text'].'</div>
500                     <div class="guideEntry">
501                         <table width="100%" cellpadding="0" cellspacing="0" border="0">
502                             <tr valign="top">
503                                 <td style="padding-right:5px;"><code>'.$numbers.'</code></td>
504                                 <td>'.$content.'</td>
505                             </tr>
506                         </table>
507                     </div>';
508         }
509
510         echo '</div>';
511     }
512
513    /**
514     * Display PHP source code in an example tab
515     *
516     * @access    public
517     * @param    string    $tabId    The ID of the tab
518     * @param    string    $file    The file to hilight
519     */
520     function displayPHPSource( $tabId, $file )
521     {
522         echo '<div class="exampleContent" id="'.$tabId.'">';
523         highlight_file( $file );
524         echo '</div>';
525     }
526     
527    /**
528     * Display a free text in a tab
529     *
530     * @access    public
531     * @param    string    $tabId    The ID of the tab
532     * @param    string    $text    The text to display
533     */
534     function displayText( $tabId, $text )
535     {
536         echo '<div class="exampleContent" id="'.$tabId.'">';
537         echo $text;
538         echo '</div>';
539     }
540
541    /**
542     * Display XML source code in an example tab
543     *
544     * @access    public
545     * @param    string    $tabId    The ID of the tab
546     * @param    string    $file    The file to hilight
547     */
548     function displayXMLSource( $tabId, $file )
549     {
550         $url = str_replace( 'index.php', $file, 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'] );
551     
552         $source = $this->url_get_contents( $url );
553         if( !$source )
554             die( 'Could not open XML source file for hilighting: "'.$url.'"' );
555     
556         echo '<div class="exampleContent" id="'.$tabId.'">';
557         $this->displayXMLString( $source );
558         echo '</div>';
559     }
560     
561    /**
562     * Hilights an xml string and displays it
563     *
564     * @access    public
565