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; 1493ca6f4fSAndreas Gohruse dokuwiki\plugin\struct\meta\AccessDataValidator; 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 3593ca6f4fSAndreas Gohr /** @var AccessDataValidator[] 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; 6567036dabSAndreas Gohr $this->tosave = array(); 6604641d56SMichael Große 6787dc1344SAndreas Gohr // run the validation for each assignded schema 6893ca6f4fSAndreas Gohr $valid = AccessDataValidator::validateDataForPage($INPUT->arr(self::$VAR), $ID, $errors); 6993ca6f4fSAndreas Gohr if($valid === false) { 7087dc1344SAndreas Gohr $this->validated = false; 7193ca6f4fSAndreas Gohr foreach($errors as $error) { 72c8a548a8SAndreas Gohr msg(hsc($error), -1); 73bd92cd68SAndreas Gohr } 7487dc1344SAndreas Gohr } else { 7593ca6f4fSAndreas Gohr $this->validated = true; 7693ca6f4fSAndreas Gohr $this->tosave = $valid; 7787dc1344SAndreas Gohr } 7887dc1344SAndreas Gohr 7987dc1344SAndreas Gohr // FIXME we used to set the cleaned data as new input data. this caused #140 8087dc1344SAndreas Gohr // could we just not do that, and keep the cleaning to saving only? and fix that bug this way? 81bd92cd68SAndreas Gohr 8217560ecbSAndreas Gohr // did validation go through? otherwise abort saving 833c2e6844SAndreas Gohr if(!$this->validated && $act == 'save') { 8417560ecbSAndreas Gohr $event->data = 'edit'; 8517560ecbSAndreas Gohr } 8617560ecbSAndreas Gohr 8787dc1344SAndreas Gohr return true; 8804641d56SMichael Große } 8904641d56SMichael Große 9017560ecbSAndreas Gohr /** 913c2e6844SAndreas Gohr * Check if the page has to be changed 923c2e6844SAndreas Gohr * 933c2e6844SAndreas Gohr * @param Doku_Event $event event object by reference 943c2e6844SAndreas Gohr * @param mixed $param [the parameters passed as fifth argument to register_hook() when this 953c2e6844SAndreas Gohr * handler was registered] 963c2e6844SAndreas Gohr * @return bool 973c2e6844SAndreas Gohr */ 983c2e6844SAndreas Gohr public function handle_pagesave_before(Doku_Event $event, $param) { 9987dc1344SAndreas Gohr if($event->data['contentChanged']) return false; // will be saved for page changes 100d683a527SAndreas Gohr global $ACT; 10187dc1344SAndreas Gohr if($ACT == 'revert') return false; // this is handled in revert.php 1027dac04ffSAndreas Gohr 1037dac04ffSAndreas Gohr if(count($this->tosave) || isset($GLOBALS['struct_plugin_force_page_save'])) { 1043c2e6844SAndreas Gohr if(trim($event->data['newContent']) === '') { 1053c2e6844SAndreas Gohr // this happens when a new page is tried to be created with only struct data 1063c2e6844SAndreas Gohr msg($this->getLang('emptypage'), -1); 1073c2e6844SAndreas Gohr } else { 1083c2e6844SAndreas Gohr $event->data['contentChanged'] = true; // save for data changes 10948010be8SAndreas Gohr 11048010be8SAndreas Gohr // add a summary 11148010be8SAndreas Gohr if(empty($event->data['summary'])) { 11248010be8SAndreas Gohr $event->data['summary'] = $this->getLang('summary'); 11348010be8SAndreas Gohr } 1143c2e6844SAndreas Gohr } 115d683a527SAndreas Gohr } 11687dc1344SAndreas Gohr 11787dc1344SAndreas Gohr return true; 1183c2e6844SAndreas Gohr } 1193c2e6844SAndreas Gohr 1203c2e6844SAndreas Gohr /** 1213c2e6844SAndreas Gohr * Save the data 1223c2e6844SAndreas Gohr * 12387dc1344SAndreas Gohr * When this is called, INPUT data has been validated already. 12456672c36SAndreas Gohr * 1253c2e6844SAndreas Gohr * @param Doku_Event $event event object by reference 1263c2e6844SAndreas Gohr * @param mixed $param [the parameters passed as fifth argument to register_hook() when this 1273c2e6844SAndreas Gohr * handler was registered] 1283c2e6844SAndreas Gohr * @return bool 1293c2e6844SAndreas Gohr */ 1303c2e6844SAndreas Gohr public function handle_pagesave_after(Doku_Event $event, $param) { 13156672c36SAndreas Gohr global $ACT; 13287dc1344SAndreas Gohr if($ACT == 'revert') return false; // handled in revert 1333c2e6844SAndreas Gohr 134*025cb9daSAndreas Gohr $assignments = Assignments::getInstance(); 13558cb1498SAndreas Gohr if($event->data['changeType'] == DOKU_CHANGE_TYPE_DELETE && empty($GLOBALS['PLUGIN_MOVE_WORKING'])) { 13658cb1498SAndreas Gohr // clear all data on delete unless it's a move operation 137eeb8d29fSAndreas Gohr $tables = $assignments->getPageAssignments($event->data['id']); 138eeb8d29fSAndreas Gohr foreach($tables as $table) { 139f392071eSAndreas Gohr $schemaData = AccessTable::byTableName($table, $event->data['id'], time()); 1406ebbbb8eSAndreas Gohr if($schemaData->getSchema()->isEditable()){ 141eeb8d29fSAndreas Gohr $schemaData->clearData(); 1423c2e6844SAndreas Gohr } 1436ebbbb8eSAndreas Gohr } 144eeb8d29fSAndreas Gohr } else { 145eeb8d29fSAndreas Gohr // save the provided data 14687dc1344SAndreas Gohr if($this->tosave) foreach($this->tosave as $validation) { 1476ebbbb8eSAndreas Gohr if($validation->getAccessTable()->getSchema()->isEditable()) { 14887dc1344SAndreas Gohr $validation->saveData($event->data['newRevision']); 149956fa7d4SAndreas Gohr 150956fa7d4SAndreas Gohr // make sure this schema is assigned 15187dc1344SAndreas Gohr $assignments->assignPageSchema( 15287dc1344SAndreas Gohr $event->data['id'], 15387dc1344SAndreas Gohr $validation->getAccessTable()->getSchema()->getTable() 15487dc1344SAndreas Gohr ); 1553c2e6844SAndreas Gohr } 1563c2e6844SAndreas Gohr } 1576ebbbb8eSAndreas Gohr } 15887dc1344SAndreas Gohr return true; 159eeb8d29fSAndreas Gohr } 1603c2e6844SAndreas Gohr 1613c2e6844SAndreas Gohr /** 16265598e4aSAndreas Gohr * Create the form to edit schemadata 163f36fda9dSAndreas Gohr * 164c2fd0bf0SMichael Große * @param string $tablename 16565598e4aSAndreas Gohr * @return string The HTML for this schema's form 166c2fd0bf0SMichael Große */ 16765598e4aSAndreas Gohr protected function createForm($tablename) { 168c2fd0bf0SMichael Große global $ID; 16983beda18SAndreas Gohr global $REV; 17017560ecbSAndreas Gohr global $INPUT; 171fc13e8e7SMichael Große if(auth_quickaclcheck($ID) == AUTH_READ) return ''; 172cb249c51SMichael Große if(checklock($ID)) return ''; 173f411d872SAndreas Gohr $schema = AccessTable::byTableName($tablename, $ID, $REV); 174c2fd0bf0SMichael Große $schemadata = $schema->getData(); 175c2fd0bf0SMichael Große 17617560ecbSAndreas Gohr $structdata = $INPUT->arr(self::$VAR); 17717560ecbSAndreas Gohr if(isset($structdata[$tablename])) { 17817560ecbSAndreas Gohr $postdata = $structdata[$tablename]; 17917560ecbSAndreas Gohr } else { 18017560ecbSAndreas Gohr $postdata = array(); 18117560ecbSAndreas Gohr } 18217560ecbSAndreas Gohr 1835d5ff984SAndreas Gohr // we need a short, unique identifier to use in the cookie. this should be good enough 1845d5ff984SAndreas Gohr $schemaid = 'SRCT' . substr(str_replace(array('+', '/'), '', base64_encode(sha1($tablename, true))), 0, 5); 1855d5ff984SAndreas Gohr $html = '<fieldset data-schema="' . $schemaid . '">'; 18634bdbea7SAndreas Gohr $html .= '<legend>' . hsc($tablename) . '</legend>'; 187053212b1SAndreas Gohr foreach($schemadata as $field) { 188053212b1SAndreas Gohr $label = $field->getColumn()->getLabel(); 18917560ecbSAndreas Gohr if(isset($postdata[$label])) { 190c0230d2cSAndreas Gohr // posted data trumps stored data -> set as raw value 191c0230d2cSAndreas Gohr $field->setValue($postdata[$label], true); 19217560ecbSAndreas Gohr } 19395838d50SAndreas Gohr $html .= $this->makeField($field, self::$VAR . "[$tablename][$label]"); 194ed3de3d6SAndreas Gohr } 195ed3de3d6SAndreas Gohr $html .= '</fieldset>'; 196ed3de3d6SAndreas Gohr 197ed3de3d6SAndreas Gohr return $html; 198ed3de3d6SAndreas Gohr } 199ed3de3d6SAndreas Gohr 200ed3de3d6SAndreas Gohr /** 201ed3de3d6SAndreas Gohr * Create the input field 202ed3de3d6SAndreas Gohr * 203ed3de3d6SAndreas Gohr * @param Value $field 204ed3de3d6SAndreas Gohr * @param String $name field's name 205ed3de3d6SAndreas Gohr * @return string 206ed3de3d6SAndreas Gohr */ 2076b5e52fdSAndreas Gohr public function makeField(Value $field, $name) { 2089e9bee91SAndreas Gohr $trans = hsc($field->getColumn()->getTranslatedLabel()); 2093a717675SAndreas Gohr $hint = hsc($field->getColumn()->getTranslatedHint()); 2103a717675SAndreas Gohr $class = $hint ? 'hashint' : ''; 211ed3de3d6SAndreas Gohr $colname = $field->getColumn()->getFullQualifiedLabel(); 2123a717675SAndreas Gohr 213053212b1SAndreas Gohr $input = $field->getValueEditor($name); 2142350b48eSAndreas Gohr 2152350b48eSAndreas Gohr // we keep all the custom form stuff the field might produce, but hide it 2162350b48eSAndreas Gohr if(!$field->getColumn()->isVisibleInEditor()) { 2172350b48eSAndreas Gohr $hide = 'style="display:none"'; 2182350b48eSAndreas Gohr } else { 2192350b48eSAndreas Gohr $hide = ''; 2202350b48eSAndreas Gohr } 2212350b48eSAndreas Gohr 222ed3de3d6SAndreas Gohr $html = ''; 223ed3de3d6SAndreas Gohr $html .= "<label $hide data-column=\"$colname\">"; 2243a717675SAndreas Gohr $html .= "<span class=\"label $class\" title=\"$hint\">$trans</span>"; 2253a717675SAndreas Gohr $html .= "<span class=\"input\">$input</span>"; 2263a717675SAndreas Gohr $html .= '</label>'; 22765598e4aSAndreas Gohr 22865598e4aSAndreas Gohr return $html; 229549a0837SAndreas Gohr } 230549a0837SAndreas Gohr} 231549a0837SAndreas Gohr 232549a0837SAndreas Gohr// vim:ts=4:sw=4:et: 233