xref: /plugin/combo/action/snippets.php (revision c3437056399326d621a01da73b649707fbb0ae69)
15f891b7eSNickeau<?php
25f891b7eSNickeau
3*c3437056SNickeauuse ComboStrap\CacheManager;
4654a02feSgerardnicouse ComboStrap\DokuPath;
5*c3437056SNickeauuse ComboStrap\ExceptionCombo;
65f891b7eSNickeauuse ComboStrap\LogUtility;
75f891b7eSNickeauuse ComboStrap\PluginUtility;
8654a02feSgerardnicouse ComboStrap\Resources;
9*c3437056SNickeauuse ComboStrap\Snippet;
10*c3437056SNickeauuse ComboStrap\SnippetManager;
11*c3437056SNickeauuse dokuwiki\Cache\CacheParser;
125f891b7eSNickeau
135f891b7eSNickeauif (!defined('DOKU_INC')) die();
145f891b7eSNickeau
155f891b7eSNickeau/**
165f891b7eSNickeau *
175f891b7eSNickeau *
185f891b7eSNickeau * Add the snippet needed by the components
195f891b7eSNickeau *
205f891b7eSNickeau */
215f891b7eSNickeauclass action_plugin_combo_snippets extends DokuWiki_Action_Plugin
225f891b7eSNickeau{
235f891b7eSNickeau
245f891b7eSNickeau    /**
255f891b7eSNickeau     * @var bool - to trace if the header output was called
265f891b7eSNickeau     */
275f891b7eSNickeau    private $headerOutputWasCalled = false;
285f891b7eSNickeau
295f891b7eSNickeau    function __construct()
305f891b7eSNickeau    {
315f891b7eSNickeau        // enable direct access to language strings
325f891b7eSNickeau        // ie $this->lang
335f891b7eSNickeau        $this->setupLocale();
345f891b7eSNickeau    }
355f891b7eSNickeau
365f891b7eSNickeau    public function register(Doku_Event_Handler $controller)
375f891b7eSNickeau    {
388aa9d0e6Sgerardnico
3921913ab3SNickeau        /**
4021913ab3SNickeau         * To add the snippets in the header
4121913ab3SNickeau         */
425f891b7eSNickeau        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'componentSnippetHead', array());
4321913ab3SNickeau
4421913ab3SNickeau        /**
4521913ab3SNickeau         * To add the snippets in the content
4621913ab3SNickeau         * if they have not been added to the header
47531e725cSNickeau         *
48531e725cSNickeau         * Not https://www.dokuwiki.org/devel:event:tpl_content_display TPL_ACT_RENDER
49531e725cSNickeau         * or https://www.dokuwiki.org/devel:event:tpl_act_render
50531e725cSNickeau         * because it works only for the main content
51531e725cSNickeau         * in {@link tpl_content()}
52531e725cSNickeau         *
53531e725cSNickeau         * We use
54531e725cSNickeau         * https://www.dokuwiki.org/devel:event:renderer_content_postprocess
55531e725cSNickeau         * that is in {@link p_render()} and takes into account also the slot page.
5621913ab3SNickeau         */
57531e725cSNickeau        $controller->register_hook('RENDERER_CONTENT_POSTPROCESS', 'AFTER', $this, 'componentSnippetContent', array());
588aa9d0e6Sgerardnico
5921913ab3SNickeau        /**
6021913ab3SNickeau         * To reset the value
6121913ab3SNickeau         */
6221913ab3SNickeau        $controller->register_hook('DOKUWIKI_DONE', 'BEFORE', $this, 'close', array());
638aa9d0e6Sgerardnico
6421913ab3SNickeau
655f891b7eSNickeau    }
665f891b7eSNickeau
675f891b7eSNickeau    /**
6832b85071SNickeau     * Reset variable
6932b85071SNickeau     * Otherwise in test, when we call it two times, it just fail
7032b85071SNickeau     */
7121913ab3SNickeau    function close()
7221913ab3SNickeau    {
7332b85071SNickeau
7432b85071SNickeau        $this->headerOutputWasCalled = false;
7532b85071SNickeau
7632b85071SNickeau        /**
7732b85071SNickeau         * Fighting the fact that in 7.2,
7832b85071SNickeau         * there is still a cache
7932b85071SNickeau         */
80*c3437056SNickeau        SnippetManager::init();
8132b85071SNickeau
8232b85071SNickeau    }
8332b85071SNickeau
8432b85071SNickeau    /**
855f891b7eSNickeau     * Dokuwiki has already a canonical methodology
865f891b7eSNickeau     * https://www.dokuwiki.org/canonical
875f891b7eSNickeau     *
885f891b7eSNickeau     * @param $event
895f891b7eSNickeau     */
905f891b7eSNickeau    function componentSnippetHead($event)
915f891b7eSNickeau    {
925f891b7eSNickeau
935f891b7eSNickeau
945f891b7eSNickeau        global $ID;
955f891b7eSNickeau        if (empty($ID)) {
96e8b2ff59SNickeau
9721913ab3SNickeau            global $_SERVER;
98e8b2ff59SNickeau            $scriptName = $_SERVER['SCRIPT_NAME'];
99e8b2ff59SNickeau
100e8b2ff59SNickeau            /**
101e8b2ff59SNickeau             * If this is an ajax call, return
102e8b2ff59SNickeau             * only if this not from webcode
103e8b2ff59SNickeau             */
104e8b2ff59SNickeau            if (strpos($scriptName, "/lib/exe/ajax.php") !== false) {
10521913ab3SNickeau                global $_REQUEST;
10621913ab3SNickeau                $call = $_REQUEST['call'];
10721913ab3SNickeau                if ($call != action_plugin_combo_webcode::CALL_ID) {
1085f891b7eSNickeau                    return;
1095f891b7eSNickeau                }
110e8b2ff59SNickeau            } else if (!(strpos($scriptName, "/lib/exe/detail.php") !== false)) {
111e8b2ff59SNickeau                /**
112e8b2ff59SNickeau                 * Image page has an header and footer that may needs snippet
113e8b2ff59SNickeau                 * We return only if this is not a image/detail page
114e8b2ff59SNickeau                 */
115e8b2ff59SNickeau                return;
11621913ab3SNickeau            }
11721913ab3SNickeau        }
1185f891b7eSNickeau
1195f891b7eSNickeau        /**
1205f891b7eSNickeau         * Advertise that the header output was called
1215f891b7eSNickeau         * If the user is using another template
1225f891b7eSNickeau         * than strap that does not put the component snippet
1235f891b7eSNickeau         * in the head
1245f891b7eSNickeau         * Used in
1255f891b7eSNickeau         */
1265f891b7eSNickeau        $this->headerOutputWasCalled = true;
1275f891b7eSNickeau
1285f891b7eSNickeau        $snippetManager = PluginUtility::getSnippetManager();
129*c3437056SNickeau        $cacheManager = CacheManager::getOrCreate();
1305f891b7eSNickeau
1315f891b7eSNickeau        /**
1328aa9d0e6Sgerardnico         * For each processed bar in the page
1338aa9d0e6Sgerardnico         *   * retrieve the snippets from the cache or store the process one
1348aa9d0e6Sgerardnico         *   * add the cache information in meta
1355f891b7eSNickeau         */
136*c3437056SNickeau        $slots = $cacheManager->getXhtmlCacheSlotResultsForRequestedPage();
13737748cd8SNickeau        foreach ($slots as $slotId => $servedFromCache) {
1388aa9d0e6Sgerardnico
139*c3437056SNickeau            /**
140*c3437056SNickeau             * The local file location of the slot
141*c3437056SNickeau             */
142*c3437056SNickeau            $slotLocalFilePath = DokuPath::createPagePathFromId($slotId)
143*c3437056SNickeau                ->toLocalPath()
144*c3437056SNickeau                ->toAbsolutePath()
145*c3437056SNickeau                ->toString();
1468aa9d0e6Sgerardnico
147*c3437056SNickeau            /**
148*c3437056SNickeau             * Using a cache parser, set the page id and will trigger
149*c3437056SNickeau             * the parser cache use event in order to log/report the cache usage
150*c3437056SNickeau             * At {@link action_plugin_combo_cache::logCacheUsage()}
151*c3437056SNickeau             */
152*c3437056SNickeau            $cache = new CacheParser($slotId, $slotLocalFilePath, "snippet.json");
153*c3437056SNickeau            $cache->setEvent('PARSER_CACHE_USE'); // cache parser use already this event, just FYI
154654a02feSgerardnico            $dependencies = array(
155654a02feSgerardnico                "files" => [
156*c3437056SNickeau                    $slotLocalFilePath,
157654a02feSgerardnico                    Resources::getComboHome() . "/plugin.info.txt"
158654a02feSgerardnico                ]
159654a02feSgerardnico            );
1608aa9d0e6Sgerardnico
1618aa9d0e6Sgerardnico            // if the bar was served from the cache
162654a02feSgerardnico            if ($servedFromCache && $cache->useCache($dependencies)) {
1638aa9d0e6Sgerardnico
16421913ab3SNickeau                // Retrieve snippets from previous run
1655f891b7eSNickeau                $data = $cache->retrieveCache();
1665f891b7eSNickeau                if (!empty($data)) {
1678aa9d0e6Sgerardnico
168*c3437056SNickeau                    $jsonDecodeSnippets = json_decode($data, true);
169*c3437056SNickeau                    $nativeSnippets = [];
170*c3437056SNickeau                    foreach ($jsonDecodeSnippets as $type => $snippets) {
171*c3437056SNickeau                        foreach ($snippets as $snippetId => $snippetArray) {
172*c3437056SNickeau                            try {
173*c3437056SNickeau                                $nativeSnippets[$type][$snippetId] = Snippet::createFromJson($snippetArray);
174*c3437056SNickeau                            } catch (ExceptionCombo $e) {
175*c3437056SNickeau                                LogUtility::msg("The snippet json array cannot be build into a snippet object. " . $e->getMessage());
1765f891b7eSNickeau                            }
177*c3437056SNickeau                        }
178*c3437056SNickeau                    }
179*c3437056SNickeau                    $snippetManager->addSnippetsFromCacheForBar($slotId, $nativeSnippets);
180d2ffcff9Sgerardnico
1818aa9d0e6Sgerardnico                }
182*c3437056SNickeau
1838aa9d0e6Sgerardnico            } else {
184*c3437056SNickeau                $jsonDecodeSnippets = $snippetManager->getSnippetsForBar($slotId);
185*c3437056SNickeau                if ($jsonDecodeSnippets !== null) {
186*c3437056SNickeau                    $data1 = json_encode($jsonDecodeSnippets);
187*c3437056SNickeau                    $cache->storeCache($data1);
1888aa9d0e6Sgerardnico                }
1898aa9d0e6Sgerardnico            }
1905f891b7eSNickeau
1918aa9d0e6Sgerardnico        }
1925f891b7eSNickeau
1935f891b7eSNickeau        /**
19421913ab3SNickeau         * Snippets
1955f891b7eSNickeau         */
196*c3437056SNickeau        $allSnippets = $snippetManager->getSnippets();
197*c3437056SNickeau        foreach ($allSnippets as $tagType => $tags) {
19821913ab3SNickeau
19921913ab3SNickeau            foreach ($tags as $tag) {
20021913ab3SNickeau                $event->data[$tagType][] = $tag;
2015f891b7eSNickeau            }
2025f891b7eSNickeau
2035f891b7eSNickeau        }
2045f891b7eSNickeau
2055f891b7eSNickeau        $snippetManager->close();
2065f891b7eSNickeau
2075f891b7eSNickeau    }
2085f891b7eSNickeau
2095f891b7eSNickeau    /**
2105f891b7eSNickeau     * Used if the template does not run the content
2115f891b7eSNickeau     * before the calling of the header as strap does.
2125f891b7eSNickeau     *
2135f891b7eSNickeau     * In this case, the {@link \ComboStrap\SnippetManager::close()} has
2145f891b7eSNickeau     * not run, and the snippets are still in memory.
2155f891b7eSNickeau     *
2165f891b7eSNickeau     * We store them in the HTML and they
2175f891b7eSNickeau     * follows then the HTML cache of DokuWiki
2185f891b7eSNickeau     * @param $event
2195f891b7eSNickeau     */
2205f891b7eSNickeau    function componentSnippetContent($event)
2215f891b7eSNickeau    {
2225f891b7eSNickeau
223531e725cSNickeau        $format = $event->data[0];
224531e725cSNickeau        if ($format !== "xhtml") {
225531e725cSNickeau            return;
226531e725cSNickeau        }
2275f891b7eSNickeau
2285f891b7eSNickeau        /**
2295f891b7eSNickeau         * Run only if the header output was already called
2305f891b7eSNickeau         */
2315f891b7eSNickeau        if ($this->headerOutputWasCalled) {
2325f891b7eSNickeau
2335f891b7eSNickeau            $snippetManager = PluginUtility::getSnippetManager();
2345f891b7eSNickeau
235531e725cSNickeau            $xhtmlContent = &$event->data[1];
236531e725cSNickeau            $snippets = $snippetManager->getSnippets();
237531e725cSNickeau            foreach ($snippets as $tagType => $tags) {
23821913ab3SNickeau
23921913ab3SNickeau                foreach ($tags as $tag) {
240531e725cSNickeau                    $xhtmlContent .= DOKU_LF . "<$tagType";
24121913ab3SNickeau                    $attributes = "";
24221913ab3SNickeau                    $content = null;
24321913ab3SNickeau                    foreach ($tag as $attributeName => $attributeValue) {
2445f891b7eSNickeau                        if ($attributeName != "_data") {
24521913ab3SNickeau                            $attributes .= " $attributeName=\"$attributeValue\"";
2465f891b7eSNickeau                        } else {
2475f891b7eSNickeau                            $content = $attributeValue;
2485f891b7eSNickeau                        }
2495f891b7eSNickeau                    }
250531e725cSNickeau                    $xhtmlContent .= "$attributes>";
2515f891b7eSNickeau                    if (!empty($content)) {
252531e725cSNickeau                        $xhtmlContent .= $content;
2535f891b7eSNickeau                    }
254531e725cSNickeau                    $xhtmlContent .= "</$tagType>" . DOKU_LF;
2555f891b7eSNickeau                }
2565f891b7eSNickeau
2575f891b7eSNickeau            }
2585f891b7eSNickeau
2595f891b7eSNickeau            $snippetManager->close();
2605f891b7eSNickeau
2615f891b7eSNickeau        }
2625f891b7eSNickeau
2635f891b7eSNickeau    }
2645f891b7eSNickeau
2658aa9d0e6Sgerardnico
2665f891b7eSNickeau}
267