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