xref: /plugin/dbquery/syntax/query.php (revision 19d0a884dddeec9e1724d72d24545e2e89a66bae)
1c64c1748SAndreas Gohr<?php
2c64c1748SAndreas Gohr
39730265cSAndreas Gohruse dokuwiki\Extension\SyntaxPlugin;
49730265cSAndreas Gohr
5c64c1748SAndreas Gohr/**
6c64c1748SAndreas Gohr * DokuWiki Plugin dbquery (Syntax Component)
7c64c1748SAndreas Gohr *
8c64c1748SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
9c64c1748SAndreas Gohr * @author  Andreas Gohr <dokuwiki@cosmocode.de>
10c64c1748SAndreas Gohr */
119730265cSAndreas Gohrclass syntax_plugin_dbquery_query extends SyntaxPlugin
12c64c1748SAndreas Gohr{
13c64c1748SAndreas Gohr    /** @inheritDoc */
14c64c1748SAndreas Gohr    public function getType()
15c64c1748SAndreas Gohr    {
16c64c1748SAndreas Gohr        return 'substition';
17c64c1748SAndreas Gohr    }
18c64c1748SAndreas Gohr
19c64c1748SAndreas Gohr    /** @inheritDoc */
20c64c1748SAndreas Gohr    public function getPType()
21c64c1748SAndreas Gohr    {
22c64c1748SAndreas Gohr        return 'block';
23c64c1748SAndreas Gohr    }
24c64c1748SAndreas Gohr
25c64c1748SAndreas Gohr    /** @inheritDoc */
26c64c1748SAndreas Gohr    public function getSort()
27c64c1748SAndreas Gohr    {
28c64c1748SAndreas Gohr        return 135;
29c64c1748SAndreas Gohr    }
30c64c1748SAndreas Gohr
31c64c1748SAndreas Gohr    /** @inheritDoc */
32c64c1748SAndreas Gohr    public function connectTo($mode)
33c64c1748SAndreas Gohr    {
34c64c1748SAndreas Gohr        $this->Lexer->addSpecialPattern('{{QUERY:\w+}}', $mode, 'plugin_dbquery_query');
35c64c1748SAndreas Gohr    }
36c64c1748SAndreas Gohr
37c64c1748SAndreas Gohr    /** @inheritDoc */
38c64c1748SAndreas Gohr    public function handle($match, $state, $pos, Doku_Handler $handler)
39c64c1748SAndreas Gohr    {
40c64c1748SAndreas Gohr        return ['name' => substr($match, 8, -2)];
41c64c1748SAndreas Gohr    }
42c64c1748SAndreas Gohr
43c64c1748SAndreas Gohr    /** @inheritDoc */
44c64c1748SAndreas Gohr    public function render($mode, Doku_Renderer $renderer, $data)
45c64c1748SAndreas Gohr    {
46c64c1748SAndreas Gohr        if ($mode !== 'xhtml') {
47c64c1748SAndreas Gohr            return false;
48c64c1748SAndreas Gohr        }
49c64c1748SAndreas Gohr
50c64c1748SAndreas Gohr        /** @var helper_plugin_dbquery $hlp */
51c64c1748SAndreas Gohr        $hlp = plugin_load('helper', 'dbquery');
52c64c1748SAndreas Gohr        try {
53c64c1748SAndreas Gohr            $qdata = $hlp->loadDataFromPage($data['name']);
543113520cSAndreas Gohr            $result = $hlp->executeQuery($qdata['codeblocks']['_'], $qdata['macros']['dsn'] ?? null);
55c64c1748SAndreas Gohr        } catch (\Exception $e) {
56c64c1748SAndreas Gohr            msg(hsc($e->getMessage()), -1);
57c64c1748SAndreas Gohr            return true;
58c64c1748SAndreas Gohr        }
59c64c1748SAndreas Gohr
60c64c1748SAndreas Gohr        if (count($result) === 1 && isset($result[0]['status']) && isset($qdata['codeblocks'][$result[0]['status']])) {
61c64c1748SAndreas Gohr            $this->renderStatus($result, $qdata['codeblocks'][$result[0]['status']], $renderer);
629730265cSAndreas Gohr        } elseif ($qdata['macros']['transpose']) {
63c64c1748SAndreas Gohr            $this->renderTransposedResultTable($result, $renderer);
64c64c1748SAndreas Gohr        } else {
65c64c1748SAndreas Gohr            $this->renderResultTable($result, $renderer);
66c64c1748SAndreas Gohr        }
67c64c1748SAndreas Gohr
68c64c1748SAndreas Gohr        return true;
69c64c1748SAndreas Gohr    }
70c64c1748SAndreas Gohr
71c64c1748SAndreas Gohr    /**
72c64c1748SAndreas Gohr     * Render given result via the given status HTML
73c64c1748SAndreas Gohr     *
74c64c1748SAndreas Gohr     * @param string[][] $result
75c64c1748SAndreas Gohr     * @param string $html
76c64c1748SAndreas Gohr     * @param Doku_Renderer $R
77c64c1748SAndreas Gohr     */
78c64c1748SAndreas Gohr    public function renderStatus($result, $html, Doku_Renderer $R)
79c64c1748SAndreas Gohr    {
809730265cSAndreas Gohr        $value = $result[0]['result'] ?? '';
81c64c1748SAndreas Gohr        $html = str_replace(':result', hsc($value), $html);
82c64c1748SAndreas Gohr        $R->doc .= $html;
83c64c1748SAndreas Gohr    }
84c64c1748SAndreas Gohr
85c64c1748SAndreas Gohr    /**
86c64c1748SAndreas Gohr     * Render the given result as a table
87c64c1748SAndreas Gohr     *
88c64c1748SAndreas Gohr     * @param string[][] $result
89c64c1748SAndreas Gohr     * @param Doku_Renderer $R
90c64c1748SAndreas Gohr     */
91c64c1748SAndreas Gohr    public function renderResultTable($result, Doku_Renderer $R)
92c64c1748SAndreas Gohr    {
93c64c1748SAndreas Gohr        global $lang;
94c64c1748SAndreas Gohr
95c64c1748SAndreas Gohr        if (!count($result)) {
96c64c1748SAndreas Gohr            $R->cdata($lang['nothingfound']);
97c64c1748SAndreas Gohr            return;
98c64c1748SAndreas Gohr        }
99c64c1748SAndreas Gohr
100c64c1748SAndreas Gohr        $R->table_open();
10104ef7616SAndreas Gohr        $R->tablethead_open();
102c64c1748SAndreas Gohr        $R->tablerow_open();
103c64c1748SAndreas Gohr        foreach (array_keys($result[0]) as $header) {
104*19d0a884SAndreas Gohr            $header = preg_replace('/_wiki$/', ' ', $header); // remove _wiki type suffix
105c64c1748SAndreas Gohr            $R->tableheader_open();
106c64c1748SAndreas Gohr            $R->cdata($header);
107c64c1748SAndreas Gohr            $R->tableheader_close();
108c64c1748SAndreas Gohr        }
109c64c1748SAndreas Gohr        $R->tablerow_close();
11004ef7616SAndreas Gohr        $R->tablethead_close();
111c64c1748SAndreas Gohr
11204ef7616SAndreas Gohr        $R->tabletbody_open();
113c64c1748SAndreas Gohr        foreach ($result as $row) {
114c64c1748SAndreas Gohr            $R->tablerow_open();
115*19d0a884SAndreas Gohr            foreach ($row as $col =>  $cell) {
116c64c1748SAndreas Gohr                $R->tablecell_open();
117*19d0a884SAndreas Gohr                $this->cellFormat($cell, $R, $col);
118c64c1748SAndreas Gohr                $R->tablecell_close();
119c64c1748SAndreas Gohr            }
120c64c1748SAndreas Gohr            $R->tablerow_close();
121c64c1748SAndreas Gohr        }
12204ef7616SAndreas Gohr        $R->tabletbody_close();
123c64c1748SAndreas Gohr        $R->table_close();
124c64c1748SAndreas Gohr    }
125c64c1748SAndreas Gohr
126c64c1748SAndreas Gohr    /**
127c64c1748SAndreas Gohr     * Render the given result as a table, but turned 90 degrees
128c64c1748SAndreas Gohr     *
129c64c1748SAndreas Gohr     * @param string[][] $result
130c64c1748SAndreas Gohr     * @param Doku_Renderer $R
131c64c1748SAndreas Gohr     */
132c64c1748SAndreas Gohr    public function renderTransposedResultTable($result, Doku_Renderer $R)
133c64c1748SAndreas Gohr    {
134c64c1748SAndreas Gohr        global $lang;
135c64c1748SAndreas Gohr
136c64c1748SAndreas Gohr        if (!count($result)) {
137c64c1748SAndreas Gohr            $R->cdata($lang['nothingfound']);
138c64c1748SAndreas Gohr            return;
139c64c1748SAndreas Gohr        }
140c64c1748SAndreas Gohr
141c64c1748SAndreas Gohr        $width = count($result[0]);
142c64c1748SAndreas Gohr        $height = count($result);
143c64c1748SAndreas Gohr
144c64c1748SAndreas Gohr        $R->table_open();
145c64c1748SAndreas Gohr        for ($x = 0; $x < $width; $x++) {
146*19d0a884SAndreas Gohr            $col = array_keys($result[0])[$x];
147*19d0a884SAndreas Gohr            $header = preg_replace('/_wiki$/', ' ', $col); // remove _wiki type suffix
148*19d0a884SAndreas Gohr
149c64c1748SAndreas Gohr            $R->tablerow_open();
150c64c1748SAndreas Gohr            $R->tableheader_open();
151*19d0a884SAndreas Gohr            $R->cdata($header);
152c64c1748SAndreas Gohr            $R->tableheader_close();
153c64c1748SAndreas Gohr
154c64c1748SAndreas Gohr            for ($y = 0; $y < $height; $y++) {
155c64c1748SAndreas Gohr                $R->tablecell_open();
156*19d0a884SAndreas Gohr                $this->cellFormat(array_values($result[$y])[$x], $R, $col);
157c64c1748SAndreas Gohr                $R->tablecell_close();
158c64c1748SAndreas Gohr            }
159c64c1748SAndreas Gohr            $R->tablerow_close();
160c64c1748SAndreas Gohr        }
161c64c1748SAndreas Gohr        $R->table_close();
162c64c1748SAndreas Gohr    }
163c64c1748SAndreas Gohr
1641b7b5e66SAndreas Gohr    /**
1651b7b5e66SAndreas Gohr     * Pass the given cell content to the correct renderer call
1661b7b5e66SAndreas Gohr     *
1671b7b5e66SAndreas Gohr     * Detects a subset of the wiki link syntax
1681b7b5e66SAndreas Gohr     *
1691b7b5e66SAndreas Gohr     * @param string $content
1701b7b5e66SAndreas Gohr     * @param Doku_Renderer $R
171*19d0a884SAndreas Gohr     * @param string $name Name of the selected column
1721b7b5e66SAndreas Gohr     * @return void
1731b7b5e66SAndreas Gohr     */
174*19d0a884SAndreas Gohr    protected function cellFormat($content, Doku_Renderer $R, $name)
1751b7b5e66SAndreas Gohr    {
176*19d0a884SAndreas Gohr        if(trim($content) === '') {
177*19d0a884SAndreas Gohr            return;
178*19d0a884SAndreas Gohr        }
179*19d0a884SAndreas Gohr
180*19d0a884SAndreas Gohr        // parse wiki syntax
181*19d0a884SAndreas Gohr        if(str_ends_with($name, '_wiki')) {
182*19d0a884SAndreas Gohr            $this->renderInject($R, $content);
183*19d0a884SAndreas Gohr            return;
184*19d0a884SAndreas Gohr        }
185*19d0a884SAndreas Gohr
1861b7b5e66SAndreas Gohr        // external urls
1871b7b5e66SAndreas Gohr        if (preg_match('/^\[\[(https?:\/\/[^|\]]+)(|.*?)?]]$/', $content, $m)) {
1881b7b5e66SAndreas Gohr            $url = $m[1];
1891b7b5e66SAndreas Gohr            $title = $m[2] ?? '';
1901b7b5e66SAndreas Gohr            $title = trim($title, '|');
1911b7b5e66SAndreas Gohr            $R->externallink($url, $title);
1921b7b5e66SAndreas Gohr            return;
1931b7b5e66SAndreas Gohr        }
1941b7b5e66SAndreas Gohr
1951b7b5e66SAndreas Gohr        // internal urls
1961b7b5e66SAndreas Gohr        if (preg_match('/^\[\[([^|\]]+)(|.*?)?]]$/', $content, $m)) {
1971b7b5e66SAndreas Gohr            $page = cleanID($m[1]);
1981b7b5e66SAndreas Gohr            $title = $m[2] ?? '';
1991b7b5e66SAndreas Gohr            $title = trim($title, '|');
2001b7b5e66SAndreas Gohr            $R->internallink($page, $title);
2011b7b5e66SAndreas Gohr            return;
2021b7b5e66SAndreas Gohr        }
2031b7b5e66SAndreas Gohr
2041b7b5e66SAndreas Gohr        $R->cdata($content);
2051b7b5e66SAndreas Gohr    }
206*19d0a884SAndreas Gohr
207*19d0a884SAndreas Gohr    /**
208*19d0a884SAndreas Gohr     * Injects the given syntax into the current renderer
209*19d0a884SAndreas Gohr     *
210*19d0a884SAndreas Gohr     * @param Doku_Renderer $R
211*19d0a884SAndreas Gohr     * @param string $syntax
212*19d0a884SAndreas Gohr     * @return void
213*19d0a884SAndreas Gohr     */
214*19d0a884SAndreas Gohr    protected function renderInject(Doku_Renderer $R, $syntax)
215*19d0a884SAndreas Gohr    {
216*19d0a884SAndreas Gohr        $instructions = p_get_instructions($syntax);
217*19d0a884SAndreas Gohr        foreach ($instructions as $instruction) {
218*19d0a884SAndreas Gohr            // not these
219*19d0a884SAndreas Gohr            if(in_array($instruction[0], ['document_start', 'document_end'])) {
220*19d0a884SAndreas Gohr                continue;
221*19d0a884SAndreas Gohr            }
222*19d0a884SAndreas Gohr
223*19d0a884SAndreas Gohr            // no headers
224*19d0a884SAndreas Gohr            if($instruction[0] === 'header') {
225*19d0a884SAndreas Gohr                $R->p_open();
226*19d0a884SAndreas Gohr                $R->strong_open();
227*19d0a884SAndreas Gohr                $R->cdata($instruction[1][0]);
228*19d0a884SAndreas Gohr                $R->strong_close();
229*19d0a884SAndreas Gohr                $R->p_close();
230*19d0a884SAndreas Gohr                continue;
231*19d0a884SAndreas Gohr            }
232*19d0a884SAndreas Gohr
233*19d0a884SAndreas Gohr            call_user_func_array([$R, $instruction[0]], $instruction[1]);
234*19d0a884SAndreas Gohr        }
235*19d0a884SAndreas Gohr    }
236c64c1748SAndreas Gohr}
237