1<?php
2/**
3 * Plugin SQL:  executes SQL queries
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Slim Amamou <slim.amamou@gmail.com>
7 */
8
9if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
10if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
11require_once(DOKU_PLUGIN.'syntax.php');
12require_once(DOKU_INC.'inc/parserutils.php');
13require_once('DB.php');
14
15function property($prop, $xml)
16{
17	$pattern = '/'.$prop ."='([^']*)')/";
18	if (preg_match($pattern, $xml, $matches)) {
19		return $matches[1];
20	}
21	$pattern = '/'.$prop .'="([^"]*)"/';
22	if (preg_match($pattern, $xml, $matches)) {
23		return $matches[1];
24	}
25	return FALSE;
26}
27
28/**
29 * All DokuWiki plugins to extend the parser/rendering mechanism
30 * need to inherit from this class
31 */
32class syntax_plugin_sql extends DokuWiki_Syntax_Plugin {
33    var $databases = array();
34	var $wikitext_enabled = TRUE;
35	var $display_inline = FALSE;
36	var $vertical_position = FALSE;
37
38    /**
39     * What kind of syntax are we?
40     */
41    function getType(){
42        return 'substition';
43    }
44
45    /**
46     * Where to sort in?
47     */
48    function getSort(){
49        return 555;
50    }
51
52
53    /**
54     * Connect pattern to lexer
55     */
56    function connectTo($mode) {
57      $this->Lexer->addEntryPattern('<sql [^>]*>',$mode,'plugin_sql');
58    }
59
60    function postConnect() {
61      $this->Lexer->addExitPattern('</sql>','plugin_sql');
62    }
63
64
65    /**
66     * Handle the match
67     */
68    function handle($match, $state, $pos, Doku_Handler $handler){
69        switch ($state) {
70          case DOKU_LEXER_ENTER :
71			$urn = property('db',$match);
72			$wikitext = property('wikitext', $match);
73			$display = property('display', $match);
74			$position = property('position', $match);
75			return array('urn' => $urn, 'wikitext' => $wikitext, 'display' => $display, 'position' => $position);
76            break;
77          case DOKU_LEXER_UNMATCHED :
78			$queries = explode(';', $match);
79			if (trim(end($queries)) == "") {
80				array_pop($queries);
81			}
82			return array('sql' => $queries);
83            break;
84          case DOKU_LEXER_EXIT :
85			$this->wikitext_enabled = TRUE;
86			$this->display_inline = FALSE;
87			$this->vertical_position = FALSE;
88			return array('wikitext' => 'enable', 'display' => 'block', 'position' => 'horizontal');
89            break;
90        }
91        return array();
92    }
93
94    /**
95     * Create output
96     */
97    function render($mode, Doku_Renderer $renderer, $data) {
98		$renderer->info['cache'] = false;
99
100        if($mode == 'xhtml'){
101
102			if ($data['wikitext'] == 'disable') {
103				$this->wikitext_enabled = FALSE;
104			} else if ($data['wikitext'] == 'enable') {
105				$this->wikitext_enabled = TRUE;
106			}
107			if ($data['display'] == 'inline') {
108				$this->display_inline = TRUE;
109			} else if ($data['display'] == 'block') {
110				$this->display_inline = FALSE;
111			}
112			if ($data['position'] == 'vertical') {
113				$this->vertical_position = TRUE;
114			} else if ($data['position'] == 'horizontal') {
115				$this->vertical_position = FALSE;
116			}
117			if ($data['urn'] != "") {
118				try {
119					$db =& DB::connect($data['urn']);
120				} catch(Exception $e) {
121					$error = $e->getMessage();
122					$renderer->doc .= '<div class="error">Plugin SQL Error '. $error .'</div>';
123					return TRUE;
124				}
125				array_push($this->databases, $db);
126			}
127			elseif (!empty($data['sql'])) {
128			    $db =& array_pop($this->databases);
129				if (!empty($db)) {
130					foreach ($data['sql'] as $query) {
131						try {
132							$result =& $db->getAll($query);
133						} catch(Exception $e) {
134							$error = $e->getMessage();
135							$renderer->doc .= '<div class="error">Plugin SQL Error '. $error .'</div>';
136							return TRUE;
137						}
138
139							if (! $this->vertical_position) {
140								if ($this->display_inline) {
141									$renderer->doc .= '<table class="inline" style="display:inline"><tbody>';
142								} else {
143									$renderer->doc .= '<table class="inline"><tbody>';
144								}
145								$renderer->doc .= '<tr>';
146								foreach (array_keys($result[0]) as $header) {
147									$renderer->doc .= '<th>';
148									if ($this->wikitext_enabled) {
149										$renderer->nest(p_get_instructions($header));
150									} else {
151										$renderer->cdata($header);
152									}
153									$renderer->doc .= '</th>';
154								}
155								$renderer->doc .= '</tr>';
156								foreach ($result as $row) {
157									$renderer->doc .= '<tr>';
158									foreach ($row as $cell) {
159										$renderer->doc .= '<td>';
160										if ($this->wikitext_enabled) {
161											$renderer->nest(p_get_instructions($cell));
162										} else {
163											$renderer->cdata($cell);
164										}
165										$renderer->doc .= '</td>';
166									}
167									$renderer->doc .= '</td>';
168									$renderer->doc .= '</tr>';
169								}
170								$renderer->doc .= '</tbody></table>';
171							} else {
172								foreach ($result as $row) {
173									$renderer->doc .= '<table class="inline"><tbody>';
174									foreach ($row as $name => $cell) {
175										$renderer->doc .= '<tr>';
176										$renderer->doc .= "<th>$name</th>";
177										$renderer->doc .= '<td>';
178										if ($this->wikitext_enabled) {
179											$renderer->nest(p_get_instructions($cell));
180										} else {
181											$renderer->cdata($cell);
182										}
183										$renderer->doc .= '</td>';
184										$renderer->doc .= '</tr>';
185									}
186									$renderer->doc .= '</tbody></table>';
187								}
188							}
189					}
190				}
191			}
192            return true;
193        }
194        return false;
195    }
196}
197