1<?php
2
3use dokuwiki\Search\Indexer;
4
5/**
6 * DokuWiki Plugin PageTitle; Action component
7 *
8 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
9 * @author     Satoshi Sahara <sahara.satoshi@gmail.com>
10 */
11class action_plugin_pagetitle extends DokuWiki_Action_Plugin
12{
13    /**
14     * register the event handlers
15     */
16    public function register(Doku_Event_Handler $controller) {
17      //$controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'deleteObsoletedSingleClass');
18        $controller->register_hook('INDEXER_VERSION_GET', 'BEFORE', $this, '_indexer_version');
19        $controller->register_hook('INDEXER_PAGE_ADD', 'BEFORE', $this, '_indexer_pagetitle');
20        $controller->register_hook('PARSER_METADATA_RENDER', 'AFTER', $this, '_parser_render');
21        $controller->register_hook('PARSER_CACHE_USE', 'BEFORE', $this, '_prepare_cache');
22    }
23
24    /**
25     * Delete syntax.php which is obsoleted since multi-components syntax structure
26     */
27    public function deleteObsoletedSingleClass(Doku_Event $event)
28    {
29        $legacyFile = dirname(__FILE__).'/syntax.php';
30        if (file_exists($legacyFile)) { unlink($legacyFile); }
31    }
32
33
34    /**
35     * INDEXER_VERSION_GET
36     * Set a version string to the metadata index so that
37     * the index will be re-created when the version increased
38     */
39    public function _indexer_version(Doku_Event $event, $param)
40    {
41        $event->data['plgin_pagetitle'] = '1.'.$this->getConf('usePersistent');
42    }
43
44    /**
45     * INDEXER_PAGE_ADD
46     * Add id of the page to metadata index, relevant pages should be found
47     * in data/index/plugin_pagetitle_w.idx file
48     */
49    public function _indexer_pagetitle(Doku_Event $event, $param)
50    {
51        $metadata = p_get_metadata($event->data['page'], 'plugin pagetitle');
52        $id = $metadata['title'] ?? null;
53        if ($id) {
54            $event->data['metadata']['plugin_pagetitle'] = $id;
55        }
56    }
57
58
59    /**
60     * PAESER_METADATA_RENDER
61     * Use this event to update/reflesh metadata they may have set elseware.
62     * The page metadata is passed including both the current and persistent arrays.
63     */
64    public function _parser_render(Doku_Event $event, $param)
65    {
66        global $ID;
67
68        /*
69         * The PageTitle plugin will overwrite "title" metadata of the page
70         * with "pagetitle" specified in page source. The page must be rendered
71         * first in xhtml mode to get pagetitle and to stote it on metadata
72         * storage.
73
74         * Each metadata storage (.meta file) may be expired or refleshed by
75         * DokuWiki or any plugins at elsewhere in any stage. For example,
76         * metadata will be expired when main config modified. DokuWiki will set
77         * again title metadata through calls p_get_first_heading() depending on
78         * $conf['useheading"] setting.
79         *
80         * Since page text is not changed, instruction and xhtml cache files are
81         * used to set title metadata, there is no chance to handle/render page
82         * source to get pagetitle and to overwite title metadata.
83         * Therfore, the value of "title" metadata will remain wrong with that
84         * pagetitle plugin intended.
85         *
86         * For the purpose to trigger PageTitle plugin's renderer, we tentatively
87         * set $ID as "title" to tell DokuWiki caching mechanism so that old
88         * cache need to be purged and metadata must be rebuild again.
89         */
90
91        $meta       =& $event->data['current'];
92        $persistent =& $event->data['persistent'];
93
94        // check metadata index whether pagetitle had used in the wiki page
95        $pages = $this->getIndexer()->getPages('plugin_pagetitle');
96        $pageTitled = in_array($ID, $pages);
97
98        if (!$pageTitled) return;
99
100        // check whether page has rendered by pagetitle plugin
101        if (!isset($meta['plugin']['pagetitle'])) {
102            // tentatively assign full id as page title, just to distinguish
103            // with normal setting noNS($ID) and to purge .meta file later
104            $meta['title'] = $ID;
105        }
106
107        // unnecessary persistent metadata should be removed in syntax component,
108        // however it may be possible to remove it here
109        if (!$this->getConf('usePersistent')) {
110            unset($persistent['title']);
111        }
112    }
113
114    /**
115     * PARSER_CACHE_USE
116     * prepare the cache object for default _useCache action
117     */
118    public function _prepare_cache(Doku_Event $event, $param)
119    {
120        $cache =& $event->data;
121
122        // we're only interested in wiki pages
123        if (!isset($cache->page)) return;
124
125        // check dependency for hierarchical breadcrumbs
126        if ($cache->mode == 'xhtml') {
127            $metadata = p_get_metadata($cache->page, 'plugin pagetitle');
128            if (isset($metadata['youarehere'])) {
129                isset($helper) || $helper = $this->loadHelper('pagetitle');
130                $html = $helper->html_youarehere(1, $cache->page, $traces);
131                array_pop($traces);
132                $depends = [];
133                foreach ($traces as $id) {
134                    $depends[] = wikiFN($id, '', false);
135                }
136                $cache->depends['files'] = array_merge((array)$cache->depends['files'], $depends);
137            }
138        }
139
140        // check metadata index whether pagetitle had used in the wiki page
141        $pages = $this->getIndexer()->getPages('plugin_pagetitle');
142        $pageTitled = in_array($cache->page, $pages);
143
144        if (!$pageTitled) return;
145
146        // check title metadata whether cache files should be purged
147        $title = p_get_metadata($cache->page, 'title', METADATA_DONT_RENDER);
148        switch ($cache->mode) {
149            case 'i': // instruction cache
150                $request = ($title == $cache->page);
151                break;
152            case 'metadata': // metadata cache?
153                $request = ($title == $cache->page);
154                break;
155            case 'xhtml': // xhtml cache
156                $request = ($title == $cache->page);
157                break;
158        }
159        // request purge if necessary
160        $cache->depends['purge'] = $request;
161    }
162
163    // compatibility
164    private function getIndexer()
165    {
166        return is_callable([Indexer::class, 'getInstance'])
167            ? Indexer::getInstance()
168            : idx_get_indexer();
169    }
170
171}
172