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