xref: /plugin/struct/action/entry.php (revision 67036dabf44b9e0cedad20f245d5bbd56237e48e) !
1549a0837SAndreas Gohr<?php
2549a0837SAndreas Gohr/**
3549a0837SAndreas Gohr * DokuWiki Plugin struct (Action Component)
4549a0837SAndreas Gohr *
5549a0837SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6549a0837SAndreas Gohr * @author  Andreas Gohr, Michael Große <dokuwiki@cosmocode.de>
7549a0837SAndreas Gohr */
8549a0837SAndreas Gohr
9549a0837SAndreas Gohr// must be run within Dokuwiki
10549a0837SAndreas Gohrif(!defined('DOKU_INC')) die();
11549a0837SAndreas Gohr
12f411d872SAndreas Gohruse dokuwiki\plugin\struct\meta\AccessTable;
1387dc1344SAndreas Gohruse dokuwiki\plugin\struct\meta\Assignments;
1487dc1344SAndreas Gohruse dokuwiki\plugin\struct\meta\ValidationResult;
15ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Value;
16c2fd0bf0SMichael Große
173c2e6844SAndreas Gohr/**
183c2e6844SAndreas Gohr * Class action_plugin_struct_entry
193c2e6844SAndreas Gohr *
203c2e6844SAndreas Gohr * Handles the whole struct data entry process
213c2e6844SAndreas Gohr */
22549a0837SAndreas Gohrclass action_plugin_struct_entry extends DokuWiki_Action_Plugin {
23549a0837SAndreas Gohr
2417560ecbSAndreas Gohr    /**
2517560ecbSAndreas Gohr     * @var string The form name we use to transfer schema data
2617560ecbSAndreas Gohr     */
2717560ecbSAndreas Gohr    protected static $VAR = 'struct_schema_data';
28c2fd0bf0SMichael Große
29c2fd0bf0SMichael Große    /** @var helper_plugin_sqlite */
30c2fd0bf0SMichael Große    protected $sqlite;
31c2fd0bf0SMichael Große
323c2e6844SAndreas Gohr    /** @var  bool has the data been validated correctly? */
333c2e6844SAndreas Gohr    protected $validated;
343c2e6844SAndreas Gohr
35f392071eSAndreas Gohr    /** @var  ValidationResult[] these schemas are validated and have changed data and need to be saved */
363c2e6844SAndreas Gohr    protected $tosave;
373c2e6844SAndreas Gohr
38549a0837SAndreas Gohr    /**
39549a0837SAndreas Gohr     * Registers a callback function for a given event
40549a0837SAndreas Gohr     *
41549a0837SAndreas Gohr     * @param Doku_Event_Handler $controller DokuWiki's event controller object
42549a0837SAndreas Gohr     * @return void
43549a0837SAndreas Gohr     */
44549a0837SAndreas Gohr    public function register(Doku_Event_Handler $controller) {
453c2e6844SAndreas Gohr        // validate data on preview and save;
463c2e6844SAndreas Gohr        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_validation');
473c2e6844SAndreas Gohr        // ensure a page revision is created when struct data changes:
483c2e6844SAndreas Gohr        $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'BEFORE', $this, 'handle_pagesave_before');
493c2e6844SAndreas Gohr        // save struct data after page has been saved:
503c2e6844SAndreas Gohr        $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'AFTER', $this, 'handle_pagesave_after');
51549a0837SAndreas Gohr    }
52549a0837SAndreas Gohr
53549a0837SAndreas Gohr    /**
543c2e6844SAndreas Gohr     * Clean up and validate the input data
553c2e6844SAndreas Gohr     *
563c2e6844SAndreas Gohr     * @param Doku_Event $event event object by reference
573c2e6844SAndreas Gohr     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
583c2e6844SAndreas Gohr     *                           handler was registered]
593c2e6844SAndreas Gohr     * @return bool
603c2e6844SAndreas Gohr     */
613c2e6844SAndreas Gohr    public function handle_validation(Doku_Event $event, $param) {
623ece9074SMichael Große        global $ID, $INPUT;
6317560ecbSAndreas Gohr        $act = act_clean($event->data);
6417560ecbSAndreas Gohr        if(!in_array($act, array('save', 'preview'))) return false;
65*67036dabSAndreas Gohr        $this->tosave = array();
6604641d56SMichael Große
6787dc1344SAndreas Gohr        // run the validation for each assignded schema
6887dc1344SAndreas Gohr        $input = $INPUT->arr(self::$VAR);
6987dc1344SAndreas Gohr        $this->validated = true;
7087dc1344SAndreas Gohr        $assignments = new Assignments();
7187dc1344SAndreas Gohr        $tables = $assignments->getPageAssignments($ID);
7287dc1344SAndreas Gohr        foreach($tables as $table) {
73f392071eSAndreas Gohr            $access = AccessTable::byTableName($table, $ID);
7487dc1344SAndreas Gohr            $validation = $access->getValidator($input[$table]);
7587dc1344SAndreas Gohr            if(!$validation->validate()) {
7687dc1344SAndreas Gohr                $this->validated = false;
7787dc1344SAndreas Gohr                foreach($validation->getErrors() as $error) {
78c8a548a8SAndreas Gohr                    msg(hsc($error), -1);
79bd92cd68SAndreas Gohr                }
8087dc1344SAndreas Gohr            } else {
8187dc1344SAndreas Gohr                if($validation->hasChanges()) {
8287dc1344SAndreas Gohr                    $this->tosave[] = $validation;
8387dc1344SAndreas Gohr                }
8487dc1344SAndreas Gohr            }
8587dc1344SAndreas Gohr        }
8687dc1344SAndreas Gohr
8787dc1344SAndreas Gohr        // FIXME we used to set the cleaned data as new input data. this caused #140
8887dc1344SAndreas Gohr        // could we just not do that, and keep the cleaning to saving only? and fix that bug this way?
89bd92cd68SAndreas Gohr
9017560ecbSAndreas Gohr        // did validation go through? otherwise abort saving
913c2e6844SAndreas Gohr        if(!$this->validated && $act == 'save') {
9217560ecbSAndreas Gohr            $event->data = 'edit';
9317560ecbSAndreas Gohr        }
9417560ecbSAndreas Gohr
9587dc1344SAndreas Gohr        return true;
9604641d56SMichael Große    }
9704641d56SMichael Große
9817560ecbSAndreas Gohr    /**
993c2e6844SAndreas Gohr     * Check if the page has to be changed
1003c2e6844SAndreas Gohr     *
1013c2e6844SAndreas Gohr     * @param Doku_Event $event event object by reference
1023c2e6844SAndreas Gohr     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
1033c2e6844SAndreas Gohr     *                           handler was registered]
1043c2e6844SAndreas Gohr     * @return bool
1053c2e6844SAndreas Gohr     */
1063c2e6844SAndreas Gohr    public function handle_pagesave_before(Doku_Event $event, $param) {
10787dc1344SAndreas Gohr        if($event->data['contentChanged']) return false; // will be saved for page changes
108d683a527SAndreas Gohr        global $ACT;
10987dc1344SAndreas Gohr        if($ACT == 'revert') return false; // this is handled in revert.php
1107dac04ffSAndreas Gohr
1117dac04ffSAndreas Gohr        if(count($this->tosave) || isset($GLOBALS['struct_plugin_force_page_save'])) {
1123c2e6844SAndreas Gohr            if(trim($event->data['newContent']) === '') {
1133c2e6844SAndreas Gohr                // this happens when a new page is tried to be created with only struct data
1143c2e6844SAndreas Gohr                msg($this->getLang('emptypage'), -1);
1153c2e6844SAndreas Gohr            } else {
1163c2e6844SAndreas Gohr                $event->data['contentChanged'] = true; // save for data changes
11748010be8SAndreas Gohr
11848010be8SAndreas Gohr                // add a summary
11948010be8SAndreas Gohr                if(empty($event->data['summary'])) {
12048010be8SAndreas Gohr                    $event->data['summary'] = $this->getLang('summary');
12148010be8SAndreas Gohr                }
1223c2e6844SAndreas Gohr            }
123d683a527SAndreas Gohr        }
12487dc1344SAndreas Gohr
12587dc1344SAndreas Gohr        return true;
1263c2e6844SAndreas Gohr    }
1273c2e6844SAndreas Gohr
1283c2e6844SAndreas Gohr    /**
1293c2e6844SAndreas Gohr     * Save the data
1303c2e6844SAndreas Gohr     *
13187dc1344SAndreas Gohr     * When this is called, INPUT data has been validated already.
13256672c36SAndreas Gohr     *
1333c2e6844SAndreas Gohr     * @param Doku_Event $event event object by reference
1343c2e6844SAndreas Gohr     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
1353c2e6844SAndreas Gohr     *                           handler was registered]
1363c2e6844SAndreas Gohr     * @return bool
1373c2e6844SAndreas Gohr     */
1383c2e6844SAndreas Gohr    public function handle_pagesave_after(Doku_Event $event, $param) {
13956672c36SAndreas Gohr        global $ACT;
14087dc1344SAndreas Gohr        if($ACT == 'revert') return false; // handled in revert
1413c2e6844SAndreas Gohr
142956fa7d4SAndreas Gohr        $assignments = new Assignments();
14358cb1498SAndreas Gohr        if($event->data['changeType'] == DOKU_CHANGE_TYPE_DELETE && empty($GLOBALS['PLUGIN_MOVE_WORKING'])) {
14458cb1498SAndreas Gohr            // clear all data on delete unless it's a move operation
145eeb8d29fSAndreas Gohr            $tables = $assignments->getPageAssignments($event->data['id']);
146eeb8d29fSAndreas Gohr            foreach($tables as $table) {
147f392071eSAndreas Gohr                $schemaData = AccessTable::byTableName($table, $event->data['id'], time());
148eeb8d29fSAndreas Gohr                $schemaData->clearData();
1493c2e6844SAndreas Gohr            }
150eeb8d29fSAndreas Gohr        } else {
151eeb8d29fSAndreas Gohr            // save the provided data
15287dc1344SAndreas Gohr            if($this->tosave) foreach($this->tosave as $validation) {
15387dc1344SAndreas Gohr                $validation->saveData($event->data['newRevision']);
154956fa7d4SAndreas Gohr
155956fa7d4SAndreas Gohr                // make sure this schema is assigned
15687dc1344SAndreas Gohr                $assignments->assignPageSchema(
15787dc1344SAndreas Gohr                    $event->data['id'],
15887dc1344SAndreas Gohr                    $validation->getAccessTable()->getSchema()->getTable()
15987dc1344SAndreas Gohr                );
1603c2e6844SAndreas Gohr            }
1613c2e6844SAndreas Gohr        }
16287dc1344SAndreas Gohr        return true;
163eeb8d29fSAndreas Gohr    }
1643c2e6844SAndreas Gohr
1653c2e6844SAndreas Gohr    /**
16665598e4aSAndreas Gohr     * Create the form to edit schemadata
167f36fda9dSAndreas Gohr     *
168c2fd0bf0SMichael Große     * @param string $tablename
16965598e4aSAndreas Gohr     * @return string The HTML for this schema's form
170c2fd0bf0SMichael Große     */
17165598e4aSAndreas Gohr    protected function createForm($tablename) {
172c2fd0bf0SMichael Große        global $ID;
17383beda18SAndreas Gohr        global $REV;
17417560ecbSAndreas Gohr        global $INPUT;
175fc13e8e7SMichael Große        if(auth_quickaclcheck($ID) == AUTH_READ) return '';
176cb249c51SMichael Große        if(checklock($ID)) return '';
177f411d872SAndreas Gohr        $schema = AccessTable::byTableName($tablename, $ID, $REV);
178c2fd0bf0SMichael Große        $schemadata = $schema->getData();
179c2fd0bf0SMichael Große
18017560ecbSAndreas Gohr        $structdata = $INPUT->arr(self::$VAR);
18117560ecbSAndreas Gohr        if(isset($structdata[$tablename])) {
18217560ecbSAndreas Gohr            $postdata = $structdata[$tablename];
18317560ecbSAndreas Gohr        } else {
18417560ecbSAndreas Gohr            $postdata = array();
18517560ecbSAndreas Gohr        }
18617560ecbSAndreas Gohr
1875d5ff984SAndreas Gohr        // we need a short, unique identifier to use in the cookie. this should be good enough
1885d5ff984SAndreas Gohr        $schemaid = 'SRCT' . substr(str_replace(array('+', '/'), '', base64_encode(sha1($tablename, true))), 0, 5);
1895d5ff984SAndreas Gohr        $html = '<fieldset data-schema="' . $schemaid . '">';
19034bdbea7SAndreas Gohr        $html .= '<legend>' . hsc($tablename) . '</legend>';
191053212b1SAndreas Gohr        foreach($schemadata as $field) {
192053212b1SAndreas Gohr            $label = $field->getColumn()->getLabel();
19317560ecbSAndreas Gohr            if(isset($postdata[$label])) {
19417560ecbSAndreas Gohr                // posted data trumps stored data
19517560ecbSAndreas Gohr                $field->setValue($postdata[$label]);
19617560ecbSAndreas Gohr            }
19795838d50SAndreas Gohr            $html .= $this->makeField($field, self::$VAR . "[$tablename][$label]");
198ed3de3d6SAndreas Gohr        }
199ed3de3d6SAndreas Gohr        $html .= '</fieldset>';
200ed3de3d6SAndreas Gohr
201ed3de3d6SAndreas Gohr        return $html;
202ed3de3d6SAndreas Gohr    }
203ed3de3d6SAndreas Gohr
204ed3de3d6SAndreas Gohr    /**
205ed3de3d6SAndreas Gohr     * Create the input field
206ed3de3d6SAndreas Gohr     *
207ed3de3d6SAndreas Gohr     * @param Value $field
208ed3de3d6SAndreas Gohr     * @param String $name field's name
209ed3de3d6SAndreas Gohr     * @return string
210ed3de3d6SAndreas Gohr     */
2116b5e52fdSAndreas Gohr    public function makeField(Value $field, $name) {
2129e9bee91SAndreas Gohr        $trans = hsc($field->getColumn()->getTranslatedLabel());
2133a717675SAndreas Gohr        $hint = hsc($field->getColumn()->getTranslatedHint());
2143a717675SAndreas Gohr        $class = $hint ? 'hashint' : '';
215ed3de3d6SAndreas Gohr        $colname = $field->getColumn()->getFullQualifiedLabel();
2163a717675SAndreas Gohr
217053212b1SAndreas Gohr        $input = $field->getValueEditor($name);
2182350b48eSAndreas Gohr
2192350b48eSAndreas Gohr        // we keep all the custom form stuff the field might produce, but hide it
2202350b48eSAndreas Gohr        if(!$field->getColumn()->isVisibleInEditor()) {
2212350b48eSAndreas Gohr            $hide = 'style="display:none"';
2222350b48eSAndreas Gohr        } else {
2232350b48eSAndreas Gohr            $hide = '';
2242350b48eSAndreas Gohr        }
2252350b48eSAndreas Gohr
226ed3de3d6SAndreas Gohr        $html = '';
227ed3de3d6SAndreas Gohr        $html .= "<label $hide data-column=\"$colname\">";
2283a717675SAndreas Gohr        $html .= "<span class=\"label $class\" title=\"$hint\">$trans</span>";
2293a717675SAndreas Gohr        $html .= "<span class=\"input\">$input</span>";
2303a717675SAndreas Gohr        $html .= '</label>';
23165598e4aSAndreas Gohr
23265598e4aSAndreas Gohr        return $html;
233549a0837SAndreas Gohr    }
234549a0837SAndreas Gohr}
235549a0837SAndreas Gohr
236549a0837SAndreas Gohr// vim:ts=4:sw=4:et:
237