1<?php 2/** 3 * DokuWiki Plugin struct (Helper 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 10use dokuwiki\plugin\struct\meta\AccessDataValidator; 11use dokuwiki\plugin\struct\meta\AccessTable; 12use dokuwiki\plugin\struct\meta\AccessTableLookup; 13use dokuwiki\plugin\struct\meta\Assignments; 14use dokuwiki\plugin\struct\meta\Schema; 15use dokuwiki\plugin\struct\meta\StructException; 16 17if(!defined('DOKU_INC')) die(); 18 19/** 20 * The public interface for the struct plugin 21 * 22 * 3rd party developers should always interact with struct data through this 23 * helper plugin only. If additionional interface functionality is needed, 24 * it should be added here. 25 * 26 * All functions will throw StructExceptions when something goes wrong. 27 * 28 * Remember to check permissions yourself! 29 */ 30class helper_plugin_struct extends DokuWiki_Plugin { 31 32 /** 33 * Get the structured data of a given page 34 * 35 * @param string $page The page to get data for 36 * @param string|null $schema The schema to use null for all 37 * @param int $time A timestamp if you want historic data 38 * @return array ('schema' => ( 'fieldlabel' => 'value', ...)) 39 * @throws StructException 40 */ 41 public function getData($page, $schema = null, $time = 0) { 42 $page = cleanID($page); 43 if (!$time) { 44 $time = time(); 45 } 46 47 if(is_null($schema)) { 48 $assignments = Assignments::getInstance(); 49 $schemas = $assignments->getPageAssignments($page, false); 50 } else { 51 $schemas = array($schema); 52 } 53 54 $result = array(); 55 foreach($schemas as $schema) { 56 $schemaData = AccessTable::byTableName($schema, $page, $time); 57 $result[$schema] = $schemaData->getDataArray(); 58 } 59 60 return $result; 61 } 62 63 /** 64 * Saves data for a given page (creates a new revision) 65 * 66 * If this call succeeds you can assume your data has either been saved or it was 67 * not necessary to save it because the data already existed in the wanted form or 68 * the given schemas are no longer assigned to that page. 69 * 70 * Important: You have to check write permissions for the given page before calling 71 * this function yourself! 72 * 73 * this duplicates a bit of code from entry.php - we could also fake post data and let 74 * entry handle it, but that would be rather unclean and might be problematic when multiple 75 * calls are done within the same request. 76 * 77 * @todo should this try to lock the page? 78 * 79 * 80 * @param string $page 81 * @param array $data ('schema' => ( 'fieldlabel' => 'value', ...)) 82 * @param string $summary 83 * @param string $summary 84 * @throws StructException 85 */ 86 public function saveData($page, $data, $summary = '', $minor = false) 87 { 88 $page = cleanID($page); 89 $summary = trim($summary); 90 if(!$summary) $summary = $this->getLang('summary'); 91 92 if(!page_exists($page)) throw new StructException("Page does not exist. You can not attach struct data"); 93 94 // validate and see if anything changes 95 $valid = AccessDataValidator::validateDataForPage($data, $page, $errors); 96 if($valid === false) { 97 throw new StructException("Validation failed:\n%s", join("\n", $errors)); 98 } 99 if(!$valid) return; // empty array when no changes were detected 100 101 $newrevision = self::createPageRevision($page, $summary, $minor); 102 103 // save the provided data 104 $assignments = Assignments::getInstance(); 105 foreach($valid as $v) { 106 $v->saveData($newrevision); 107 // make sure this schema is assigned 108 $assignments->assignPageSchema($page, $v->getAccessTable()->getSchema()->getTable()); 109 } 110 } 111 112 /** 113 * Save lookup data row 114 * 115 * @param AccessTable $access the table into which to save the data 116 * @param array $data data to be saved in the form of [columnName => 'data'] 117 */ 118 public function saveLookupData(AccessTable $access, $data) 119 { 120 if(!$access->getSchema()->isEditable()) { 121 throw new StructException('lookup save error: no permission for schema'); 122 } 123 $validator = $access->getValidator($data); 124 if(!$validator->validate()) { 125 throw new StructException("Validation failed:\n%s", implode("\n", $validator->getErrors())); 126 } 127 if(!$validator->saveData()) { 128 throw new StructException('No data saved'); 129 } 130 } 131 132 /** 133 * Creates a new page revision with the same page content as before 134 * 135 * @param string $page 136 * @param string $summary 137 * @param bool $minor 138 * @return int the new revision 139 */ 140 static public function createPageRevision($page, $summary = '', $minor = false) { 141 $summary = trim($summary); 142 // force a new page revision @see action_plugin_struct_entry::handle_pagesave_before() 143 $GLOBALS['struct_plugin_force_page_save'] = true; 144 saveWikiText($page, rawWiki($page), $summary, $minor); 145 unset($GLOBALS['struct_plugin_force_page_save']); 146 $file = wikiFN($page); 147 clearstatcache(false, $file); 148 return filemtime($file); 149 } 150 151 /** 152 * Get info about existing schemas 153 * 154 * @param string|null $schema the schema to query, null for all 155 * @return Schema[] 156 * @throws StructException 157 */ 158 public function getSchema($schema = null) { 159 if(is_null($schema)) { 160 $schemas = Schema::getAll(); 161 } else { 162 $schemas = array($schema); 163 } 164 165 $result = array(); 166 foreach($schemas as $table) { 167 $result[$table] = new Schema($table); 168 } 169 return $result; 170 } 171 172 /** 173 * Returns all pages known to the struct plugin 174 * 175 * That means all pages that have or had once struct data saved 176 * 177 * @param string|null $schema limit the result to a given schema 178 * @return array (page => (schema => true), ...) 179 * @throws StructException 180 */ 181 public function getPages($schema = null) { 182 $assignments = Assignments::getInstance(); 183 return $assignments->getPages($schema); 184 } 185 186} 187