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; 1394c9aa4cSAndreas Gohruse dokuwiki\plugin\struct\meta\AccessTableData; 14*87dc1344SAndreas Gohruse dokuwiki\plugin\struct\meta\Assignments; 15*87dc1344SAndreas Gohruse dokuwiki\plugin\struct\meta\ValidationResult; 16ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Value; 17c2fd0bf0SMichael Große 183c2e6844SAndreas Gohr/** 193c2e6844SAndreas Gohr * Class action_plugin_struct_entry 203c2e6844SAndreas Gohr * 213c2e6844SAndreas Gohr * Handles the whole struct data entry process 223c2e6844SAndreas Gohr */ 23549a0837SAndreas Gohrclass action_plugin_struct_entry extends DokuWiki_Action_Plugin { 24549a0837SAndreas Gohr 2517560ecbSAndreas Gohr /** 2617560ecbSAndreas Gohr * @var string The form name we use to transfer schema data 2717560ecbSAndreas Gohr */ 2817560ecbSAndreas Gohr protected static $VAR = 'struct_schema_data'; 29c2fd0bf0SMichael Große 30c2fd0bf0SMichael Große /** @var helper_plugin_sqlite */ 31c2fd0bf0SMichael Große protected $sqlite; 32c2fd0bf0SMichael Große 333c2e6844SAndreas Gohr /** @var bool has the data been validated correctly? */ 343c2e6844SAndreas Gohr protected $validated; 353c2e6844SAndreas Gohr 36*87dc1344SAndreas Gohr /** @var ValidationResult[]|string[] these schemas are validated and have changed data and need to be saved */ 373c2e6844SAndreas Gohr protected $tosave; 383c2e6844SAndreas Gohr 39549a0837SAndreas Gohr /** 40549a0837SAndreas Gohr * Registers a callback function for a given event 41549a0837SAndreas Gohr * 42549a0837SAndreas Gohr * @param Doku_Event_Handler $controller DokuWiki's event controller object 43549a0837SAndreas Gohr * @return void 44549a0837SAndreas Gohr */ 45549a0837SAndreas Gohr public function register(Doku_Event_Handler $controller) { 463c2e6844SAndreas Gohr // validate data on preview and save; 473c2e6844SAndreas Gohr $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_validation'); 483c2e6844SAndreas Gohr // ensure a page revision is created when struct data changes: 493c2e6844SAndreas Gohr $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'BEFORE', $this, 'handle_pagesave_before'); 503c2e6844SAndreas Gohr // save struct data after page has been saved: 513c2e6844SAndreas Gohr $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'AFTER', $this, 'handle_pagesave_after'); 52549a0837SAndreas Gohr } 53549a0837SAndreas Gohr 54549a0837SAndreas Gohr /** 553c2e6844SAndreas Gohr * Clean up and validate the input data 563c2e6844SAndreas Gohr * 573c2e6844SAndreas Gohr * @param Doku_Event $event event object by reference 583c2e6844SAndreas Gohr * @param mixed $param [the parameters passed as fifth argument to register_hook() when this 593c2e6844SAndreas Gohr * handler was registered] 603c2e6844SAndreas Gohr * @return bool 613c2e6844SAndreas Gohr */ 623c2e6844SAndreas Gohr public function handle_validation(Doku_Event $event, $param) { 633ece9074SMichael Große global $ID, $INPUT; 6417560ecbSAndreas Gohr $act = act_clean($event->data); 6517560ecbSAndreas Gohr if(!in_array($act, array('save', 'preview'))) return false; 6604641d56SMichael Große 67*87dc1344SAndreas Gohr // run the validation for each assignded schema 68*87dc1344SAndreas Gohr $input = $INPUT->arr(self::$VAR); 69*87dc1344SAndreas Gohr $this->validated = true; 70*87dc1344SAndreas Gohr $assignments = new Assignments(); 71*87dc1344SAndreas Gohr $tables = $assignments->getPageAssignments($ID); 72*87dc1344SAndreas Gohr foreach($tables as $table) { 73*87dc1344SAndreas Gohr $access = new AccessTableData($table, $ID); 74*87dc1344SAndreas Gohr $validation = $access->getValidator($input[$table]); 75*87dc1344SAndreas Gohr if(!$validation->validate()) { 76*87dc1344SAndreas Gohr $this->validated = false; 77*87dc1344SAndreas Gohr foreach($validation->getErrors() as $error) { 78c8a548a8SAndreas Gohr msg(hsc($error), -1); 79bd92cd68SAndreas Gohr } 80*87dc1344SAndreas Gohr } else { 81*87dc1344SAndreas Gohr if($validation->hasChanges()) { 82*87dc1344SAndreas Gohr $this->tosave[] = $validation; 83*87dc1344SAndreas Gohr } 84*87dc1344SAndreas Gohr } 85*87dc1344SAndreas Gohr } 86*87dc1344SAndreas Gohr 87*87dc1344SAndreas Gohr // FIXME we used to set the cleaned data as new input data. this caused #140 88*87dc1344SAndreas 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 95*87dc1344SAndreas 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) { 107*87dc1344SAndreas Gohr if($event->data['contentChanged']) return false; // will be saved for page changes 108d683a527SAndreas Gohr global $ACT; 109*87dc1344SAndreas 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 } 124*87dc1344SAndreas Gohr 125*87dc1344SAndreas Gohr return true; 1263c2e6844SAndreas Gohr } 1273c2e6844SAndreas Gohr 1283c2e6844SAndreas Gohr /** 1293c2e6844SAndreas Gohr * Save the data 1303c2e6844SAndreas Gohr * 131*87dc1344SAndreas 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; 140*87dc1344SAndreas 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) { 147*87dc1344SAndreas Gohr $schemaData = new AccessTableData($table, $event->data['id'], time()); 148eeb8d29fSAndreas Gohr $schemaData->clearData(); 1493c2e6844SAndreas Gohr } 150eeb8d29fSAndreas Gohr } else { 151eeb8d29fSAndreas Gohr // save the provided data 152*87dc1344SAndreas Gohr if($this->tosave) foreach($this->tosave as $validation) { 153*87dc1344SAndreas Gohr $validation->saveData($event->data['newRevision']); 154956fa7d4SAndreas Gohr 155956fa7d4SAndreas Gohr // make sure this schema is assigned 156*87dc1344SAndreas Gohr $assignments->assignPageSchema( 157*87dc1344SAndreas Gohr $event->data['id'], 158*87dc1344SAndreas Gohr $validation->getAccessTable()->getSchema()->getTable() 159*87dc1344SAndreas Gohr ); 1603c2e6844SAndreas Gohr } 1613c2e6844SAndreas Gohr } 162*87dc1344SAndreas 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