xref: /plugin/struct/helper.php (revision 4fc908c26a1ba87b8658df684b82b191fd852c45)
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\AccessTableLookup;
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