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