15f891b7eSNickeau<?php 25f891b7eSNickeau 3654a02feSgerardnicouse ComboStrap\DokuPath; 45f891b7eSNickeauuse ComboStrap\LogUtility; 55f891b7eSNickeauuse ComboStrap\PluginUtility; 6654a02feSgerardnicouse ComboStrap\Resources; 78aa9d0e6Sgerardnicouse ComboStrap\Site; 88aa9d0e6Sgerardnicouse dokuwiki\Cache\CacheRenderer; 95f891b7eSNickeau 105f891b7eSNickeauif (!defined('DOKU_INC')) die(); 115f891b7eSNickeau 125f891b7eSNickeau/** 135f891b7eSNickeau * 145f891b7eSNickeau * 155f891b7eSNickeau * Add the snippet needed by the components 165f891b7eSNickeau * 175f891b7eSNickeau */ 185f891b7eSNickeauclass action_plugin_combo_snippets extends DokuWiki_Action_Plugin 195f891b7eSNickeau{ 205f891b7eSNickeau 218aa9d0e6Sgerardnico const COMBO_CACHE_PREFIX = "combo:cache:"; 225f891b7eSNickeau 235f891b7eSNickeau /** 245f891b7eSNickeau * @var bool - to trace if the header output was called 255f891b7eSNickeau */ 265f891b7eSNickeau private $headerOutputWasCalled = false; 275f891b7eSNickeau 285f891b7eSNickeau function __construct() 295f891b7eSNickeau { 305f891b7eSNickeau // enable direct access to language strings 315f891b7eSNickeau // ie $this->lang 325f891b7eSNickeau $this->setupLocale(); 335f891b7eSNickeau } 345f891b7eSNickeau 355f891b7eSNickeau public function register(Doku_Event_Handler $controller) 365f891b7eSNickeau { 378aa9d0e6Sgerardnico 3821913ab3SNickeau /** 3921913ab3SNickeau * To add the snippets in the header 4021913ab3SNickeau */ 415f891b7eSNickeau $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'componentSnippetHead', array()); 4221913ab3SNickeau 4321913ab3SNickeau /** 4421913ab3SNickeau * To add the snippets in the content 4521913ab3SNickeau * if they have not been added to the header 46531e725cSNickeau * 47531e725cSNickeau * Not https://www.dokuwiki.org/devel:event:tpl_content_display TPL_ACT_RENDER 48531e725cSNickeau * or https://www.dokuwiki.org/devel:event:tpl_act_render 49531e725cSNickeau * because it works only for the main content 50531e725cSNickeau * in {@link tpl_content()} 51531e725cSNickeau * 52531e725cSNickeau * We use 53531e725cSNickeau * https://www.dokuwiki.org/devel:event:renderer_content_postprocess 54531e725cSNickeau * that is in {@link p_render()} and takes into account also the slot page. 5521913ab3SNickeau */ 56531e725cSNickeau $controller->register_hook('RENDERER_CONTENT_POSTPROCESS', 'AFTER', $this, 'componentSnippetContent', array()); 578aa9d0e6Sgerardnico 5821913ab3SNickeau /** 5921913ab3SNickeau * To reset the value 6021913ab3SNickeau */ 6121913ab3SNickeau $controller->register_hook('DOKUWIKI_DONE', 'BEFORE', $this, 'close', array()); 628aa9d0e6Sgerardnico 6321913ab3SNickeau 6421913ab3SNickeau /** 6521913ab3SNickeau * To log the cache used by bar 6621913ab3SNickeau */ 678aa9d0e6Sgerardnico $controller->register_hook('PARSER_CACHE_USE', 'AFTER', $this, 'barParsed', array()); 688aa9d0e6Sgerardnico 695f891b7eSNickeau } 705f891b7eSNickeau 715f891b7eSNickeau /** 7232b85071SNickeau * Reset variable 7332b85071SNickeau * Otherwise in test, when we call it two times, it just fail 7432b85071SNickeau */ 7521913ab3SNickeau function close() 7621913ab3SNickeau { 7732b85071SNickeau 7832b85071SNickeau $this->headerOutputWasCalled = false; 7932b85071SNickeau 8032b85071SNickeau /** 8132b85071SNickeau * Fighting the fact that in 7.2, 8232b85071SNickeau * there is still a cache 8332b85071SNickeau */ 8432b85071SNickeau PluginUtility::initSnippetManager(); 8532b85071SNickeau 8632b85071SNickeau } 8732b85071SNickeau 8832b85071SNickeau /** 895f891b7eSNickeau * Dokuwiki has already a canonical methodology 905f891b7eSNickeau * https://www.dokuwiki.org/canonical 915f891b7eSNickeau * 925f891b7eSNickeau * @param $event 935f891b7eSNickeau */ 945f891b7eSNickeau function componentSnippetHead($event) 955f891b7eSNickeau { 965f891b7eSNickeau 975f891b7eSNickeau 985f891b7eSNickeau global $ID; 995f891b7eSNickeau if (empty($ID)) { 100*e8b2ff59SNickeau 10121913ab3SNickeau global $_SERVER; 102*e8b2ff59SNickeau $scriptName = $_SERVER['SCRIPT_NAME']; 103*e8b2ff59SNickeau 104*e8b2ff59SNickeau /** 105*e8b2ff59SNickeau * If this is an ajax call, return 106*e8b2ff59SNickeau * only if this not from webcode 107*e8b2ff59SNickeau */ 108*e8b2ff59SNickeau if (strpos($scriptName, "/lib/exe/ajax.php") !== false) { 10921913ab3SNickeau global $_REQUEST; 11021913ab3SNickeau $call = $_REQUEST['call']; 11121913ab3SNickeau if ($call != action_plugin_combo_webcode::CALL_ID) { 1125f891b7eSNickeau return; 1135f891b7eSNickeau } 114*e8b2ff59SNickeau } else if (!(strpos($scriptName, "/lib/exe/detail.php") !== false)) { 115*e8b2ff59SNickeau /** 116*e8b2ff59SNickeau * Image page has an header and footer that may needs snippet 117*e8b2ff59SNickeau * We return only if this is not a image/detail page 118*e8b2ff59SNickeau */ 119*e8b2ff59SNickeau return; 12021913ab3SNickeau } 12121913ab3SNickeau } 1225f891b7eSNickeau 1235f891b7eSNickeau /** 1245f891b7eSNickeau * Advertise that the header output was called 1255f891b7eSNickeau * If the user is using another template 1265f891b7eSNickeau * than strap that does not put the component snippet 1275f891b7eSNickeau * in the head 1285f891b7eSNickeau * Used in 1295f891b7eSNickeau */ 1305f891b7eSNickeau $this->headerOutputWasCalled = true; 1315f891b7eSNickeau 1325f891b7eSNickeau $snippetManager = PluginUtility::getSnippetManager(); 1335f891b7eSNickeau 1345f891b7eSNickeau /** 1358aa9d0e6Sgerardnico * For each processed bar in the page 1368aa9d0e6Sgerardnico * * retrieve the snippets from the cache or store the process one 1378aa9d0e6Sgerardnico * * add the cache information in meta 1385f891b7eSNickeau */ 1398aa9d0e6Sgerardnico $bars = $snippetManager->getBarsOfPage(); 140654a02feSgerardnico foreach ($bars as $barId => $servedFromCache) { 1418aa9d0e6Sgerardnico 14221913ab3SNickeau // Add cache information into the head meta 143e957c58cSgerardnico // to test 144654a02feSgerardnico $event->data["meta"][] = array("name" => self::COMBO_CACHE_PREFIX . $barId, "content" => var_export($servedFromCache, true)); 1458aa9d0e6Sgerardnico 1468aa9d0e6Sgerardnico // Get or store the data 147654a02feSgerardnico $cache = new \dokuwiki\Cache\Cache($barId, "snippet"); 14885e82846SNickeau $barFileSystemPath = DokuPath::createPagePathFromPath(DokuPath::PATH_SEPARATOR . $barId)->getFileSystemPath(); 149654a02feSgerardnico $dependencies = array( 150654a02feSgerardnico "files" => [ 151654a02feSgerardnico $barFileSystemPath, 152654a02feSgerardnico Resources::getComboHome() . "/plugin.info.txt" 153654a02feSgerardnico ] 154654a02feSgerardnico ); 1558aa9d0e6Sgerardnico 1568aa9d0e6Sgerardnico // if the bar was served from the cache 157654a02feSgerardnico if ($servedFromCache && $cache->useCache($dependencies)) { 1588aa9d0e6Sgerardnico 15921913ab3SNickeau // Retrieve snippets from previous run 1605f891b7eSNickeau $data = $cache->retrieveCache(); 1618aa9d0e6Sgerardnico 1625f891b7eSNickeau if (!empty($data)) { 1638aa9d0e6Sgerardnico $snippets = unserialize($data); 164654a02feSgerardnico $snippetManager->addSnippetsFromCacheForBar($barId, $snippets); 1658aa9d0e6Sgerardnico 1668aa9d0e6Sgerardnico if (Site::debugIsOn()) { 1678aa9d0e6Sgerardnico LogUtility::log2file("Snippet cache file {$cache->cache} used", LogUtility::LVL_MSG_DEBUG); 1688aa9d0e6Sgerardnico $event->data['script'][] = array( 1698aa9d0e6Sgerardnico "type" => "application/json", 1708aa9d0e6Sgerardnico "_data" => json_encode($snippets), 171654a02feSgerardnico "class" => "combo-snippet-cache-" . str_replace(":", "-", $barId)); 1725f891b7eSNickeau } 173d2ffcff9Sgerardnico 1748aa9d0e6Sgerardnico } 1758aa9d0e6Sgerardnico } else { 176654a02feSgerardnico $snippets = $snippetManager->getSnippetsForBar($barId); 1778aa9d0e6Sgerardnico if (!empty($snippets)) { 1788aa9d0e6Sgerardnico $cache->storeCache(serialize($snippets)); 1798aa9d0e6Sgerardnico } 1808aa9d0e6Sgerardnico } 1815f891b7eSNickeau 1828aa9d0e6Sgerardnico } 1835f891b7eSNickeau 1845f891b7eSNickeau /** 18521913ab3SNickeau * Snippets 1865f891b7eSNickeau */ 18721913ab3SNickeau foreach ($snippetManager->getSnippets() as $tagType => $tags) { 18821913ab3SNickeau 18921913ab3SNickeau foreach ($tags as $tag) { 19021913ab3SNickeau $event->data[$tagType][] = $tag; 1915f891b7eSNickeau } 1925f891b7eSNickeau 1935f891b7eSNickeau } 1945f891b7eSNickeau 1955f891b7eSNickeau 1965f891b7eSNickeau $snippetManager->close(); 1975f891b7eSNickeau 1985f891b7eSNickeau } 1995f891b7eSNickeau 2005f891b7eSNickeau /** 2015f891b7eSNickeau * Used if the template does not run the content 2025f891b7eSNickeau * before the calling of the header as strap does. 2035f891b7eSNickeau * 2045f891b7eSNickeau * In this case, the {@link \ComboStrap\SnippetManager::close()} has 2055f891b7eSNickeau * not run, and the snippets are still in memory. 2065f891b7eSNickeau * 2075f891b7eSNickeau * We store them in the HTML and they 2085f891b7eSNickeau * follows then the HTML cache of DokuWiki 2095f891b7eSNickeau * @param $event 2105f891b7eSNickeau */ 2115f891b7eSNickeau function componentSnippetContent($event) 2125f891b7eSNickeau { 2135f891b7eSNickeau 214531e725cSNickeau $format = $event->data[0]; 215531e725cSNickeau if ($format !== "xhtml") { 216531e725cSNickeau return; 217531e725cSNickeau } 2185f891b7eSNickeau 2195f891b7eSNickeau /** 2205f891b7eSNickeau * Run only if the header output was already called 2215f891b7eSNickeau */ 2225f891b7eSNickeau if ($this->headerOutputWasCalled) { 2235f891b7eSNickeau 2245f891b7eSNickeau $snippetManager = PluginUtility::getSnippetManager(); 2255f891b7eSNickeau 226531e725cSNickeau $xhtmlContent = &$event->data[1]; 227531e725cSNickeau $snippets = $snippetManager->getSnippets(); 228531e725cSNickeau foreach ($snippets as $tagType => $tags) { 22921913ab3SNickeau 23021913ab3SNickeau foreach ($tags as $tag) { 231531e725cSNickeau $xhtmlContent .= DOKU_LF . "<$tagType"; 23221913ab3SNickeau $attributes = ""; 23321913ab3SNickeau $content = null; 23421913ab3SNickeau foreach ($tag as $attributeName => $attributeValue) { 2355f891b7eSNickeau if ($attributeName != "_data") { 23621913ab3SNickeau $attributes .= " $attributeName=\"$attributeValue\""; 2375f891b7eSNickeau } else { 2385f891b7eSNickeau $content = $attributeValue; 2395f891b7eSNickeau } 2405f891b7eSNickeau } 241531e725cSNickeau $xhtmlContent .= "$attributes>"; 2425f891b7eSNickeau if (!empty($content)) { 243531e725cSNickeau $xhtmlContent .= $content; 2445f891b7eSNickeau } 245531e725cSNickeau $xhtmlContent .= "</$tagType>" . DOKU_LF; 2465f891b7eSNickeau } 2475f891b7eSNickeau 2485f891b7eSNickeau } 2495f891b7eSNickeau 2505f891b7eSNickeau $snippetManager->close(); 2515f891b7eSNickeau 2525f891b7eSNickeau } 2535f891b7eSNickeau 2545f891b7eSNickeau } 2555f891b7eSNickeau 2568aa9d0e6Sgerardnico 2575f891b7eSNickeau /** 2588aa9d0e6Sgerardnico * 2598aa9d0e6Sgerardnico * @param $event 2605f891b7eSNickeau */ 2618aa9d0e6Sgerardnico function barParsed($event) 2625f891b7eSNickeau { 2638aa9d0e6Sgerardnico $data = $event->data; 2648aa9d0e6Sgerardnico if ($data->mode == "xhtml") { 2655f891b7eSNickeau 2668aa9d0e6Sgerardnico /* @var CacheRenderer $data */ 267654a02feSgerardnico $pageId = $data->page; 2688aa9d0e6Sgerardnico $cached = $event->result; 269654a02feSgerardnico PluginUtility::getSnippetManager()->addBar($pageId, $cached); 2705f891b7eSNickeau 2715f891b7eSNickeau } 2725f891b7eSNickeau 2738aa9d0e6Sgerardnico 2748aa9d0e6Sgerardnico } 2755f891b7eSNickeau 2765f891b7eSNickeau 2775f891b7eSNickeau} 278