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
10if(!defined('DOKU_INC')) die();
11
12if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
13require_once DOKU_PLUGIN.'syntax.php';
14require_once DOKU_INC.'inc/parser/parser.php';
15require_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 */
21class 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}