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