xref: /plugin/struct/syntax/output.php (revision 308cc83fd5391df29d21d2bc1306c8da49fdb335)
1<?php
2
3/**
4 * DokuWiki Plugin struct (Syntax Component)
5 *
6 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
7 * @author  Andreas Gohr, Michael Große <dokuwiki@cosmocode.de>
8 */
9
10use dokuwiki\plugin\struct\meta\AccessTable;
11use dokuwiki\plugin\struct\meta\Assignments;
12use dokuwiki\plugin\struct\meta\StructException;
13
14class syntax_plugin_struct_output extends DokuWiki_Syntax_Plugin
15{
16
17    protected $hasBeenRendered = false;
18
19    const XHTML_OPEN = '<div id="plugin__struct_output">';
20    const XHTML_CLOSE = '</div>';
21
22    /**
23     * Class names of renderers which should NOT render struct data.
24     * All descendants are also blacklisted.
25     */
26    const BLACKLIST_RENDERER = array('Doku_Renderer_metadata');
27
28    /**
29     * Regexp to check on which actions the struct data may be rendered
30     */
31    const WHITELIST_ACTIONS = '/^(show|export_.*)$/';
32
33    /**
34     * @return string Syntax mode type
35     */
36    public function getType()
37    {
38        return 'substition';
39    }
40
41    /**
42     * @return string Paragraph type
43     */
44    public function getPType()
45    {
46        return 'block';
47    }
48
49    /**
50     * @return int Sort order - Low numbers go before high numbers
51     */
52    public function getSort()
53    {
54        return 155;
55    }
56
57    /**
58     * Connect lookup pattern to lexer.
59     *
60     * We do not connect any pattern here, because the call to this plugin is not
61     * triggered from syntax but our action component
62     *
63     * @asee action_plugin_struct_output
64     * @param string $mode Parser mode
65     */
66    public function connectTo($mode)
67    {
68    }
69
70    /**
71     * Handle matches of the struct syntax
72     *
73     * @param string $match The match of the syntax
74     * @param int $state The state of the handler
75     * @param int $pos The position in the document
76     * @param Doku_Handler $handler The handler
77     * @return array Data for the renderer
78     */
79    public function handle($match, $state, $pos, Doku_Handler $handler)
80    {
81        // this is never called
82        return array();
83    }
84
85    /**
86     * Render schema data
87     *
88     * Currently completely renderer agnostic
89     *
90     * @param string $mode Renderer mode
91     * @param Doku_Renderer $R The renderer
92     * @param array $data The data from the handler() function
93     * @return bool If rendering was successful.
94     */
95    public function render($mode, Doku_Renderer $R, $data)
96    {
97        global $ACT;
98        global $ID;
99        global $INFO;
100        global $REV;
101
102        foreach (self::BLACKLIST_RENDERER as $blacklisted) {
103            if ($R instanceof $blacklisted) {
104                return true;
105            }
106        }
107        if ($ID != $INFO['id']) return true;
108        if (!$INFO['exists']) return true;
109        if ($this->hasBeenRendered) return true;
110        if (!preg_match(self::WHITELIST_ACTIONS, act_clean($ACT))) return true;
111
112        // do not render the output twice on the same page, e.g. when another page has been included
113        $this->hasBeenRendered = true;
114        try {
115            $assignments = Assignments::getInstance();
116        } catch (StructException $e) {
117            return false;
118        }
119        $tables = $assignments->getPageAssignments($ID);
120        if (!$tables) return true;
121
122        if ($mode == 'xhtml') $R->doc .= self::XHTML_OPEN;
123
124        $hasdata = false;
125        foreach ($tables as $table) {
126            try {
127                $schemadata = AccessTable::getPageAccess($table, $ID, (int)$REV);
128            } catch (StructException $ignored) {
129                continue; // no such schema at this revision
130            }
131            $schemadata->optionSkipEmpty(true);
132            $data = $schemadata->getData();
133            if (!count($data)) continue;
134            $hasdata = true;
135
136            $R->table_open();
137
138            $R->tablethead_open();
139            $R->tablerow_open();
140            $R->tableheader_open(2);
141            $R->cdata($schemadata->getSchema()->getTranslatedLabel());
142            $R->tableheader_close();
143            $R->tablerow_close();
144            $R->tablethead_close();
145
146            $R->tabletbody_open();
147            foreach ($data as $field) {
148                $R->tablerow_open();
149                $R->tableheader_open();
150                $R->cdata($field->getColumn()->getTranslatedLabel());
151                $R->tableheader_close();
152                $R->tablecell_open();
153                if ($mode == 'xhtml') {
154                    $R->doc = substr($R->doc, 0, -1) .
155                        ' data-struct="' . hsc($field->getColumn()->getFullQualifiedLabel()) .
156                        '">';
157                }
158                $field->render($R, $mode);
159                $R->tablecell_close();
160                $R->tablerow_close();
161            }
162            $R->tabletbody_close();
163            $R->table_close();
164        }
165
166        if ($mode == 'xhtml') $R->doc .= self::XHTML_CLOSE;
167
168        // if no data has been output, remove empty wrapper again
169        if ($mode == 'xhtml' && !$hasdata) {
170            $R->doc = substr($R->doc, 0, -1 * strlen(self::XHTML_OPEN . self::XHTML_CLOSE));
171        }
172
173        return true;
174    }
175}
176
177// vim:ts=4:sw=4:et:
178