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