1<?php
2
3use dokuwiki\Extension\SyntaxPlugin;
4
5/**
6 * CSV Plugin: displays a cvs formatted file or inline data as a table
7 *
8 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
9 * @author     Steven Danz <steven-danz@kc.rr.com>
10 * @author     Gert
11 * @author     Andreas Gohr <gohr@cosmocode.de>
12 * @author     Jerry G. Geiger <JerryGeiger@web.de>
13 */
14/**
15 * Display CSV data as table
16 */
17class syntax_plugin_csv_table extends SyntaxPlugin
18{
19    /** @inheritdoc */
20    public function getType()
21    {
22        return 'substition';
23    }
24
25    /** @inheritdoc */
26    public function getSort()
27    {
28        return 155;
29    }
30
31    /** @inheritdoc */
32    public function getPType()
33    {
34        return 'block';
35    }
36
37    /** @inheritdoc */
38    public function connectTo($mode)
39    {
40        $this->Lexer->addSpecialPattern('<csv[^>]*>.*?(?:<\/csv>)', $mode, 'plugin_csv_table');
41    }
42
43    /** @inheritdoc */
44    public function handle($match, $state, $pos, Doku_Handler $handler)
45    {
46        $match = substr($match, 4, -6); // <csv ... </csv>
47
48        [$optstr, $content] = explode('>', $match, 2);
49        $opt = helper_plugin_csv::parseOptions($optstr);
50        $opt['content'] = $content;
51
52        return $opt;
53    }
54
55    /** @inheritdoc */
56    public function render($mode, Doku_Renderer $renderer, $opt)
57    {
58        if ($mode == 'metadata') return false;
59
60        // load file data
61        if ($opt['file']) {
62            try {
63                $opt['content'] = helper_plugin_csv::loadContent($opt['file']);
64                if (!media_ispublic($opt['file'])) $renderer->info['cache'] = false;
65            } catch (\Exception $e) {
66                $renderer->cdata($e->getMessage());
67                return true;
68            }
69        }
70
71        // check if there is content
72        $content =& $opt['content'];
73        $content = trim($content);
74        if ($content === '') {
75            $renderer->cdata('No csv data found');
76            return true;
77        }
78
79        $data = helper_plugin_csv::prepareData($content, $opt);
80
81        if (empty($data)) {
82            $message = $this->getLang('no_result');
83            $renderer->cdata($message);
84            return true;
85        }
86
87        $maxcol = count($data[0]);
88        $line = 0;
89
90        // render
91        $renderer->table_open($maxcol, count($data));
92        // Open thead or tbody
93        ($opt['hdr_rows']) ? $renderer->tablethead_open() : $renderer->tabletbody_open();
94        foreach ($data as $row) {
95            // close thead yet?
96            if ($line > 0 && $line == $opt['hdr_rows']) {
97                $renderer->tablethead_close();
98                $renderer->tabletbody_open();
99            }
100            $renderer->tablerow_open();
101            for ($i = 0; $i < $maxcol;) {
102                $span = 1;
103                // lookahead to find spanning cells
104                if ($opt['span_empty_cols']) {
105                    for ($j = $i + 1; $j < $maxcol; $j++) {
106                        if ($row[$j] === '') {
107                            $span++;
108                        } else {
109                            break;
110                        }
111                    }
112                }
113
114                // open cell
115                if ($line < $opt['hdr_rows'] || $i < $opt['hdr_cols']) {
116                    $renderer->tableheader_open($span);
117                } else {
118                    $renderer->tablecell_open($span);
119                }
120
121                // print cell content, call linebreak() for newlines
122                $lines = explode("\n", $row[$i]);
123                $cnt = count($lines);
124                for ($k = 0; $k < $cnt; $k++) {
125                    $renderer->cdata($lines[$k]);
126                    if ($k < $cnt - 1) $renderer->linebreak();
127                }
128
129                // close cell
130                if ($line < $opt['hdr_rows'] || $i < $opt['hdr_cols']) {
131                    $renderer->tableheader_close();
132                } else {
133                    $renderer->tablecell_close();
134                }
135
136                $i += $span;
137            }
138            $renderer->tablerow_close();
139            $line++;
140        }
141        // if there was a tbody, close it
142        if ($opt['hdr_rows'] < $line) $renderer->tabletbody_close();
143        $renderer->table_close();
144
145        return true;
146    }
147}
148