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