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\Assignments;
12use dokuwiki\plugin\struct\meta\Schema;
13use dokuwiki\plugin\struct\meta\Search;
14use dokuwiki\plugin\struct\types\Lookup;
15
16/**
17 * Handles bureaucracy additions
18 *
19 * This registers to the template action of the bureaucracy plugin and saves all struct data
20 * submitted through the bureaucracy form to all newly created pages (if the schema applies).
21 *
22 * It also registers the struct_schema type for bureaucracy which will add all fields of the
23 * schema to the form. The struct_field type is added through standard naming convention - see
24 * helper/fiels.php for that.
25 */
26class action_plugin_struct_bureaucracy extends DokuWiki_Action_Plugin
27{
28    /**
29     * Registers a callback function for a given event
30     *
31     * @param Doku_Event_Handler $controller DokuWiki's event controller object
32     * @return void
33     */
34    public function register(Doku_Event_Handler $controller)
35    {
36        $controller->register_hook('PLUGIN_BUREAUCRACY_PAGENAME', 'BEFORE', $this, 'handleLookupFields');
37        $controller->register_hook('PLUGIN_BUREAUCRACY_EMAIL_SEND', 'BEFORE', $this, 'handleLookupFields');
38        $controller->register_hook('PLUGIN_BUREAUCRACY_TEMPLATE_SAVE', 'AFTER', $this, 'handleSave');
39        $controller->register_hook('PLUGIN_BUREAUCRACY_FIELD_UNKNOWN', 'BEFORE', $this, 'handleSchema');
40    }
41
42    /**
43     * Load a whole schema as fields
44     *
45     * @param Doku_Event $event event object by reference
46     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
47     *                           handler was registered]
48     * @return bool
49     */
50    public function handleSchema(Doku_Event $event, $param)
51    {
52        $args = $event->data['args'];
53        if ($args[0] != 'struct_schema') return false;
54        $event->preventDefault();
55        $event->stopPropagation();
56
57        /** @var helper_plugin_bureaucracy_field $helper */
58        $helper = plugin_load('helper', 'bureaucracy_field');
59        $helper->initialize($args);
60
61        $schema = new Schema($helper->opt['label']);
62        if (!$schema->getId()) {
63            msg('This schema does not exist', -1);
64            return false;
65        }
66
67        foreach ($schema->getColumns(false) as $column) {
68            /** @var helper_plugin_struct_field $field */
69            $field = plugin_load('helper', 'struct_field');
70            // we don't initialize the field but set the appropriate values
71            $field->opt = $helper->opt; // copy all the settings to each field
72            $field->opt['label'] = $column->getFullQualifiedLabel();
73            $field->column = $column;
74            $event->data['fields'][] = $field;
75        }
76        return true;
77    }
78
79    /**
80     * Replace lookup fields placeholder's values
81     *
82     * @param Doku_Event $event event object by reference
83     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
84     *                           handler was registered]
85     * @return bool
86     */
87    public function handleLookupFields(Doku_Event $event, $param)
88    {
89        foreach ($event->data['fields'] as $field) {
90            if (!is_a($field, 'helper_plugin_struct_field')) continue;
91            if (!$field->column->getType() instanceof Lookup) continue;
92
93            $value = $field->getParam('value');
94            if (!is_array($value)) $value = array($value);
95
96            $config = $field->column->getType()->getConfig();
97
98            // find proper value
99            // current Search implementation doesn't allow doing it using SQL
100            $search = new Search();
101            $search->addSchema($config['schema']);
102            $search->addColumn($config['field']);
103            $result = $search->execute();
104            $pids = $search->getPids();
105            $rids = $search->getRids();
106
107            $field->opt['struct_pids'] = array();
108            $new_value = array();
109            foreach ($value as $pid) {
110                for ($i = 0; $i < count($result); $i++) {
111                    // lookups can reference pages or global data, so check both pid and rid
112                    $pid = json_decode($pid)[0] ?: $pid;
113                    $rid = json_decode($pid)[1];
114                    if (($pid && $pids[$i] === $pid) || ($rid && $rids[$i] === (string)$rid)) {
115                        $field->opt['struct_pids'][] = $pid;
116                        $new_value[] = $result[$i][0]->getDisplayValue();
117                    }
118                }
119            }
120
121            //replace previous value
122            if ($field->column->isMulti()) {
123                $field->opt['value'] = $new_value;
124            } else {
125                $event->data['values'][$field->column->getFullQualifiedLabel()] = $new_value[0];
126            }
127        }
128        return true;
129    }
130
131    /**
132     * Save the struct data
133     *
134     * @param Doku_Event $event event object by reference
135     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
136     *                           handler was registered]
137     * @return bool
138     */
139    public function handleSave(Doku_Event $event, $param)
140    {
141        // get all struct values and their associated schemas
142        $tosave = array();
143        foreach ($event->data['fields'] as $field) {
144            if (!is_a($field, 'helper_plugin_struct_field')) continue;
145            /** @var helper_plugin_struct_field $field */
146            $tbl = $field->column->getTable();
147            $lbl = $field->column->getLabel();
148            if (!isset($tosave[$tbl])) $tosave[$tbl] = array();
149
150            if ($field->column->isMulti() && $field->column->getType() instanceof Lookup) {
151                $tosave[$tbl][$lbl] = $field->opt['struct_pids'];
152            } else {
153                $tosave[$tbl][$lbl] = $field->getParam('value');
154            }
155        }
156
157        // save all the struct data of assigned schemas
158        $id = $event->data['id'];
159        $time = filemtime(wikiFN($id));
160
161        $assignments = Assignments::getInstance();
162        $assigned = $assignments->getPageAssignments($id);
163        foreach ($tosave as $table => $data) {
164            if (!in_array($table, $assigned)) continue;
165            $access = AccessTable::getPageAccess($table, $id, $time);
166            $validator = $access->getValidator($data);
167            if ($validator->validate()) {
168                $validator->saveData($time);
169
170                // make sure this schema is assigned
171                $assignments->assignPageSchema(
172                    $id,
173                    $validator->getAccessTable()->getSchema()->getTable()
174                );
175
176                // trigger meta data rendering to set page title
177                p_get_metadata($id);
178            }
179        }
180
181        return true;
182    }
183}
184
185// vim:ts=4:sw=4:et:
186