1*04fd306cSNickeau<?php 2*04fd306cSNickeau 3*04fd306cSNickeaunamespace ComboStrap; 4*04fd306cSNickeau 5*04fd306cSNickeauuse dokuwiki\Cache\CacheInstructions; 6*04fd306cSNickeauuse dokuwiki\Cache\CacheParser; 7*04fd306cSNickeauuse dokuwiki\Cache\CacheRenderer; 8*04fd306cSNickeau 9*04fd306cSNickeau/** 10*04fd306cSNickeau * Builder class for {@link FetcherMarkup} 11*04fd306cSNickeau * Php does not allow for nested class 12*04fd306cSNickeau * We therefore need to get the builder class out. 13*04fd306cSNickeau * 14*04fd306cSNickeau * We extends just to get access to protected members class 15*04fd306cSNickeau * and to mimic a builder pattern 16*04fd306cSNickeau * 17*04fd306cSNickeau * @internal 18*04fd306cSNickeau */ 19*04fd306cSNickeauclass FetcherMarkupBuilder 20*04fd306cSNickeau{ 21*04fd306cSNickeau 22*04fd306cSNickeau /** 23*04fd306cSNickeau * Private are they may be null 24*04fd306cSNickeau */ 25*04fd306cSNickeau private ?string $builderMarkupString = null; 26*04fd306cSNickeau private ?Path $builderMarkupSourcePath = null; 27*04fd306cSNickeau private ?array $builderRequestedInstructions = null; 28*04fd306cSNickeau 29*04fd306cSNickeau protected WikiPath $requestedContextPath; 30*04fd306cSNickeau protected Mime $mime; 31*04fd306cSNickeau protected bool $deleteRootBlockElement = false; 32*04fd306cSNickeau protected string $rendererName; 33*04fd306cSNickeau 34*04fd306cSNickeau 35*04fd306cSNickeau protected bool $isDoc; 36*04fd306cSNickeau protected array $builderContextData; 37*04fd306cSNickeau private bool $isCodeStandAloneExecution = false; 38*04fd306cSNickeau /** 39*04fd306cSNickeau * @var FetcherMarkup - a parent if any 40*04fd306cSNickeau */ 41*04fd306cSNickeau private FetcherMarkup $parentMarkupHandler; 42*04fd306cSNickeau 43*04fd306cSNickeau 44*04fd306cSNickeau public function __construct() 45*04fd306cSNickeau { 46*04fd306cSNickeau } 47*04fd306cSNickeau 48*04fd306cSNickeau /** 49*04fd306cSNickeau * The local path is part of the key cache and should be the same 50*04fd306cSNickeau * than dokuwiki 51*04fd306cSNickeau * 52*04fd306cSNickeau * For whatever reason, Dokuwiki uses: 53*04fd306cSNickeau * * `/` as separator on Windows 54*04fd306cSNickeau * * and Windows short path `GERARD~1` not gerardnico 55*04fd306cSNickeau * See {@link wikiFN()} 56*04fd306cSNickeau * There is also a cache in the function 57*04fd306cSNickeau * 58*04fd306cSNickeau * We can't use our {@link Path} class to be compatible because the 59*04fd306cSNickeau * path is on windows format without the short path format 60*04fd306cSNickeau */ 61*04fd306cSNickeau public static function getWikiIdAndLocalFileDokuwikiCompliant(Path $sourcePath): array 62*04fd306cSNickeau { 63*04fd306cSNickeau 64*04fd306cSNickeau try { 65*04fd306cSNickeau $markuSourceWikiPath = $sourcePath->toWikiPath(); 66*04fd306cSNickeau 67*04fd306cSNickeau if ($markuSourceWikiPath->getDrive() === WikiPath::MARKUP_DRIVE) { 68*04fd306cSNickeau /** 69*04fd306cSNickeau * Dokuwiki special function 70*04fd306cSNickeau * that should be the same to conform to the cache key 71*04fd306cSNickeau */ 72*04fd306cSNickeau $wikiId = $markuSourceWikiPath->getWikiId(); 73*04fd306cSNickeau $localFile = wikiFN($wikiId); 74*04fd306cSNickeau } else { 75*04fd306cSNickeau $localFile = $markuSourceWikiPath->toLocalPath(); 76*04fd306cSNickeau $wikiId = $markuSourceWikiPath->toUriString(); 77*04fd306cSNickeau } 78*04fd306cSNickeau } catch (ExceptionCast $e) { 79*04fd306cSNickeau $wikiId = $sourcePath->toAbsoluteId(); 80*04fd306cSNickeau try { 81*04fd306cSNickeau $localFile = $sourcePath->toLocalPath(); 82*04fd306cSNickeau } catch (ExceptionCast $e) { 83*04fd306cSNickeau throw new ExceptionRuntimeInternal("The source path ({$sourcePath}) is not supported as markup source path.", $e); 84*04fd306cSNickeau } 85*04fd306cSNickeau } 86*04fd306cSNickeau return [$wikiId, $localFile]; 87*04fd306cSNickeau } 88*04fd306cSNickeau 89*04fd306cSNickeau /** 90*04fd306cSNickeau * @param string $markupString - the markup is a string format 91*04fd306cSNickeau * @return FetcherMarkupBuilder 92*04fd306cSNickeau */ 93*04fd306cSNickeau public function setRequestedMarkupString(string $markupString): FetcherMarkupBuilder 94*04fd306cSNickeau { 95*04fd306cSNickeau $this->builderMarkupString = $markupString; 96*04fd306cSNickeau return $this; 97*04fd306cSNickeau } 98*04fd306cSNickeau 99*04fd306cSNickeau /** 100*04fd306cSNickeau * Delete the first P instructions 101*04fd306cSNickeau * (The parser will add a p block element) 102*04fd306cSNickeau * @param bool $b 103*04fd306cSNickeau * @return $this 104*04fd306cSNickeau */ 105*04fd306cSNickeau public function setDeleteRootBlockElement(bool $b): FetcherMarkupBuilder 106*04fd306cSNickeau { 107*04fd306cSNickeau $this->deleteRootBlockElement = $b; 108*04fd306cSNickeau return $this; 109*04fd306cSNickeau } 110*04fd306cSNickeau 111*04fd306cSNickeau /** 112*04fd306cSNickeau * The source where the markup is stored (null if dynamic) 113*04fd306cSNickeau * It's a duplicate of {@link FetcherMarkup::setSourcePath()} 114*04fd306cSNickeau * @param ?Path $executingPath 115*04fd306cSNickeau * @return $this 116*04fd306cSNickeau */ 117*04fd306cSNickeau public function setRequestedExecutingPath(?Path $executingPath): FetcherMarkupBuilder 118*04fd306cSNickeau { 119*04fd306cSNickeau 120*04fd306cSNickeau if ($executingPath == null) { 121*04fd306cSNickeau return $this; 122*04fd306cSNickeau } 123*04fd306cSNickeau 124*04fd306cSNickeau try { 125*04fd306cSNickeau /** 126*04fd306cSNickeau * Normalize to wiki path if possible 127*04fd306cSNickeau * Why ? 128*04fd306cSNickeau * Because the parent path may be used a {@link MarkupCacheDependencies::getValueForKey() cache key} 129*04fd306cSNickeau * and they will have different value if the path type is different 130*04fd306cSNickeau * * With {@link LocalPath Local Path}: `C:\Users\gerardnico\AppData\Local\Temp\dwtests-1676386702.9751\data\pages\ns_without_scope` 131*04fd306cSNickeau * * With {@link WikiPath Wiki Path}: `ns_without_scope` 132*04fd306cSNickeau * It will then make the cache file path different (ie the md5 output key is the file name) 133*04fd306cSNickeau */ 134*04fd306cSNickeau $this->builderMarkupSourcePath = $executingPath->toWikiPath(); 135*04fd306cSNickeau } catch (ExceptionCast $e) { 136*04fd306cSNickeau $this->builderMarkupSourcePath = $executingPath; 137*04fd306cSNickeau } 138*04fd306cSNickeau return $this; 139*04fd306cSNickeau 140*04fd306cSNickeau } 141*04fd306cSNickeau 142*04fd306cSNickeau /** 143*04fd306cSNickeau * The page context in which this fragment was requested 144*04fd306cSNickeau * 145*04fd306cSNickeau * Note that it may or may be not the main requested markup page. 146*04fd306cSNickeau * You can have a markup rendering inside another markup rendering. 147*04fd306cSNickeau * 148*04fd306cSNickeau * @param WikiPath $contextPath 149*04fd306cSNickeau * @return $this 150*04fd306cSNickeau */ 151*04fd306cSNickeau public function setRequestedContextPath(WikiPath $contextPath): FetcherMarkupBuilder 152*04fd306cSNickeau { 153*04fd306cSNickeau $this->requestedContextPath = $contextPath; 154*04fd306cSNickeau return $this; 155*04fd306cSNickeau } 156*04fd306cSNickeau 157*04fd306cSNickeau /** 158*04fd306cSNickeau */ 159*04fd306cSNickeau public function setRequestedMime(Mime $mime): FetcherMarkupBuilder 160*04fd306cSNickeau { 161*04fd306cSNickeau $this->mime = $mime; 162*04fd306cSNickeau return $this; 163*04fd306cSNickeau } 164*04fd306cSNickeau 165*04fd306cSNickeau public function setRequestedMimeToXhtml(): FetcherMarkupBuilder 166*04fd306cSNickeau { 167*04fd306cSNickeau try { 168*04fd306cSNickeau return $this->setRequestedMime(Mime::createFromExtension("xhtml")); 169*04fd306cSNickeau } catch (ExceptionNotFound $e) { 170*04fd306cSNickeau throw new ExceptionRuntime("Internal error", 0, $e); 171*04fd306cSNickeau } 172*04fd306cSNickeau 173*04fd306cSNickeau } 174*04fd306cSNickeau 175*04fd306cSNickeau 176*04fd306cSNickeau /** 177*04fd306cSNickeau * Technically, you could set the mime to whatever you want 178*04fd306cSNickeau * and still get the instructions via {@link FetcherMarkup::getInstructions()} 179*04fd306cSNickeau * Setting the mime to instructions will just not do any render processing. 180*04fd306cSNickeau * @return $this 181*04fd306cSNickeau */ 182*04fd306cSNickeau public function setRequestedMimeToInstructions(): FetcherMarkupBuilder 183*04fd306cSNickeau { 184*04fd306cSNickeau try { 185*04fd306cSNickeau $this->setRequestedMime(Mime::createFromExtension(MarkupRenderer::INSTRUCTION_EXTENSION)); 186*04fd306cSNickeau } catch (ExceptionNotFound $e) { 187*04fd306cSNickeau throw new ExceptionRuntime("Internal error: the mime is internal and should be good"); 188*04fd306cSNickeau } 189*04fd306cSNickeau return $this; 190*04fd306cSNickeau 191*04fd306cSNickeau } 192*04fd306cSNickeau 193*04fd306cSNickeau 194*04fd306cSNickeau /** 195*04fd306cSNickeau * @throws ExceptionNotExists 196*04fd306cSNickeau */ 197*04fd306cSNickeau public function build(): FetcherMarkup 198*04fd306cSNickeau { 199*04fd306cSNickeau 200*04fd306cSNickeau /** 201*04fd306cSNickeau * One input should be given 202*04fd306cSNickeau */ 203*04fd306cSNickeau if ($this->builderMarkupSourcePath === null && $this->builderMarkupString === null && $this->builderRequestedInstructions === null) { 204*04fd306cSNickeau throw new ExceptionRuntimeInternal("A markup source path, a markup string or instructions should be given"); 205*04fd306cSNickeau } 206*04fd306cSNickeau /** 207*04fd306cSNickeau * Only one input should be given 208*04fd306cSNickeau */ 209*04fd306cSNickeau $foundInput = ""; 210*04fd306cSNickeau if ($this->builderMarkupSourcePath !== null) { 211*04fd306cSNickeau $foundInput = "markup path"; 212*04fd306cSNickeau } 213*04fd306cSNickeau if ($this->builderMarkupString !== null) { 214*04fd306cSNickeau if (!empty($foundInput)) { 215*04fd306cSNickeau throw new ExceptionRuntimeInternal("Only one input should be given, we have found 2 inputs ($foundInput and markup string)"); 216*04fd306cSNickeau } 217*04fd306cSNickeau $foundInput = "markup string"; 218*04fd306cSNickeau 219*04fd306cSNickeau } 220*04fd306cSNickeau if ($this->builderRequestedInstructions !== null) { 221*04fd306cSNickeau if (!empty($foundInput)) { 222*04fd306cSNickeau throw new ExceptionRuntimeInternal("Only one input should be given, we have found 2 inputs ($foundInput and instructions)"); 223*04fd306cSNickeau } 224*04fd306cSNickeau } 225*04fd306cSNickeau 226*04fd306cSNickeau /** 227*04fd306cSNickeau * Other Mandatory 228*04fd306cSNickeau */ 229*04fd306cSNickeau if (!isset($this->mime)) { 230*04fd306cSNickeau throw new ExceptionRuntimeInternal("A mime is mandatory"); 231*04fd306cSNickeau } 232*04fd306cSNickeau if (!isset($this->requestedContextPath)) { 233*04fd306cSNickeau throw new ExceptionRuntimeInternal("A context path is mandatory"); 234*04fd306cSNickeau } 235*04fd306cSNickeau 236*04fd306cSNickeau /** 237*04fd306cSNickeau * The object type is mandatory 238*04fd306cSNickeau */ 239*04fd306cSNickeau if (!isset($this->rendererName)) { 240*04fd306cSNickeau switch ($this->mime->toString()) { 241*04fd306cSNickeau case Mime::XHTML: 242*04fd306cSNickeau /** 243*04fd306cSNickeau * ie last name of {@link \Doku_Renderer_xhtml} 244*04fd306cSNickeau */ 245*04fd306cSNickeau $rendererName = MarkupRenderer::XHTML_RENDERER; 246*04fd306cSNickeau break; 247*04fd306cSNickeau case Mime::META: 248*04fd306cSNickeau /** 249*04fd306cSNickeau * ie last name of {@link \Doku_Renderer_metadata} 250*04fd306cSNickeau */ 251*04fd306cSNickeau $rendererName = "metadata"; 252*04fd306cSNickeau break; 253*04fd306cSNickeau case Mime::INSTRUCTIONS: 254*04fd306cSNickeau /** 255*04fd306cSNickeau * Does not exist yet bu that the future 256*04fd306cSNickeau */ 257*04fd306cSNickeau $rendererName = FetcherMarkupInstructions::NAME; 258*04fd306cSNickeau break; 259*04fd306cSNickeau default: 260*04fd306cSNickeau throw new ExceptionRuntimeInternal("A renderer name (ie builder name/output object type) is mandatory"); 261*04fd306cSNickeau } 262*04fd306cSNickeau } else { 263*04fd306cSNickeau $rendererName = $this->rendererName; 264*04fd306cSNickeau } 265*04fd306cSNickeau 266*04fd306cSNickeau /** 267*04fd306cSNickeau * Building 268*04fd306cSNickeau */ 269*04fd306cSNickeau $newFetcherMarkup = new FetcherMarkup(); 270*04fd306cSNickeau $newFetcherMarkup->builderName = $rendererName; 271*04fd306cSNickeau 272*04fd306cSNickeau $newFetcherMarkup->requestedContextPath = $this->requestedContextPath; 273*04fd306cSNickeau if ($this->builderMarkupString !== null) { 274*04fd306cSNickeau $newFetcherMarkup->markupString = $this->builderMarkupString; 275*04fd306cSNickeau } 276*04fd306cSNickeau if ($this->builderMarkupSourcePath !== null) { 277*04fd306cSNickeau $newFetcherMarkup->markupSourcePath = $this->builderMarkupSourcePath; 278*04fd306cSNickeau if (!FileSystems::exists($this->builderMarkupSourcePath)) { 279*04fd306cSNickeau /** 280*04fd306cSNickeau * Too much edge case for now with dokuwiki 281*04fd306cSNickeau * The {@link \Doku_Renderer_metadata} for instance throws an error if the file does not exist 282*04fd306cSNickeau * ... etc .... 283*04fd306cSNickeau */ 284*04fd306cSNickeau throw new ExceptionNotExists("The executing source file ({$this->builderMarkupSourcePath}) does not exist"); 285*04fd306cSNickeau } 286*04fd306cSNickeau } 287*04fd306cSNickeau if ($this->builderRequestedInstructions !== null) { 288*04fd306cSNickeau $newFetcherMarkup->requestedInstructions = $this->builderRequestedInstructions; 289*04fd306cSNickeau } 290*04fd306cSNickeau $newFetcherMarkup->mime = $this->mime; 291*04fd306cSNickeau $newFetcherMarkup->deleteRootBlockElement = $this->deleteRootBlockElement; 292*04fd306cSNickeau 293*04fd306cSNickeau 294*04fd306cSNickeau $newFetcherMarkup->isDoc = $this->getIsDocumentExecution(); 295*04fd306cSNickeau if (isset($this->builderContextData)) { 296*04fd306cSNickeau $newFetcherMarkup->contextData = $this->builderContextData; 297*04fd306cSNickeau } 298*04fd306cSNickeau 299*04fd306cSNickeau if (isset($this->parentMarkupHandler)) { 300*04fd306cSNickeau $newFetcherMarkup->parentMarkupHandler = $this->parentMarkupHandler; 301*04fd306cSNickeau } 302*04fd306cSNickeau $newFetcherMarkup->isNonPathStandaloneExecution = $this->isCodeStandAloneExecution; 303*04fd306cSNickeau 304*04fd306cSNickeau 305*04fd306cSNickeau /** 306*04fd306cSNickeau * We build the cache dependencies even if there is no source markup path (therefore no cache store) 307*04fd306cSNickeau * (Why ? for test purpose, where we want to check if the dependencies was applied) 308*04fd306cSNickeau * !!! Attention, the build of the dependencies should happen after that the markup source path is set !!! 309*04fd306cSNickeau */ 310*04fd306cSNickeau $newFetcherMarkup->outputCacheDependencies = MarkupCacheDependencies::create($newFetcherMarkup); 311*04fd306cSNickeau 312*04fd306cSNickeau /** 313*04fd306cSNickeau * The cache object depends on the running request 314*04fd306cSNickeau * We build it then just 315*04fd306cSNickeau * 316*04fd306cSNickeau * A request is also send by dokuwiki to check the cache validity 317*04fd306cSNickeau * 318*04fd306cSNickeau */ 319*04fd306cSNickeau if ($this->builderMarkupSourcePath !== null) { 320*04fd306cSNickeau 321*04fd306cSNickeau 322*04fd306cSNickeau list($wikiId, $localFile) = self::getWikiIdAndLocalFileDokuwikiCompliant($this->builderMarkupSourcePath); 323*04fd306cSNickeau 324*04fd306cSNickeau /** 325*04fd306cSNickeau * Instructions cache 326*04fd306cSNickeau */ 327*04fd306cSNickeau $newFetcherMarkup->instructionsCache = new CacheInstructions($wikiId, $localFile); 328*04fd306cSNickeau 329*04fd306cSNickeau /** 330*04fd306cSNickeau * Content cache 331*04fd306cSNickeau */ 332*04fd306cSNickeau $extension = $this->mime->getExtension(); 333*04fd306cSNickeau $newFetcherMarkup->contentCache = new CacheRenderer($wikiId, $localFile, $extension); 334*04fd306cSNickeau $newFetcherMarkup->outputCacheDependencies->rerouteCacheDestination($newFetcherMarkup->contentCache); 335*04fd306cSNickeau 336*04fd306cSNickeau /** 337*04fd306cSNickeau * Snippet Cache 338*04fd306cSNickeau * Snippet.json is data dependent 339*04fd306cSNickeau * 340*04fd306cSNickeau * For instance, the carrousel may add glide or grid as snippet. It depends on the the number of backlinks. 341*04fd306cSNickeau * 342*04fd306cSNickeau * Therefore the output should be unique by rendered slot 343*04fd306cSNickeau * Therefore we reroute (recalculate the cache key to the same than the html file) 344*04fd306cSNickeau */ 345*04fd306cSNickeau $newFetcherMarkup->snippetCache = new CacheParser($wikiId, $localFile, "snippet.json"); 346*04fd306cSNickeau $newFetcherMarkup->outputCacheDependencies->rerouteCacheDestination($newFetcherMarkup->snippetCache); 347*04fd306cSNickeau 348*04fd306cSNickeau 349*04fd306cSNickeau /** 350*04fd306cSNickeau * Runtime Meta cache 351*04fd306cSNickeau * (Technically, it's derived from the instructions) 352*04fd306cSNickeau */ 353*04fd306cSNickeau $newFetcherMarkup->metaPath = LocalPath::createFromPathString(metaFN($wikiId, '.meta')); 354*04fd306cSNickeau $newFetcherMarkup->metaCache = new CacheRenderer($wikiId, $localFile, 'metadata'); 355*04fd306cSNickeau 356*04fd306cSNickeau } 357*04fd306cSNickeau 358*04fd306cSNickeau return $newFetcherMarkup; 359*04fd306cSNickeau 360*04fd306cSNickeau } 361*04fd306cSNickeau 362*04fd306cSNickeau public function setRequestedMimeToMetadata(): FetcherMarkupBuilder 363*04fd306cSNickeau { 364*04fd306cSNickeau try { 365*04fd306cSNickeau return $this->setRequestedMime(Mime::createFromExtension(MarkupRenderer::METADATA_EXTENSION)); 366*04fd306cSNickeau } catch (ExceptionNotFound $e) { 367*04fd306cSNickeau throw new ExceptionRuntime("Internal error", 0, $e); 368*04fd306cSNickeau } 369*04fd306cSNickeau } 370*04fd306cSNickeau 371*04fd306cSNickeau public function setRequestedRenderer(string $rendererName): FetcherMarkupBuilder 372*04fd306cSNickeau { 373*04fd306cSNickeau $this->rendererName = $rendererName; 374*04fd306cSNickeau return $this; 375*04fd306cSNickeau } 376*04fd306cSNickeau 377*04fd306cSNickeau public function setRequestedContextPathWithDefault(): FetcherMarkupBuilder 378*04fd306cSNickeau { 379*04fd306cSNickeau $executionContext = ExecutionContext::getActualOrCreateFromEnv(); 380*04fd306cSNickeau try { 381*04fd306cSNickeau // do we have an executing handler 382*04fd306cSNickeau $this->requestedContextPath = $executionContext 383*04fd306cSNickeau ->getExecutingMarkupHandler() 384*04fd306cSNickeau ->getRequestedExecutingPath() 385*04fd306cSNickeau ->toWikiPath(); 386*04fd306cSNickeau } catch (ExceptionCast|ExceptionNotFound $e) { 387*04fd306cSNickeau $this->requestedContextPath = $executionContext->getConfig()->getDefaultContextPath(); 388*04fd306cSNickeau } 389*04fd306cSNickeau return $this; 390*04fd306cSNickeau } 391*04fd306cSNickeau 392*04fd306cSNickeau /** 393*04fd306cSNickeau * @param bool $isDoc - if the markup is a document or a fragment 394*04fd306cSNickeau * @return $this 395*04fd306cSNickeau * If the markup is a document, an outline is added, a toc is calculated. 396*04fd306cSNickeau * 397*04fd306cSNickeau * The default is execution parameters dependent if not set 398*04fd306cSNickeau * and is calculated at {@link FetcherMarkupBuilder::getIsDocumentExecution()} 399*04fd306cSNickeau */ 400*04fd306cSNickeau public function setIsDocument(bool $isDoc): FetcherMarkupBuilder 401*04fd306cSNickeau { 402*04fd306cSNickeau $this->isDoc = $isDoc; 403*04fd306cSNickeau return $this; 404*04fd306cSNickeau } 405*04fd306cSNickeau 406*04fd306cSNickeau /** 407*04fd306cSNickeau * @param array $instructions 408*04fd306cSNickeau * @return FetcherMarkupBuilder 409*04fd306cSNickeau */ 410*04fd306cSNickeau public function setRequestedInstructions(array $instructions): FetcherMarkupBuilder 411*04fd306cSNickeau { 412*04fd306cSNickeau $this->builderRequestedInstructions = $instructions; 413*04fd306cSNickeau return $this; 414*04fd306cSNickeau } 415*04fd306cSNickeau 416*04fd306cSNickeau /** 417*04fd306cSNickeau * @param array|null $contextData 418*04fd306cSNickeau * @return $this 419*04fd306cSNickeau */ 420*04fd306cSNickeau public function setContextData(?array $contextData): FetcherMarkupBuilder 421*04fd306cSNickeau { 422*04fd306cSNickeau if ($contextData == null) { 423*04fd306cSNickeau return $this; 424*04fd306cSNickeau } 425*04fd306cSNickeau $this->builderContextData = $contextData; 426*04fd306cSNickeau return $this; 427*04fd306cSNickeau } 428*04fd306cSNickeau 429*04fd306cSNickeau /** 430*04fd306cSNickeau * @param bool $isStandAlone 431*04fd306cSNickeau * @return $this 432*04fd306cSNickeau * 433*04fd306cSNickeau * when a execution is not a {@link FetcherMarkup::isPathExecution()}, the snippet will not be stored automatically. 434*04fd306cSNickeau * To avoid this problem, a warning is send if the calling code does not set explicitly that this is specifically a 435*04fd306cSNickeau * standalone execution 436*04fd306cSNickeau */ 437*04fd306cSNickeau public function setIsStandAloneCodeExecution(bool $isStandAlone): FetcherMarkupBuilder 438*04fd306cSNickeau { 439*04fd306cSNickeau $this->isCodeStandAloneExecution = $isStandAlone; 440*04fd306cSNickeau return $this; 441*04fd306cSNickeau } 442*04fd306cSNickeau 443*04fd306cSNickeau /** 444*04fd306cSNickeau * Determins if the run is a fragment or document execution 445*04fd306cSNickeau * 446*04fd306cSNickeau * Note: in dokuwiki term, a {@link ExecutionContext::PREVIEW_ACTION} 447*04fd306cSNickeau * preview action is a fragment 448*04fd306cSNickeau * 449*04fd306cSNickeau * @return bool true if this is a document execution 450*04fd306cSNickeau */ 451*04fd306cSNickeau private function getIsDocumentExecution(): bool 452*04fd306cSNickeau { 453*04fd306cSNickeau 454*04fd306cSNickeau if (isset($this->isDoc)) { 455*04fd306cSNickeau return $this->isDoc; 456*04fd306cSNickeau } 457*04fd306cSNickeau 458*04fd306cSNickeau /** 459*04fd306cSNickeau * By default, a string is not a whole doc 460*04fd306cSNickeau * (in test, this is almost always the case) 461*04fd306cSNickeau */ 462*04fd306cSNickeau if ($this->builderMarkupString !== null) { 463*04fd306cSNickeau return false; 464*04fd306cSNickeau } 465*04fd306cSNickeau 466*04fd306cSNickeau /** 467*04fd306cSNickeau * By default, a instructions array is not a whole doc 468*04fd306cSNickeau * (in test and rendering, this is almost always the case) 469*04fd306cSNickeau */ 470*04fd306cSNickeau if ($this->builderRequestedInstructions !== null) { 471*04fd306cSNickeau return false; 472*04fd306cSNickeau } 473*04fd306cSNickeau 474*04fd306cSNickeau try { 475*04fd306cSNickeau 476*04fd306cSNickeau /** 477*04fd306cSNickeau * What fucked up is fucked up 478*04fd306cSNickeau * Fragment such as sidebar may run in their own context (ie when editing for instance) 479*04fd306cSNickeau * but are not a document 480*04fd306cSNickeau */ 481*04fd306cSNickeau $executingWikiPath = $this->builderMarkupSourcePath->toWikiPath(); 482*04fd306cSNickeau $isFragmentMarkup = MarkupPath::createPageFromPathObject($executingWikiPath)->isSlot(); 483*04fd306cSNickeau if ($isFragmentMarkup) { 484*04fd306cSNickeau return false; 485*04fd306cSNickeau } 486*04fd306cSNickeau 487*04fd306cSNickeau /** 488*04fd306cSNickeau * If the context and executing path are: 489*04fd306cSNickeau * * the same, this is a document run 490*04fd306cSNickeau * * not the same, this is a fragment run 491*04fd306cSNickeau */ 492*04fd306cSNickeau if ($this->requestedContextPath->toUriString() !== $executingWikiPath->toUriString()) { 493*04fd306cSNickeau return false; 494*04fd306cSNickeau } 495*04fd306cSNickeau 496*04fd306cSNickeau } catch (ExceptionCast $e) { 497*04fd306cSNickeau // no executing path, not a wiki path 498*04fd306cSNickeau } 499*04fd306cSNickeau 500*04fd306cSNickeau return true; 501*04fd306cSNickeau 502*04fd306cSNickeau } 503*04fd306cSNickeau 504*04fd306cSNickeau public function setParentMarkupHandler(FetcherMarkup $parentMarkupHandler): FetcherMarkupBuilder 505*04fd306cSNickeau { 506*04fd306cSNickeau $this->parentMarkupHandler = $parentMarkupHandler; 507*04fd306cSNickeau return $this; 508*04fd306cSNickeau } 509*04fd306cSNickeau 510*04fd306cSNickeau 511*04fd306cSNickeau} 512