1 <?php
2 /**
3  * Plugin dbtables: Generate a series of tables
4  *
5  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6  * @author     Stephen C <pontiac76@gmail.com>
7  */
8 
9 // must be run within DokuWiki
10 if(!defined('DOKU_INC')) die();
11 
12 if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
13 require_once DOKU_PLUGIN.'syntax.php';
14 require_once DOKU_INC.'inc/parser/parser.php';
15 require_once DOKU_INC . 'inc/parser/xhtml.php';
16 
17 /**
18  * All DokuWiki plugins to extend the parser/rendering mechanism
19  * need to inherit from this class
20  */
21 class syntax_plugin_dbtables extends DokuWiki_Syntax_Plugin {
22 
23     // $options is used for rendering options
24     public $options=array();
25 
26     function getInfo() {
27         return array('author' => 'Stephen C',
28                      'email'  => 'pontiac76@gmail.com',
29                      'date'   => '2010-09-29',
30                      'name'   => 'DB Tables',
31                      'desc'   => 'Draw Database Tables in a Wiki',
32                      'url'    => 'http://ginger.gotdns.com/public/wiki/download/dbtables.zip');
33     }
34 
35     function getType() { return 'substition'; }
36     function getSort() { return 32; }
37 
38     function connectTo($mode) {
39         $this->Lexer->addEntryPattern('<dbtables *[^>]*>',$mode,'plugin_dbtables');
40     }
41 
42     function postConnect() {
43         $this->Lexer->addExitPattern('</dbtables>','plugin_dbtables');
44     }
45 
46     /**
47      * Handle the match
48      */
49     function handle($match, $state, $pos, &$handler){
50         switch ($state) {
51             case DOKU_LEXER_ENTER :
52               return array($state, substr($match, 10, -1) );
53               break;
54             case DOKU_LEXER_MATCHED :
55               return array($state,$match);
56               break;
57             case DOKU_LEXER_UNMATCHED :
58               return array($state, $match);
59               break;
60             case DOKU_LEXER_EXIT :
61               return array($state, '');
62               break;
63         }
64         return array();
65     }
66 
67     function render_tables($match,$mode,$data) {
68       // $match is the full text we're to consider
69       $raw=explode("\n",$match);
70 
71       $CurrentTable="";
72 
73       // Run through each line and decide how to render the text
74       foreach($raw as $rawline) {
75         if (trim($rawline)!=""){
76           // Is this row the name of a table?
77           if (substr($rawline,0,1)==$this->options["thead"]) {
78             // Yes, so draw the heading
79 
80             // Remember the current table name
81             $CurrentTable=substr($rawline,1);
82             // Draw the Dokuwiki table heading
83             $TableData[$CurrentTable].="^$CurrentTable".substr("^^^^^^^^^^",0,$this->options["cols"])."\n";
84             // Draw the descriptors of each field
85             for($ColPos=1;$ColPos<=$this->options["cols"];$ColPos++)
86               $TableData[$CurrentTable].="^".$this->options["c".$ColPos]." ";
87             $TableData[$CurrentTable].="^\n";
88           } else {
89             // No, so draw the schema for the current table
90 
91             // If we haven't seen a table name yet, skip it.
92             if ($CurrentTable!="") {
93               // Split the fields up.
94               $RowInfo=explode($this->options["fdelim"],$rawline);
95               // $RowsOut keeps track of how many entities we've sent.  Add 1
96               $RowsOut=$this->options["cols"];
97               // Go through each entity and output it
98               foreach($RowInfo as $RowData) {
99                 if ($RowsOut>0) {
100                   $TableData[$CurrentTable].="|".$RowData."  ";
101                   $RowsOut=$RowsOut-1;
102                 }
103               }
104               // Draw the tailing wiki table identifiers, including spaces
105               $EndOfTable=substr("|  |  |  |  |  |  |  |  |  |  ",0,($RowsOut+1)*3);
106               // SHIP IT!
107               $TableData[$CurrentTable].=trim($EndOfTable)."\n";
108             }
109           }
110         }
111       }
112       // By default, we sort the table listings.
113       if ($this->options["nosort"]=="")
114         sort($TableData);
115       // Start the HTML table rendering
116       $res="</p><table";
117       if ($this->options["twidth"]!="")
118         $res.=" width='".$this->options["twidth"]."'>";
119       else
120         $res.=">";
121 
122       // Used to count how many tables we've sent for rendering.
123       $CurTablePos=0;
124       foreach($TableData as $TableStruct) {
125         // Prepare the table information
126         // The option to not render from Dokuwiki to HTML is available
127         if ($this->options["norender"]=="")
128           $td="<td class='dbtables-td_".$CurTablePos % $this->options["groups"]."'>".p_render($mode,p_get_instructions($TableStruct),$data)."</td>";
129         else
130           $td="<td><pre>".$TableStruct."</pre></td>";
131 
132         // Decide if we're going to draw a new HTML-table row.
133         if (($CurTablePos % $this->options["groups"] ) == 0) {
134           // If we've NOT drawn a DB-table yet, DON'T end the TR
135           if ($CurTablePos!=0)
136             $res.="</tr>\n";
137           // Draw the table row
138           $res.="\n<tr class='dbtables-tr_".$CurTablePos % $this->options["groups"]."' valign='top'>\n";
139         }
140         // Write out the table data
141         $res.=$td."\n";
142         $CurTablePos=$CurTablePos+1;
143       }
144       // Close off the HTML-Table
145       $res.="</tr></table><p>";
146       return $res;
147     }
148 
149     function render($mode, &$renderer, $data) {
150       // This will only render in xhtml
151       if($mode == 'xhtml'){
152          list($state, $match) = $data;
153           switch ($state) {
154               // This happens when we first find the <dbtables>
155               case DOKU_LEXER_ENTER :
156                 $parmsexp=explode(';',$match);
157                 // Set the relevant default values
158                 $this->options["groups"]=4; // How many HTML tables across we want to see
159                 $this->options["cols"]=4;  // How many headings for each DB field do we want?
160                 $this->options["c1"]="Field";  // Default texts for fields
161                 $this->options["c2"]="Type";
162                 $this->options["c3"]="Relation";
163                 $this->options["c4"]="Desc";
164                 $this->options["fdelim"]=":"; // The character used to delimit what goes between fields
165                 $this->options["thead"]="_";  // The character used to indicate the table name
166                 // $this->options["twidth"]  // Default HTML table width in HTML specifications (IE: 95% - 960px)
167                 // $this->options["nosort"] -> Assign a value to NOT sort the tables
168                 // $this->options["norender"] -> Assign a value to NOT render from Dokuwiki to HTML
169 
170                 // Prepare each option
171                 foreach($parmsexp as $pexp) {
172                   $p=explode("=",$pexp);
173                   $this->options[$p[0]]=$p[1];
174                 }
175                 break;
176               // This happens each line between <dbtables> and </dbtables>
177               case DOKU_LEXER_UNMATCHED :
178                 // Send to the rendering function
179                 $renderer->doc.=$this->render_tables($match,$mode,$data);
180                 //$renderer->doc .= $renderer->_xmlEntities($match);
181                 break;
182           }
183           return true;
184       }
185       return false;
186     }
187 }