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\AccessTable;
11use dokuwiki\plugin\struct\meta\AccessTableGlobal;
12use dokuwiki\plugin\struct\meta\AggregationEditorTable;
13use dokuwiki\plugin\struct\meta\Column;
14use dokuwiki\plugin\struct\meta\Schema;
15use dokuwiki\plugin\struct\meta\SearchConfig;
16use dokuwiki\plugin\struct\meta\StructException;
17use dokuwiki\plugin\struct\meta\Value;
18
19/**
20 * Class action_plugin_struct_lookup
21 *
22 * Handle global and serial data table editing
23 */
24class action_plugin_struct_aggregationeditor extends DokuWiki_Action_Plugin
25{
26    /** @var  Column */
27    protected $column = null;
28
29    /** @var string */
30    protected $pid = '';
31
32    /** @var int */
33    protected $rid = 0;
34
35    /**
36     * Registers a callback function for a given event
37     *
38     * @param Doku_Event_Handler $controller DokuWiki's event controller object
39     * @return void
40     */
41    public function register(Doku_Event_Handler $controller)
42    {
43        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjax');
44    }
45
46    /**
47     * @param Doku_Event $event
48     * @param $param
49     */
50    public function handleAjax(Doku_Event $event, $param)
51    {
52        $len = strlen('plugin_struct_aggregationeditor_');
53        if (substr($event->data, 0, $len) != 'plugin_struct_aggregationeditor_') {
54            return;
55        }
56        $event->preventDefault();
57        $event->stopPropagation();
58
59        try {
60            if (substr($event->data, $len) == 'new') {
61                $this->newRowEditor();
62            }
63
64            if (substr($event->data, $len) == 'save') {
65                $this->saveRow();
66            }
67
68            if (substr($event->data, $len) == 'delete') {
69                $this->deleteRow();
70            }
71        } catch (StructException $e) {
72            http_status(500);
73            header('Content-Type: text/plain');
74            echo $e->getMessage();
75        }
76    }
77
78    /**
79     * Deletes a row
80     */
81    protected function deleteRow()
82    {
83        global $INPUT;
84        $tablename = $INPUT->str('schema');
85        if (!$tablename) {
86            throw new StructException('No schema given');
87        }
88
89        $this->rid = $INPUT->int('rid');
90        $this->validate();
91
92        action_plugin_struct_inline::checkCSRF();
93
94        $access = $this->getAccess($tablename);
95        if (!$access->getSchema()->isEditable()) {
96            throw new StructException('lookup delete error: no permission for schema');
97        }
98        $access->clearData();
99    }
100
101    /**
102     * Save one new row
103     */
104    protected function saveRow()
105    {
106        global $INPUT;
107        $tablename = $INPUT->str('schema');
108        $data = $INPUT->arr('entry');
109        $this->pid = $INPUT->str('pid');
110        action_plugin_struct_inline::checkCSRF();
111
112        // create a new row based on the original aggregation config
113        $access = $this->getAccess($tablename);
114
115        /** @var helper_plugin_struct $helper */
116        $helper = plugin_load('helper', 'struct');
117        $helper->saveLookupData($access, $data);
118
119        $config = json_decode($INPUT->str('searchconf'), true);
120        // update row id
121        $this->rid = $access->getRid();
122        $config = $this->addTypeFilter($config);
123
124        $editorTable = new AggregationEditorTable(
125            $this->pid,
126            'xhtml',
127            new Doku_Renderer_xhtml(),
128            new SearchConfig($config)
129        );
130
131        echo $editorTable->getFirstRow();
132    }
133
134    /**
135     * Create the Editor for a new row
136     */
137    protected function newRowEditor()
138    {
139        global $INPUT;
140        global $lang;
141        $tablename = $INPUT->str('schema');
142
143        $schema = new Schema($tablename);
144        if (!$schema->isEditable()) {
145            return;
146        } // no permissions, no editor
147
148        echo '<div class="struct_entry_form">';
149        echo '<fieldset>';
150        echo '<legend>' . $this->getLang('lookup new entry') . '</legend>';
151        /** @var action_plugin_struct_edit $edit */
152        $edit = plugin_load('action', 'struct_edit');
153        foreach ($schema->getColumns(false) as $column) {
154            $label = $column->getLabel();
155            $field = new Value($column, '');
156            echo $edit->makeField($field, "entry[$label]");
157        }
158        formSecurityToken(); // csrf protection
159        echo '<input type="hidden" name="call" value="plugin_struct_aggregationeditor_save" />';
160        echo '<input type="hidden" name="schema" value="' . hsc($tablename) . '" />';
161
162        echo '<button type="submit">' . $lang['btn_save'] . '</button>';
163
164        echo '<div class="err"></div>';
165        echo '</fieldset>';
166        echo '</div>';
167    }
168
169    /**
170     * Returns data accessor
171     *
172     * @param string $tablename
173     * @return AccessTableGlobal
174     */
175    protected function getAccess($tablename)
176    {
177        if ($this->pid) {
178            return AccessTable::getSerialAccess($tablename, $this->pid, $this->rid);
179        }
180        return AccessTable::getGlobalAccess($tablename, $this->rid);
181    }
182
183    /**
184     * Adds filter to search config to differentiate data types
185     *
186     * @param array $config
187     * @return array
188     */
189    protected function addTypeFilter($config)
190    {
191        $config['filter'][] = ['%rowid%', '=', $this->rid, 'AND'];
192        if ($this->pid) {
193            $config['filter'][] = ['%pageid%', '=', $this->pid, 'AND'];
194        }
195        return $config;
196    }
197
198    /**
199     * Throws an exception if data is invalid
200     */
201    protected function validate()
202    {
203        if (!$this->rid) {
204            throw new StructException('No row id given');
205        }
206    }
207}
208