xref: /plugin/struct/action/entry.php (revision 2987727967455b4335cb8dba900196317113c849)
1<?php
2/**
3 * DokuWiki Plugin struct (Action Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Andreas Gohr, Michael Große <dokuwiki@cosmocode.de>
7 */
8
9// must be run within Dokuwiki
10if(!defined('DOKU_INC')) die();
11
12use plugin\struct\meta\Assignments;
13use plugin\struct\meta\SchemaData;
14use plugin\struct\meta\ValidationException;
15use plugin\struct\types\AbstractBaseType;
16
17class action_plugin_struct_entry extends DokuWiki_Action_Plugin {
18
19    /**
20     * @var string The form name we use to transfer schema data
21     */
22    protected static $VAR = 'struct_schema_data';
23
24    /** @var helper_plugin_sqlite */
25    protected $sqlite;
26
27    /**
28     * Registers a callback function for a given event
29     *
30     * @param Doku_Event_Handler $controller DokuWiki's event controller object
31     * @return void
32     */
33    public function register(Doku_Event_Handler $controller) {
34
35        $controller->register_hook('HTML_EDITFORM_OUTPUT', 'BEFORE', $this, 'handle_editform');
36        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_pagesave');
37
38    }
39
40    /**
41     * Validate the input data and save on ACT=save.
42     *
43     * @param Doku_Event $event event object by reference
44     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
45     *                           handler was registered]
46     * @return bool
47     */
48    public function handle_pagesave(Doku_Event &$event, $param) {
49        global $ID, $INPUT;
50        $act = act_clean($event->data);
51        if(!in_array($act, array('save', 'preview'))) return false;
52
53        $assignments = new Assignments();
54        $tables = $assignments->getPageAssignments($ID);
55        $structData = $INPUT->arr(self::$VAR);
56        $timestamp = time(); //FIXME we should use the time stamp used to save the page data
57
58        $ok = true;
59        foreach($tables as $table) {
60            $schema = new SchemaData($table, $ID, $timestamp);
61            if(!$schema->getId()) {
62                // this schema is not available for some reason. skip it
63                continue;
64            }
65
66            $schemaData = $structData[$table];
67            foreach($schema->getColumns() as $col) {
68                // fix multi value types
69                $type = $col->getType();
70                $label = $type->getLabel();
71                $trans = $type->getTranslatedLabel();
72                if($type->isMulti() && !is_array($schemaData[$label])) {
73                    $schemaData[$label] = $type->splitValues($schemaData[$label]);
74                }
75
76                // validate data
77                $ok = $ok & $this->validate($type, $trans, $schemaData[$label]);
78            }
79
80            // save if validated okay
81            if($ok && $act == 'save') {
82                $schema->saveData($schemaData);
83            }
84
85            // write back cleaned up schemaData
86            $structData[$table] = $schemaData;
87        }
88        // write back cleaned up structData
89        $INPUT->post->set('Schema', $structData);
90
91        // did validation go through? other wise abort saving
92        if(!$ok && $act == 'save') {
93            $event->data = 'edit';
94        }
95
96        return false;
97    }
98
99    /**
100     * Validate the given data
101     *
102     * Catches the Validation exceptions and transforms them into proper messages.
103     *
104     * Blank values are not validated and always pass
105     *
106     * @param AbstractBaseType $type
107     * @param string $label
108     * @param array|string|int $data
109     * @return bool true if the data validates, otherwise false
110     */
111    protected function validate(AbstractBaseType $type, $label, $data) {
112        $prefix = sprintf($this->getLang('validation_prefix'), $label);
113
114        $ok = true;
115        if(is_array($data)) {
116            foreach($data as $value) {
117                if(!blank($value)) {
118                    try {
119                        $type->validate($value);
120                    } catch (ValidationException $e) {
121                        msg($prefix . $e->getMessage(), -1);
122                        $ok = false;
123                    }
124                }
125            }
126        } else {
127            if(!blank($data)) {
128                try {
129                    $type->validate($data);
130                } catch (ValidationException $e) {
131                    msg($prefix . $e->getMessage(), -1);
132                    $ok = false;
133                }
134            }
135        }
136
137        return $ok;
138    }
139
140
141    /*
142     * Enhance the editing form with structural data editing
143     *
144     * @param Doku_Event $event  event object by reference
145     * @param mixed      $param  [the parameters passed as fifth argument to register_hook() when this
146     *                           handler was registered]
147     * @return bool
148     */
149    public function handle_editform(Doku_Event $event, $param) {
150        global $ID;
151
152        $assignments = new Assignments();
153        $tables = $assignments->getPageAssignments($ID);
154
155        $html = '';
156        foreach($tables as $table) {
157            $html .= $this->createForm($table);
158        }
159
160        /** @var Doku_Form $form */
161        $form = $event->data;
162        $html = "<div class=\"struct\">$html</div>";
163        $pos = $form->findElementById('wiki__editbar'); // insert the form before the main buttons
164        $form->insertElement($pos, $html);
165
166        return true;
167    }
168
169    /**
170     * Create the form to edit schemadata
171     *
172     * @param string $tablename
173     * @return string The HTML for this schema's form
174     */
175    protected function createForm($tablename) {
176        global $ID;
177        global $REV;
178        global $INPUT;
179        $schema = new SchemaData($tablename, $ID, $REV);
180        $schemadata = $schema->getData();
181
182        $structdata = $INPUT->arr(self::$VAR);
183        if(isset($structdata[$tablename])) {
184            $postdata = $structdata[$tablename];
185        } else {
186            $postdata = array();
187        }
188
189        $html = "<h3>$tablename</h3>";
190        foreach($schemadata as $field) {
191            $label = $field->getColumn()->getLabel();
192            if(isset($postdata[$label])) {
193                // posted data trumps stored data
194                $field->setValue($postdata[$label]);
195            }
196            $trans = hsc($field->getColumn()->getTranslatedLabel());
197            $name = self::$VAR . "[$tablename][$label]";
198            $input = $field->getValueEditor($name);
199            $element = "<label>$trans $input</label><br />";
200            $html .= $element;
201        }
202
203        return $html;
204    }
205
206}
207
208// vim:ts=4:sw=4:et:
209