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