xref: /plugin/combo/action/snippets.php (revision e8b2ff590c848541e718216df3a67061e98c1761)
1<?php
2
3use ComboStrap\DokuPath;
4use ComboStrap\LogUtility;
5use ComboStrap\PluginUtility;
6use ComboStrap\Resources;
7use ComboStrap\Site;
8use dokuwiki\Cache\CacheRenderer;
9
10if (!defined('DOKU_INC')) die();
11
12/**
13 *
14 *
15 * Add the snippet needed by the components
16 *
17 */
18class action_plugin_combo_snippets extends DokuWiki_Action_Plugin
19{
20
21    const COMBO_CACHE_PREFIX = "combo:cache:";
22
23    /**
24     * @var bool - to trace if the header output was called
25     */
26    private $headerOutputWasCalled = false;
27
28    function __construct()
29    {
30        // enable direct access to language strings
31        // ie $this->lang
32        $this->setupLocale();
33    }
34
35    public function register(Doku_Event_Handler $controller)
36    {
37
38        /**
39         * To add the snippets in the header
40         */
41        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'componentSnippetHead', array());
42
43        /**
44         * To add the snippets in the content
45         * if they have not been added to the header
46         *
47         * Not https://www.dokuwiki.org/devel:event:tpl_content_display TPL_ACT_RENDER
48         * or https://www.dokuwiki.org/devel:event:tpl_act_render
49         * because it works only for the main content
50         * in {@link tpl_content()}
51         *
52         * We use
53         * https://www.dokuwiki.org/devel:event:renderer_content_postprocess
54         * that is in {@link p_render()} and takes into account also the slot page.
55         */
56        $controller->register_hook('RENDERER_CONTENT_POSTPROCESS', 'AFTER', $this, 'componentSnippetContent', array());
57
58        /**
59         * To reset the value
60         */
61        $controller->register_hook('DOKUWIKI_DONE', 'BEFORE', $this, 'close', array());
62
63
64        /**
65         * To log the cache used by bar
66         */
67        $controller->register_hook('PARSER_CACHE_USE', 'AFTER', $this, 'barParsed', array());
68
69    }
70
71    /**
72     * Reset variable
73     * Otherwise in test, when we call it two times, it just fail
74     */
75    function close()
76    {
77
78        $this->headerOutputWasCalled = false;
79
80        /**
81         * Fighting the fact that in 7.2,
82         * there is still a cache
83         */
84        PluginUtility::initSnippetManager();
85
86    }
87
88    /**
89     * Dokuwiki has already a canonical methodology
90     * https://www.dokuwiki.org/canonical
91     *
92     * @param $event
93     */
94    function componentSnippetHead($event)
95    {
96
97
98        global $ID;
99        if (empty($ID)) {
100
101            global $_SERVER;
102            $scriptName = $_SERVER['SCRIPT_NAME'];
103
104            /**
105             * If this is an ajax call, return
106             * only if this not from webcode
107             */
108            if (strpos($scriptName, "/lib/exe/ajax.php") !== false) {
109                global $_REQUEST;
110                $call = $_REQUEST['call'];
111                if ($call != action_plugin_combo_webcode::CALL_ID) {
112                    return;
113                }
114            } else if (!(strpos($scriptName, "/lib/exe/detail.php") !== false)) {
115                /**
116                 * Image page has an header and footer that may needs snippet
117                 * We return only if this is not a image/detail page
118                 */
119                return;
120            }
121        }
122
123        /**
124         * Advertise that the header output was called
125         * If the user is using another template
126         * than strap that does not put the component snippet
127         * in the head
128         * Used in
129         */
130        $this->headerOutputWasCalled = true;
131
132        $snippetManager = PluginUtility::getSnippetManager();
133
134        /**
135         * For each processed bar in the page
136         *   * retrieve the snippets from the cache or store the process one
137         *   * add the cache information in meta
138         */
139        $bars = $snippetManager->getBarsOfPage();
140        foreach ($bars as $barId => $servedFromCache) {
141
142            // Add cache information into the head meta
143            // to test
144            $event->data["meta"][] = array("name" => self::COMBO_CACHE_PREFIX . $barId, "content" => var_export($servedFromCache, true));
145
146            // Get or store the data
147            $cache = new \dokuwiki\Cache\Cache($barId, "snippet");
148            $barFileSystemPath = DokuPath::createPagePathFromPath(DokuPath::PATH_SEPARATOR . $barId)->getFileSystemPath();
149            $dependencies = array(
150                "files" => [
151                    $barFileSystemPath,
152                    Resources::getComboHome() . "/plugin.info.txt"
153                ]
154            );
155
156            // if the bar was served from the cache
157            if ($servedFromCache && $cache->useCache($dependencies)) {
158
159                // Retrieve snippets from previous run
160                $data = $cache->retrieveCache();
161
162                if (!empty($data)) {
163                    $snippets = unserialize($data);
164                    $snippetManager->addSnippetsFromCacheForBar($barId, $snippets);
165
166                    if (Site::debugIsOn()) {
167                        LogUtility::log2file("Snippet cache file {$cache->cache} used", LogUtility::LVL_MSG_DEBUG);
168                        $event->data['script'][] = array(
169                            "type" => "application/json",
170                            "_data" => json_encode($snippets),
171                            "class" => "combo-snippet-cache-" . str_replace(":", "-", $barId));
172                    }
173
174                }
175            } else {
176                $snippets = $snippetManager->getSnippetsForBar($barId);
177                if (!empty($snippets)) {
178                    $cache->storeCache(serialize($snippets));
179                }
180            }
181
182        }
183
184        /**
185         * Snippets
186         */
187        foreach ($snippetManager->getSnippets() as $tagType => $tags) {
188
189            foreach ($tags as $tag) {
190                $event->data[$tagType][] = $tag;
191            }
192
193        }
194
195
196        $snippetManager->close();
197
198    }
199
200    /**
201     * Used if the template does not run the content
202     * before the calling of the header as strap does.
203     *
204     * In this case, the {@link \ComboStrap\SnippetManager::close()} has
205     * not run, and the snippets are still in memory.
206     *
207     * We store them in the HTML and they
208     * follows then the HTML cache of DokuWiki
209     * @param $event
210     */
211    function componentSnippetContent($event)
212    {
213
214        $format = $event->data[0];
215        if ($format !== "xhtml") {
216            return;
217        }
218
219        /**
220         * Run only if the header output was already called
221         */
222        if ($this->headerOutputWasCalled) {
223
224            $snippetManager = PluginUtility::getSnippetManager();
225
226            $xhtmlContent = &$event->data[1];
227            $snippets = $snippetManager->getSnippets();
228            foreach ($snippets as $tagType => $tags) {
229
230                foreach ($tags as $tag) {
231                    $xhtmlContent .= DOKU_LF . "<$tagType";
232                    $attributes = "";
233                    $content = null;
234                    foreach ($tag as $attributeName => $attributeValue) {
235                        if ($attributeName != "_data") {
236                            $attributes .= " $attributeName=\"$attributeValue\"";
237                        } else {
238                            $content = $attributeValue;
239                        }
240                    }
241                    $xhtmlContent .= "$attributes>";
242                    if (!empty($content)) {
243                        $xhtmlContent .= $content;
244                    }
245                    $xhtmlContent .= "</$tagType>" . DOKU_LF;
246                }
247
248            }
249
250            $snippetManager->close();
251
252        }
253
254    }
255
256
257    /**
258     *
259     * @param $event
260     */
261    function barParsed($event)
262    {
263        $data = $event->data;
264        if ($data->mode == "xhtml") {
265
266            /* @var CacheRenderer $data */
267            $pageId = $data->page;
268            $cached = $event->result;
269            PluginUtility::getSnippetManager()->addBar($pageId, $cached);
270
271        }
272
273
274    }
275
276
277}
278