1<?php
2
3/**
4 * DokuWiki Plugin struct (Action 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\Schema;
11
12/**
13 * Class action_plugin_struct_output
14 *
15 * This action component handles the automatic output of all schema data that has been assigned
16 * to the current page by appending the appropriate instruction to the handler calls.
17 *
18 * The real output creation is done within the syntax component
19 * @see syntax_plugin_struct_output
20 */
21class action_plugin_struct_output extends DokuWiki_Action_Plugin
22{
23    protected const DW2PDF_PLACEHOLDER_PREFIX = 'PLUGIN_STRUCT';
24
25    /**
26     * Registers a callback function for a given event
27     *
28     * @param Doku_Event_Handler $controller DokuWiki's event controller object
29     * @return void
30     */
31    public function register(Doku_Event_Handler $controller)
32    {
33        $controller->register_hook('PARSER_HANDLER_DONE', 'AFTER', $this, 'handleOutput');
34        $controller->register_hook('PLUGIN_DW2PDF_REPLACE', 'BEFORE', $this, 'replaceDw2pdf');
35        $controller->register_hook('PLUGIN_DW2PDF_REPLACE', 'AFTER', $this, 'cleanupDw2pdf');
36    }
37
38    /**
39     * Appends the instruction to render our syntax output component to each page
40     * after the first found headline or the very begining if no headline was found
41     *
42     * @param Doku_Event $event
43     * @param $param
44     */
45    public function handleOutput(Doku_Event $event, $param)
46    {
47        global $ID;
48        if (!page_exists($ID)) return;
49
50        $pos = 0;
51        $ins = -1;
52
53        // display struct data at the bottom?
54        if ($this->getConf('bottomoutput')) {
55            $ins = count($event->data->calls);
56        } elseif (!$this->getConf('topoutput')) {
57            foreach ($event->data->calls as $num => $call) {
58                // try to find the first header
59                if ($call[0] == 'header') {
60                    $pos = $call[2];
61                    $ins = $num;
62                    break;
63                }
64
65                // abort when after we looked at the first 150 bytes
66                if (isset($call[3]) && $call[3] > 150) {
67                    break;
68                }
69            }
70        }
71
72        // insert our own call after the found position
73        array_splice(
74            $event->data->calls,
75            $ins + 1,
76            0,
77            array(
78                array(
79                    'plugin',
80                    array(
81                        'struct_output', array('pos' => $pos), DOKU_LEXER_SPECIAL, ''
82                    ),
83                    $pos
84                )
85            )
86        );
87    }
88
89    /**
90     * If the page has a schema assigned, add its struct data
91     * to dw2pdf's template replacements
92     *
93     * @param Doku_Event $event
94     * @param $param
95     */
96    public function replaceDw2pdf(Doku_Event $event, $param)
97    {
98        if (!$event->data['id'] || !page_exists($event->data['id'])) return;
99
100        global $REV;
101        $rev = $REV ?: time();
102
103        /** @var helper_plugin_struct $helper */
104        $helper = plugin_load('helper', 'struct');
105        $data = $helper->getData($event->data['id'], null, $rev);
106
107        if (!$data) return;
108
109        foreach ($data as $schema => $fields) {
110            $schemaObject = new Schema($schema);
111            foreach ($fields as $field => $value) {
112                // format fields
113                $col = $schemaObject->findColumn($field);
114                if (is_a($col->getType(), '\dokuwiki\plugin\struct\types\Date')) {
115                    $format = $col->getType()->getConfig()['format'];
116                    $value = date($format, strtotime($value));
117                }
118
119                $placeholder = sprintf('@%s_%s_%s@', self::DW2PDF_PLACEHOLDER_PREFIX, $schema, $field);
120                $event->data['replace'][$placeholder] = is_array($value) ? implode(', ', $value) : $value;
121            }
122        }
123    }
124
125    /**
126     * Remove struct placeholders still present after replacement.
127     * Requested data was not found.
128     *
129     * @param Doku_Event $event
130     * @param $param
131     */
132    public function cleanupDw2pdf(Doku_Event $event, $param)
133    {
134        $pattern = '~@' . self::DW2PDF_PLACEHOLDER_PREFIX . '_[^@]+?@~';
135        $event->data['content'] = preg_replace($pattern, '', $event->data['content']);
136    }
137}
138
139// vim:ts=4:sw=4:et:
140