1<?php
2/**
3 * DokuWiki Plugin strata (Action Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Brend Wanders <b.wanders@utwente.nl>
7 */
8
9// must be run within Dokuwiki
10if (!defined('DOKU_INC')) die('Meh.');
11
12/**
13 * This action component exists to allow the definition of
14 * the type autoloader.
15 */
16class action_plugin_strata extends DokuWiki_Action_Plugin {
17
18    /**
19     * Register function called by DokuWiki to allow us
20     * to register events we're interested in.
21     *
22     * @param controller object the controller to register with
23     */
24    public function register(Doku_Event_Handler $controller) {
25        $controller->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, '_io_page_write');
26        $controller->register_hook('PARSER_METADATA_RENDER', 'BEFORE', $this, '_parser_metadata_render_before');
27        $controller->register_hook('STRATA_PREVIEW_METADATA_RENDER', 'BEFORE', $this, '_parser_metadata_render_before');
28        $controller->register_hook('TPL_ACT_RENDER', 'BEFORE', $this, '_preview_before');
29        $controller->register_hook('TPL_ACT_RENDER', 'AFTER', $this, '_preview_after');
30
31        $controller->register_hook('PARSER_METADATA_RENDER', 'AFTER', $this, '_parser_metadata_render_after');
32        $controller->register_hook('STRATA_PREVIEW_METADATA_RENDER', 'AFTER', $this, '_parser_metadata_render_after');
33    }
34
35
36    /**
37     * Triggers before preview xhtml render,
38     * allows plugins to metadata render on the preview.
39     */
40    public function _preview_before(&$event, $param) {
41        global $ACT;
42        global $TEXT;
43        global $SUF;
44        global $PRE;
45        global $ID;
46        global $METADATA_RENDERERS;
47
48        if($ACT == 'preview') {
49            $triples =& plugin_load('helper', 'strata_triples');
50            $triples->beginPreview();
51
52            $text = $PRE.$TEXT.$SUF;
53            $orig = p_read_metadata($ID);
54
55            // store the original metadata in the global $METADATA_RENDERERS so p_set_metadata can use it
56            $METADATA_RENDERERS[$ID] =& $orig;
57
58            // add an extra key for the event - to tell event handlers the page whose metadata this is
59            $orig['page'] = $ID;
60            $evt = new Doku_Event('STRATA_PREVIEW_METADATA_RENDER', $orig);
61            if ($evt->advise_before()) {
62                // get instructions
63                $instructions = p_get_instructions($text);
64                if(is_null($instructions)){
65                    unset($METADATA_RENDERERS[$ID]);
66                    return null; // something went wrong with the instructions
67                }
68
69                // set up the renderer
70                $renderer = new renderer_plugin_strata();
71                $renderer->meta =& $orig['current'];
72                $renderer->persistent =& $orig['persistent'];
73
74                // loop through the instructions
75                foreach ($instructions as $instruction){
76                    // execute the callback against the renderer
77                    call_user_func_array(array(&$renderer, $instruction[0]), (array) $instruction[1]);
78                }
79
80                $evt->result = array('current'=>&$renderer->meta,'persistent'=>&$renderer->persistent);
81            }
82            $evt->advise_after();
83
84            // clean up
85            unset($METADATA_RENDERERS[$ID]);
86        }
87    }
88
89
90    public function _preview_after(&$event, $param) {
91        global $ACT;
92
93        if($ACT == 'preview') {
94            $triples =& plugin_load('helper', 'strata_triples');
95            $triples->endPreview();
96        }
97    }
98
99    /**
100     * Triggered whenever a page is written. We need to handle
101     * this event because metadata is not rendered if a page is removed.
102     */
103    public function _io_page_write(&$event, $param) {
104        // only remove triples if page is a new revision, or if it is removed
105        if($event->data[3] == false || $event->data[0][1] == '') {
106            $id = ltrim($event->data[1].':'.$event->data[2],':');
107            $this->_purge_data($id);
108        }
109    }
110
111    /**
112     * Triggered before metadata is going to be rendered. We
113     * remove triples previously generated by the page that is going to
114     * be rendered so we don't get duplicate entries.
115     */
116    public function _parser_metadata_render_before(&$event, $param) {
117        $this->_purge_data($event->data['page']);
118    }
119
120    /**
121     * Triggered after metadata has been rendered.
122     * We check the fixTitle flag, and if it is present, we
123     * add the entry title.
124     */
125    public function _parser_metadata_render_after(&$event, $param) {
126        $id = $event->data['page'];
127
128        $current =& $event->data['current'];
129
130        if(isset($current['strata']['fixTitle']) && $current['strata']['fixTitle']) {
131            // get helpers
132            $triples =& plugin_load('helper', 'strata_triples');
133            $util =& plugin_load('helper', 'strata_util');
134
135            $title = $current['title'] ?? null;
136            if(!$title) {
137                $title = noNS($id);
138            }
139
140            $title = $util->loadType('text')->normalize($title,'');
141
142            $triples->addTriple($id, $util->getTitleKey(), $title, $id);
143        }
144    }
145
146    /**
147     * Purges the data for a single page id.
148     *
149     * @param id string the page that needs to be purged
150     */
151    private function _purge_data($id) {
152        // get triples helper
153        $triples =& plugin_load('helper', 'strata_triples');
154
155        // remove all triples defined in this graph
156        $triples->removeTriples(null,null,null,$id);
157    }
158}
159
160/**
161 * Strata 'pluggable' autoloader. This function is responsible
162 * for autoloading classes that should be pluggable by external
163 * plugins.
164 *
165 * @param fullname string the name of the class to load
166 */
167function plugin_strata_autoload($fullname) {
168    static $classes = null;
169    if(is_null($classes)) $classes = array(
170        'strata_exception'         => DOKU_PLUGIN.'strata/lib/strata_exception.php',
171        'strata_querytree_visitor' => DOKU_PLUGIN.'strata/lib/strata_querytree_visitor.php',
172        'plugin_strata_type'       => DOKU_PLUGIN.'strata/lib/strata_type.php',
173        'plugin_strata_aggregate'  => DOKU_PLUGIN.'strata/lib/strata_aggregate.php',
174   );
175
176    if(isset($classes[$fullname])) {
177        require_once($classes[$fullname]);
178        return;
179    }
180
181    // only load matching components
182    if(preg_match('/^plugin_strata_(type|aggregate)_(.*)$/',$fullname, $matches)) {
183        // use descriptive names
184        list(,$kind,$name) = $matches;
185
186        // glob to find the required file
187        $filenames = glob(DOKU_PLUGIN."*/{$kind}s/{$name}.php");
188        if($filenames === false || count($filenames) == 0) {
189            // if we have no file, fake an implementation
190            eval("class $fullname extends plugin_strata_{$kind} { };");
191        } else {
192            // include the file
193            require_once $filenames[0];
194            // If the class still does not exist, the required file does not define the class, so we fall back
195            // to the default
196            if(!class_exists($fullname)) {
197                eval("class $fullname extends plugin_strata_{$kind} { };");
198            }
199        }
200
201        return;
202    }
203}
204
205// register autoloader with SPL loader stack
206spl_autoload_register('plugin_strata_autoload');
207