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