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\AccessDataValidator;
11use dokuwiki\plugin\struct\meta\AccessTable;
12use dokuwiki\plugin\struct\meta\Assignments;
13
14/**
15 * Class action_plugin_struct_entry
16 *
17 * Handles the entry process of struct data with type "page"
18 */
19class action_plugin_struct_entry extends DokuWiki_Action_Plugin
20{
21    /**
22     * @var string The form name we use to transfer schema data
23     */
24    protected static $VAR = 'struct_schema_data';
25
26    /** @var helper_plugin_sqlite */
27    protected $sqlite;
28
29    /** @var  bool has the data been validated correctly? */
30    protected $validated;
31
32    /** @var  AccessDataValidator[] these schemas are validated and have changed data and need to be saved */
33    protected $tosave;
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        // validate data on preview and save;
44        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleValidation');
45        // ensure a page revision is created when struct data changes:
46        $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'BEFORE', $this, 'handlePagesaveBefore');
47        // save struct data after page has been saved:
48        $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'AFTER', $this, 'handlePagesaveAfter');
49    }
50
51    /**
52     * Clean up and validate the input data
53     *
54     * @param Doku_Event $event event object by reference
55     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
56     *                           handler was registered]
57     * @return bool
58     */
59    public function handleValidation(Doku_Event $event, $param)
60    {
61        global $ID, $INPUT;
62        $act = act_clean($event->data);
63        if (!in_array($act, array('save', 'preview'))) return false;
64        $this->tosave = array();
65
66        // run the validation for each assignded schema
67        $valid = AccessDataValidator::validateDataForPage($INPUT->arr(self::$VAR), $ID, $errors);
68        if ($valid === false) {
69            $this->validated = false;
70            foreach ($errors as $error) {
71                msg(hsc($error), -1);
72            }
73        } else {
74            $this->validated = true;
75            $this->tosave = $valid;
76        }
77
78        // FIXME we used to set the cleaned data as new input data. this caused #140
79        // could we just not do that, and keep the cleaning to saving only? and fix that bug this way?
80
81        // did validation go through? otherwise abort saving
82        if (!$this->validated && $act == 'save') {
83            $event->data = 'edit';
84        }
85
86        return true;
87    }
88
89    /**
90     * Check if the page has to be changed
91     *
92     * @param Doku_Event $event event object by reference
93     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
94     *                           handler was registered]
95     * @return bool
96     */
97    public function handlePagesaveBefore(Doku_Event $event, $param)
98    {
99        if ($event->data['contentChanged']) return false; // will be saved for page changes
100        global $ACT;
101        if ($ACT == 'revert') return false; // this is handled in revert.php
102
103        if ((is_array($this->tosave) && count($this->tosave)) || isset($GLOBALS['struct_plugin_force_page_save'])) {
104            if (trim($event->data['newContent']) === '') {
105                // this happens when a new page is tried to be created with only struct data
106                msg($this->getLang('emptypage'), -1);
107            } else {
108                $event->data['contentChanged'] = true; // save for data changes
109
110                // add a summary
111                if (empty($event->data['summary'])) {
112                    $event->data['summary'] = $this->getLang('summary');
113                }
114            }
115        }
116
117        return true;
118    }
119
120    /**
121     * Save the data
122     *
123     * When this is called, INPUT data has been validated already.
124     *
125     * @param Doku_Event $event event object by reference
126     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
127     *                           handler was registered]
128     * @return bool
129     */
130    public function handlePagesaveAfter(Doku_Event $event, $param)
131    {
132        global $ACT;
133        if ($ACT == 'revert') return false; // handled in revert
134
135        $assignments = Assignments::getInstance();
136        if ($event->data['changeType'] == DOKU_CHANGE_TYPE_DELETE && empty($GLOBALS['PLUGIN_MOVE_WORKING'])) {
137            // clear all data on delete unless it's a move operation
138            $tables = $assignments->getPageAssignments($event->data['id']);
139            foreach ($tables as $table) {
140                $schemaData = AccessTable::getPageAccess($table, $event->data['id']);
141                if ($schemaData->getSchema()->isEditable()) {
142                    $schemaData->clearData();
143                }
144            }
145        } else {
146            // save the provided data
147            if ($this->tosave) foreach ($this->tosave as $validation) {
148                if ($validation->getAccessTable()->getSchema()->isEditable()) {
149                    $validation->saveData($event->data['newRevision']);
150
151                    // make sure this schema is assigned
152                    $assignments->assignPageSchema(
153                        $event->data['id'],
154                        $validation->getAccessTable()->getSchema()->getTable()
155                    );
156                }
157            }
158        }
159        return true;
160    }
161}
162
163// vim:ts=4:sw=4:et:
164