1*04fd306cSNickeau<?php 2*04fd306cSNickeau 3*04fd306cSNickeaunamespace ComboStrap; 4*04fd306cSNickeau 5*04fd306cSNickeau 6*04fd306cSNickeauuse ComboStrap\Meta\Store\MetadataDbStore; 7*04fd306cSNickeauuse ComboStrap\Meta\Store\MetadataDokuWikiStore; 8*04fd306cSNickeauuse ComboStrap\Tag\WebCodeTag; 9*04fd306cSNickeauuse ComboStrap\Web\Url; 10*04fd306cSNickeauuse dokuwiki\ActionRouter; 11*04fd306cSNickeauuse dokuwiki\Extension\EventHandler; 12*04fd306cSNickeauuse TestRequest; 13*04fd306cSNickeau 14*04fd306cSNickeau 15*04fd306cSNickeau/** 16*04fd306cSNickeau * An execution object permits to manage the variable state for 17*04fd306cSNickeau * an execution (ie one HTTP request) 18*04fd306cSNickeau * 19*04fd306cSNickeau * 20*04fd306cSNickeau * Note that normally every page has a page context 21*04fd306cSNickeau * meaning that you can go from an admin page to show the page. 22*04fd306cSNickeau * 23*04fd306cSNickeau * 24*04fd306cSNickeau * When an execution context has finished, it should be {@link ExecutionContext::close() closed} 25*04fd306cSNickeau * or destroyed 26*04fd306cSNickeau * 27*04fd306cSNickeau * You can get the actual execution context with {@link ExecutionContext::getActualOrCreateFromEnv()} 28*04fd306cSNickeau * 29*04fd306cSNickeau * 30*04fd306cSNickeau * Same concept than [routing context](https://vertx.io/docs/apidocs/index.html?io/vertx/ext/web/RoutingContext.html) 31*04fd306cSNickeau * (Not yet fully implemented) 32*04fd306cSNickeau * ```java 33*04fd306cSNickeau * if (pet.isPresent()) 34*04fd306cSNickeau * routingContext 35*04fd306cSNickeau * .response() 36*04fd306cSNickeau * .setStatusCode(200) 37*04fd306cSNickeau * .putHeader(HttpHeaders.CONTENT_TYPE, "application/json") 38*04fd306cSNickeau * .end(pet.get().encode()); // (4) 39*04fd306cSNickeau * else 40*04fd306cSNickeau * routingContext.fail(404, new Exception("Pet not found")); 41*04fd306cSNickeau * } 42*04fd306cSNickeau * ``` 43*04fd306cSNickeau */ 44*04fd306cSNickeauclass ExecutionContext 45*04fd306cSNickeau{ 46*04fd306cSNickeau 47*04fd306cSNickeau /** 48*04fd306cSNickeau * Dokuwiki do attribute 49*04fd306cSNickeau */ 50*04fd306cSNickeau const DO_ATTRIBUTE = "do"; 51*04fd306cSNickeau 52*04fd306cSNickeau 53*04fd306cSNickeau const CANONICAL = "execution-context"; 54*04fd306cSNickeau 55*04fd306cSNickeau /** 56*04fd306cSNickeau * All action (handler) 57*04fd306cSNickeau * That's what you will found in the `do` parameters 58*04fd306cSNickeau */ 59*04fd306cSNickeau const SHOW_ACTION = "show"; 60*04fd306cSNickeau const EDIT_ACTION = "edit"; 61*04fd306cSNickeau /** 62*04fd306cSNickeau * Preview is also used to 63*04fd306cSNickeau * set the {@link FetcherMarkup::isFragment()} 64*04fd306cSNickeau * processing to fragment 65*04fd306cSNickeau */ 66*04fd306cSNickeau const PREVIEW_ACTION = "preview"; 67*04fd306cSNickeau const ADMIN_ACTION = "admin"; 68*04fd306cSNickeau const DRAFT_ACTION = "draft"; 69*04fd306cSNickeau const SEARCH_ACTION = "search"; 70*04fd306cSNickeau const LOGIN_ACTION = "login"; 71*04fd306cSNickeau const SAVE_ACTION = "save"; 72*04fd306cSNickeau const DRAFT_DEL_ACTION = "draftdel"; 73*04fd306cSNickeau const REDIRECT_ACTION = "redirect"; 74*04fd306cSNickeau 75*04fd306cSNickeau /** 76*04fd306cSNickeau * private actions does not render a page to be indexed 77*04fd306cSNickeau * by a search engine (ie no redirect) 78*04fd306cSNickeau * May be easier, if not `show`, not public 79*04fd306cSNickeau */ 80*04fd306cSNickeau const PRIVATES_ACTION_NO_REDIRECT = [ 81*04fd306cSNickeau self::EDIT_ACTION, 82*04fd306cSNickeau self::PREVIEW_ACTION, 83*04fd306cSNickeau self::ADMIN_ACTION, 84*04fd306cSNickeau self::DRAFT_ACTION, 85*04fd306cSNickeau self::DRAFT_DEL_ACTION, 86*04fd306cSNickeau self::SEARCH_ACTION, 87*04fd306cSNickeau self::LOGIN_ACTION, 88*04fd306cSNickeau self::SAVE_ACTION, 89*04fd306cSNickeau self::REDIRECT_ACTION, 90*04fd306cSNickeau self::REGISTER_ACTION, 91*04fd306cSNickeau self::RESEND_PWD_ACTION, 92*04fd306cSNickeau self::PROFILE_ACTION, 93*04fd306cSNickeau ]; 94*04fd306cSNickeau const REGISTER_ACTION = "register"; 95*04fd306cSNickeau const RESEND_PWD_ACTION = "resendpwd"; 96*04fd306cSNickeau const PROFILE_ACTION = "profile"; 97*04fd306cSNickeau const REVISIONS_ACTION = "revisions"; 98*04fd306cSNickeau const DIFF_ACTION = "diff"; 99*04fd306cSNickeau const INDEX_ACTION = "index"; 100*04fd306cSNickeau 101*04fd306cSNickeau 102*04fd306cSNickeau /** 103*04fd306cSNickeau * @var array of objects that are scoped to this request 104*04fd306cSNickeau */ 105*04fd306cSNickeau private array $executionScopedVariables = []; 106*04fd306cSNickeau 107*04fd306cSNickeau private CacheManager $cacheManager; 108*04fd306cSNickeau 109*04fd306cSNickeau private Site $app; 110*04fd306cSNickeau 111*04fd306cSNickeau /** 112*04fd306cSNickeau * A root execution context if any 113*04fd306cSNickeau * Null because you can not unset a static variable 114*04fd306cSNickeau */ 115*04fd306cSNickeau private static ?ExecutionContext $actualExecutionContext = null; 116*04fd306cSNickeau 117*04fd306cSNickeau private ?string $capturedGlobalId; 118*04fd306cSNickeau /** 119*04fd306cSNickeau * It may be an array when preview/save/cancel 120*04fd306cSNickeau * @var array|string|null 121*04fd306cSNickeau */ 122*04fd306cSNickeau private $capturedAct; 123*04fd306cSNickeau 124*04fd306cSNickeau 125*04fd306cSNickeau private Url $url; 126*04fd306cSNickeau 127*04fd306cSNickeau 128*04fd306cSNickeau public HttpResponse $response; 129*04fd306cSNickeau 130*04fd306cSNickeau /** 131*04fd306cSNickeau * @var IFetcher - the fetcher that takes into account the HTTP request 132*04fd306cSNickeau */ 133*04fd306cSNickeau private IFetcher $executingMainFetcher; 134*04fd306cSNickeau 135*04fd306cSNickeau /** 136*04fd306cSNickeau * @var array - a stack of: 137*04fd306cSNickeau * * markup handler executing (ie handler that is taking a markup (file, string) and making it a HTML, pdf, ...) 138*04fd306cSNickeau * * and old global environement, $executingId, $contextExecutingId, $act 139*04fd306cSNickeau * 140*04fd306cSNickeau * This fetcher is called by the main fetcher or by the {@link self::setExecutingMarkupHandler()} 141*04fd306cSNickeau */ 142*04fd306cSNickeau private array $executingMarkupHandlerStack = []; 143*04fd306cSNickeau 144*04fd306cSNickeau /** 145*04fd306cSNickeau * @var TemplateForWebPage - the page template fetcher running (when a fetcher creates a page, it would uses this fetcher) 146*04fd306cSNickeau * This class is called by the main fetcher to create a page 147*04fd306cSNickeau */ 148*04fd306cSNickeau private TemplateForWebPage $executingPageTemplate; 149*04fd306cSNickeau private string $creationTime; 150*04fd306cSNickeau 151*04fd306cSNickeau 152*04fd306cSNickeau public function __construct() 153*04fd306cSNickeau { 154*04fd306cSNickeau 155*04fd306cSNickeau $this->creationTime = Iso8601Date::createFromNow()->toIsoStringMs(); 156*04fd306cSNickeau 157*04fd306cSNickeau $this->url = Url::createFromGetOrPostGlobalVariable(); 158*04fd306cSNickeau 159*04fd306cSNickeau $this->response = HttpResponse::createFromExecutionContext($this); 160*04fd306cSNickeau 161*04fd306cSNickeau /** 162*04fd306cSNickeau * The requested action 163*04fd306cSNickeau */ 164*04fd306cSNickeau global $ACT; 165*04fd306cSNickeau $this->capturedAct = $ACT; 166*04fd306cSNickeau try { 167*04fd306cSNickeau $urlAct = $this->url->getQueryPropertyValue(self::DO_ATTRIBUTE); 168*04fd306cSNickeau } catch (ExceptionNotFound $e) { 169*04fd306cSNickeau /** 170*04fd306cSNickeau * The value is unknown 171*04fd306cSNickeau * (in doku.php, the default is `show`, 172*04fd306cSNickeau * we take the dokuwiki value because the execution context may be 173*04fd306cSNickeau * created after the dokuwiki init) 174*04fd306cSNickeau */ 175*04fd306cSNickeau $urlAct = $ACT; 176*04fd306cSNickeau } 177*04fd306cSNickeau $ACT = $urlAct; 178*04fd306cSNickeau 179*04fd306cSNickeau /** 180*04fd306cSNickeau * The requested id 181*04fd306cSNickeau */ 182*04fd306cSNickeau global $ID; 183*04fd306cSNickeau $this->capturedGlobalId = $ID; 184*04fd306cSNickeau try { 185*04fd306cSNickeau 186*04fd306cSNickeau $urlId = $this->url->getQueryPropertyValue(DokuwikiId::DOKUWIKI_ID_ATTRIBUTE); 187*04fd306cSNickeau if (is_array($urlId)) { 188*04fd306cSNickeau /** 189*04fd306cSNickeau * hack because the dokuwiki request global object as `ID` and `id` as array 190*04fd306cSNickeau * but our own {@link Url object} don't allow that and makes an array instead 191*04fd306cSNickeau * We don't use this data anyway, anymore ... 192*04fd306cSNickeau */ 193*04fd306cSNickeau $urlId = $urlId[0]; 194*04fd306cSNickeau } 195*04fd306cSNickeau $ID = $urlId; 196*04fd306cSNickeau 197*04fd306cSNickeau } catch (ExceptionNotFound $e) { 198*04fd306cSNickeau // none 199*04fd306cSNickeau $ID = null; 200*04fd306cSNickeau } 201*04fd306cSNickeau 202*04fd306cSNickeau 203*04fd306cSNickeau } 204*04fd306cSNickeau 205*04fd306cSNickeau 206*04fd306cSNickeau /** 207*04fd306cSNickeau * @throws ExceptionNotFound 208*04fd306cSNickeau */ 209*04fd306cSNickeau public static function getExecutionContext(): ExecutionContext 210*04fd306cSNickeau { 211*04fd306cSNickeau if (!isset(self::$actualExecutionContext)) { 212*04fd306cSNickeau throw new ExceptionNotFound("No root context"); 213*04fd306cSNickeau } 214*04fd306cSNickeau return self::$actualExecutionContext; 215*04fd306cSNickeau } 216*04fd306cSNickeau 217*04fd306cSNickeau /** 218*04fd306cSNickeau * Utility class to set the requested id (used only in test, 219*04fd306cSNickeau * normally the environment is set from global PHP environment variable 220*04fd306cSNickeau * that get the HTTP request 221*04fd306cSNickeau * @param string $requestedId 222*04fd306cSNickeau * @return ExecutionContext 223*04fd306cSNickeau * @deprecated use {@link self::setDefaultContextPath()} if you want to set a context path 224*04fd306cSNickeau * without using a {@link TemplateForWebPage} or {@link FetcherMarkup} 225*04fd306cSNickeau */ 226*04fd306cSNickeau public static function getOrCreateFromRequestedWikiId(string $requestedId): ExecutionContext 227*04fd306cSNickeau { 228*04fd306cSNickeau 229*04fd306cSNickeau return self::getActualOrCreateFromEnv() 230*04fd306cSNickeau ->setDefaultContextPath(WikiPath::createMarkupPathFromId($requestedId)); 231*04fd306cSNickeau 232*04fd306cSNickeau } 233*04fd306cSNickeau 234*04fd306cSNickeau 235*04fd306cSNickeau /** 236*04fd306cSNickeau * @return ExecutionContext 237*04fd306cSNickeau * @deprecated uses {@link self::createBlank()} instead 238*04fd306cSNickeau */ 239*04fd306cSNickeau public static function createFromEnvironmentVariable(): ExecutionContext 240*04fd306cSNickeau { 241*04fd306cSNickeau return self::createBlank(); 242*04fd306cSNickeau } 243*04fd306cSNickeau 244*04fd306cSNickeau 245*04fd306cSNickeau public static function createBlank(): ExecutionContext 246*04fd306cSNickeau { 247*04fd306cSNickeau 248*04fd306cSNickeau if (self::$actualExecutionContext !== null) { 249*04fd306cSNickeau throw new ExceptionRuntimeInternal("The previous root context should be closed first"); 250*04fd306cSNickeau } 251*04fd306cSNickeau $rootExecutionContext = (new ExecutionContext()); 252*04fd306cSNickeau self::$actualExecutionContext = $rootExecutionContext; 253*04fd306cSNickeau return $rootExecutionContext; 254*04fd306cSNickeau 255*04fd306cSNickeau } 256*04fd306cSNickeau 257*04fd306cSNickeau /** 258*04fd306cSNickeau * @return ExecutionContext - return the actual context or create a new one from the environment 259*04fd306cSNickeau */ 260*04fd306cSNickeau public static function getActualOrCreateFromEnv(): ExecutionContext 261*04fd306cSNickeau { 262*04fd306cSNickeau try { 263*04fd306cSNickeau return self::getExecutionContext(); 264*04fd306cSNickeau } catch (ExceptionNotFound $e) { 265*04fd306cSNickeau return self::createBlank(); 266*04fd306cSNickeau } 267*04fd306cSNickeau } 268*04fd306cSNickeau 269*04fd306cSNickeau /** 270*04fd306cSNickeau * We create the id manager in the execution 271*04fd306cSNickeau * context 272*04fd306cSNickeau * (because in case a user choose to not use templating, the {@link FetcherMarkup} 273*04fd306cSNickeau * is not available) 274*04fd306cSNickeau * And all dynamic component such as {@link \syntax_plugin_combo_dropdown} would not 275*04fd306cSNickeau * work anymore. 276*04fd306cSNickeau * 277*04fd306cSNickeau * @return IdManager 278*04fd306cSNickeau */ 279*04fd306cSNickeau public function getIdManager(): IdManager 280*04fd306cSNickeau { 281*04fd306cSNickeau if (!isset($this->idManager)) { 282*04fd306cSNickeau $this->idManager = new IdManager($this); 283*04fd306cSNickeau } 284*04fd306cSNickeau return $this->idManager; 285*04fd306cSNickeau } 286*04fd306cSNickeau 287*04fd306cSNickeau /** 288*04fd306cSNickeau * Return the actual context path 289*04fd306cSNickeau */ 290*04fd306cSNickeau public function getContextNamespacePath(): WikiPath 291*04fd306cSNickeau { 292*04fd306cSNickeau $requestedPath = $this->getContextPath(); 293*04fd306cSNickeau try { 294*04fd306cSNickeau return $requestedPath->getParent(); 295*04fd306cSNickeau } catch (ExceptionNotFound $e) { 296*04fd306cSNickeau // root 297*04fd306cSNickeau return $requestedPath; 298*04fd306cSNickeau } 299*04fd306cSNickeau 300*04fd306cSNickeau } 301*04fd306cSNickeau 302*04fd306cSNickeau 303*04fd306cSNickeau /** 304*04fd306cSNickeau * @throws ExceptionNotFound 305*04fd306cSNickeau */ 306*04fd306cSNickeau public function getExecutingWikiId(): string 307*04fd306cSNickeau { 308*04fd306cSNickeau global $ID; 309*04fd306cSNickeau if (empty($ID)) { 310*04fd306cSNickeau throw new ExceptionNotFound("No executing id was found"); 311*04fd306cSNickeau } 312*04fd306cSNickeau return $ID; 313*04fd306cSNickeau } 314*04fd306cSNickeau 315*04fd306cSNickeau 316*04fd306cSNickeau /** 317*04fd306cSNickeau * @return void close the execution context 318*04fd306cSNickeau */ 319*04fd306cSNickeau public function close() 320*04fd306cSNickeau { 321*04fd306cSNickeau 322*04fd306cSNickeau /** 323*04fd306cSNickeau * Check that this execution context was not closed 324*04fd306cSNickeau */ 325*04fd306cSNickeau if (self::$actualExecutionContext->creationTime !== $this->creationTime) { 326*04fd306cSNickeau throw new ExceptionRuntimeInternal("This execution context was already closed"); 327*04fd306cSNickeau } 328*04fd306cSNickeau 329*04fd306cSNickeau /** 330*04fd306cSNickeau * Restore the global $conf of dokuwiki 331*04fd306cSNickeau */ 332*04fd306cSNickeau $this->getApp()->getConfig()->restoreConfigState(); 333*04fd306cSNickeau 334*04fd306cSNickeau /** global dokuwiki messages variable */ 335*04fd306cSNickeau global $MSG; 336*04fd306cSNickeau unset($MSG); 337*04fd306cSNickeau 338*04fd306cSNickeau /** 339*04fd306cSNickeau * Environment restoration 340*04fd306cSNickeau * Execution context, change for now only this 341*04fd306cSNickeau * global variables 342*04fd306cSNickeau */ 343*04fd306cSNickeau global $ACT; 344*04fd306cSNickeau $ACT = $this->getCapturedAct(); 345*04fd306cSNickeau global $ID; 346*04fd306cSNickeau $ID = $this->getCapturedRunningId(); 347*04fd306cSNickeau global $TOC; 348*04fd306cSNickeau unset($TOC); 349*04fd306cSNickeau 350*04fd306cSNickeau // global scope store 351*04fd306cSNickeau MetadataDbStore::resetAll(); 352*04fd306cSNickeau MetadataDokuWikiStore::unsetGlobalVariables(); 353*04fd306cSNickeau 354*04fd306cSNickeau // Router: dokuwiki global 355*04fd306cSNickeau // reset event handler 356*04fd306cSNickeau global $EVENT_HANDLER; 357*04fd306cSNickeau $EVENT_HANDLER = new EventHandler(); 358*04fd306cSNickeau /** 359*04fd306cSNickeau * We can't give the getInstance, a true value 360*04fd306cSNickeau * because it will otherwise start the routing process 361*04fd306cSNickeau * {@link ActionRouter::getInstance()} 362*04fd306cSNickeau */ 363*04fd306cSNickeau 364*04fd306cSNickeau 365*04fd306cSNickeau /** 366*04fd306cSNickeau * Close execution variables 367*04fd306cSNickeau * (and therefore also {@link Sqlite} 368*04fd306cSNickeau */ 369*04fd306cSNickeau $this->closeExecutionVariables(); 370*04fd306cSNickeau 371*04fd306cSNickeau /** 372*04fd306cSNickeau * Is this really needed ? 373*04fd306cSNickeau * as we unset the execution context below 374*04fd306cSNickeau */ 375*04fd306cSNickeau unset($this->executingMainFetcher); 376*04fd306cSNickeau unset($this->executingMarkupHandlerStack); 377*04fd306cSNickeau unset($this->cacheManager); 378*04fd306cSNickeau unset($this->idManager); 379*04fd306cSNickeau 380*04fd306cSNickeau /** 381*04fd306cSNickeau * Deleting 382*04fd306cSNickeau */ 383*04fd306cSNickeau self::$actualExecutionContext = null; 384*04fd306cSNickeau 385*04fd306cSNickeau 386*04fd306cSNickeau } 387*04fd306cSNickeau 388*04fd306cSNickeau 389*04fd306cSNickeau public function getCapturedRunningId(): ?string 390*04fd306cSNickeau { 391*04fd306cSNickeau return $this->capturedGlobalId; 392*04fd306cSNickeau } 393*04fd306cSNickeau 394*04fd306cSNickeau public function getCapturedAct() 395*04fd306cSNickeau { 396*04fd306cSNickeau return $this->capturedAct; 397*04fd306cSNickeau } 398*04fd306cSNickeau 399*04fd306cSNickeau public function getCacheManager(): CacheManager 400*04fd306cSNickeau { 401*04fd306cSNickeau $root = self::$actualExecutionContext; 402*04fd306cSNickeau if (!isset($root->cacheManager)) { 403*04fd306cSNickeau $root->cacheManager = new CacheManager($this); 404*04fd306cSNickeau } 405*04fd306cSNickeau return $root->cacheManager; 406*04fd306cSNickeau 407*04fd306cSNickeau } 408*04fd306cSNickeau 409*04fd306cSNickeau /** 410*04fd306cSNickeau * Return the root path if nothing is found 411*04fd306cSNickeau */ 412*04fd306cSNickeau public function getRequestedPath(): WikiPath 413*04fd306cSNickeau { 414*04fd306cSNickeau /** 415*04fd306cSNickeau * Do we have a template page executing ? 416*04fd306cSNickeau */ 417*04fd306cSNickeau try { 418*04fd306cSNickeau return $this->getExecutingPageTemplate() 419*04fd306cSNickeau ->getRequestedContextPath(); 420*04fd306cSNickeau } catch (ExceptionNotFound $e) { 421*04fd306cSNickeau try { 422*04fd306cSNickeau /** 423*04fd306cSNickeau * Case when the main handler 424*04fd306cSNickeau * run the main content before 425*04fd306cSNickeau * to inject it in the template page 426*04fd306cSNickeau * {@link TemplateForWebPage::render()} 427*04fd306cSNickeau */ 428*04fd306cSNickeau return $this->getExecutingMarkupHandler() 429*04fd306cSNickeau ->getRequestedContextPath(); 430*04fd306cSNickeau } catch (ExceptionNotFound $e) { 431*04fd306cSNickeau 432*04fd306cSNickeau 433*04fd306cSNickeau /** 434*04fd306cSNickeau * not a template engine running 435*04fd306cSNickeau * The id notion is a little bit everywhere 436*04fd306cSNickeau * That's why we just don't check the action ($ACT) 437*04fd306cSNickeau * 438*04fd306cSNickeau * Example: 439*04fd306cSNickeau * * `id` may be asked by acl to determine the right 440*04fd306cSNickeau * * ... 441*04fd306cSNickeau */ 442*04fd306cSNickeau global $INPUT; 443*04fd306cSNickeau $inputId = $INPUT->str("id"); 444*04fd306cSNickeau if (!empty($inputId)) { 445*04fd306cSNickeau return WikiPath::createMarkupPathFromId($inputId); 446*04fd306cSNickeau } 447*04fd306cSNickeau 448*04fd306cSNickeau global $ID; 449*04fd306cSNickeau if (!empty($ID)) { 450*04fd306cSNickeau return WikiPath::createMarkupPathFromId($ID); 451*04fd306cSNickeau } 452*04fd306cSNickeau 453*04fd306cSNickeau /** 454*04fd306cSNickeau * This should be less used 455*04fd306cSNickeau * but shows where the requested id is spilled in dokuwiki 456*04fd306cSNickeau * 457*04fd306cSNickeau * If the component is in a sidebar, we don't want the ID of the sidebar 458*04fd306cSNickeau * but the ID of the page. 459*04fd306cSNickeau */ 460*04fd306cSNickeau global $INFO; 461*04fd306cSNickeau if ($INFO !== null) { 462*04fd306cSNickeau $callingId = $INFO['id']; 463*04fd306cSNickeau if (!empty($callingId)) { 464*04fd306cSNickeau return WikiPath::createMarkupPathFromId($callingId); 465*04fd306cSNickeau } 466*04fd306cSNickeau } 467*04fd306cSNickeau 468*04fd306cSNickeau /** 469*04fd306cSNickeau * This is the case with event triggered 470*04fd306cSNickeau * before DokuWiki such as 471*04fd306cSNickeau * https://www.dokuwiki.org/devel:event:init_lang_load 472*04fd306cSNickeau * REQUEST is a mixed of post and get parameters 473*04fd306cSNickeau */ 474*04fd306cSNickeau global $_REQUEST; 475*04fd306cSNickeau if (isset($_REQUEST[DokuwikiId::DOKUWIKI_ID_ATTRIBUTE])) { 476*04fd306cSNickeau $requestId = $_REQUEST[DokuwikiId::DOKUWIKI_ID_ATTRIBUTE]; 477*04fd306cSNickeau if (!empty($requestId)) { 478*04fd306cSNickeau return WikiPath::createMarkupPathFromId($requestId); 479*04fd306cSNickeau } 480*04fd306cSNickeau } 481*04fd306cSNickeau 482*04fd306cSNickeau // not that show action is the default even if it's not set 483*04fd306cSNickeau // we can't then control if the id should exists or not 484*04fd306cSNickeau // markup based on string (test) or snippet of code 485*04fd306cSNickeau // return the default context path (ie the root page) 486*04fd306cSNickeau return $this->getConfig()->getDefaultContextPath(); 487*04fd306cSNickeau } 488*04fd306cSNickeau 489*04fd306cSNickeau } 490*04fd306cSNickeau 491*04fd306cSNickeau } 492*04fd306cSNickeau 493*04fd306cSNickeau /** 494*04fd306cSNickeau * @throws ExceptionNotFound 495*04fd306cSNickeau */ 496*04fd306cSNickeau public function &getRuntimeObject(string $objectIdentifier) 497*04fd306cSNickeau { 498*04fd306cSNickeau if (isset($this->executionScopedVariables[$objectIdentifier])) { 499*04fd306cSNickeau return $this->executionScopedVariables[$objectIdentifier]; 500*04fd306cSNickeau } 501*04fd306cSNickeau throw new ExceptionNotFound("No object $objectIdentifier found"); 502*04fd306cSNickeau } 503*04fd306cSNickeau 504*04fd306cSNickeau public function setRuntimeObject($objectIdentifier, &$object): ExecutionContext 505*04fd306cSNickeau { 506*04fd306cSNickeau $this->executionScopedVariables[$objectIdentifier] = &$object; 507*04fd306cSNickeau return $this; 508*04fd306cSNickeau } 509*04fd306cSNickeau 510*04fd306cSNickeau public function getUrl(): Url 511*04fd306cSNickeau { 512*04fd306cSNickeau return $this->url; 513*04fd306cSNickeau } 514*04fd306cSNickeau 515*04fd306cSNickeau 516*04fd306cSNickeau /** 517*04fd306cSNickeau * @param string $key 518*04fd306cSNickeau * @param $value 519*04fd306cSNickeau * @param string|null $pluginNamespace - if null, stored in the global conf namespace 520*04fd306cSNickeau * @return $this 521*04fd306cSNickeau * @deprecated use {@link SiteConfig::setConf()} instead 522*04fd306cSNickeau */ 523*04fd306cSNickeau public function setConf(string $key, $value, ?string $pluginNamespace = PluginUtility::PLUGIN_BASE_NAME): ExecutionContext 524*04fd306cSNickeau { 525*04fd306cSNickeau $this->getApp()->getConfig()->setConf($key, $value, $pluginNamespace); 526*04fd306cSNickeau return $this; 527*04fd306cSNickeau } 528*04fd306cSNickeau 529*04fd306cSNickeau /** 530*04fd306cSNickeau * @param string $key 531*04fd306cSNickeau * @param string|null $default 532*04fd306cSNickeau * @return mixed|null 533*04fd306cSNickeau * @deprecated use 534*04fd306cSNickeau */ 535*04fd306cSNickeau public function getConfValue(string $key, string $default = null) 536*04fd306cSNickeau { 537*04fd306cSNickeau return $this->getApp()->getConfig()->getValue($key, $default); 538*04fd306cSNickeau } 539*04fd306cSNickeau 540*04fd306cSNickeau public function setRuntimeBoolean(string $key, bool $b): ExecutionContext 541*04fd306cSNickeau { 542*04fd306cSNickeau $this->executionScopedVariables[$key] = $b; 543*04fd306cSNickeau return $this; 544*04fd306cSNickeau } 545*04fd306cSNickeau 546*04fd306cSNickeau /** 547*04fd306cSNickeau * @throws ExceptionNotFound 548*04fd306cSNickeau */ 549*04fd306cSNickeau public function getRuntimeBoolean(string $name): bool 550*04fd306cSNickeau { 551*04fd306cSNickeau $var = $this->executionScopedVariables[$name]; 552*04fd306cSNickeau if (!isset($var)) { 553*04fd306cSNickeau throw new ExceptionNotFound("No $name runtime env was found"); 554*04fd306cSNickeau } 555*04fd306cSNickeau return DataType::toBoolean($var); 556*04fd306cSNickeau } 557*04fd306cSNickeau 558*04fd306cSNickeau /** 559*04fd306cSNickeau * @return $this 560*04fd306cSNickeau * @deprecated uses {@link SiteConfig::setCacheXhtmlOn()} 561*04fd306cSNickeau */ 562*04fd306cSNickeau public function setCacheXhtmlOn(): ExecutionContext 563*04fd306cSNickeau { 564*04fd306cSNickeau $this->getApp()->getConfig()->setCacheXhtmlOn(); 565*04fd306cSNickeau return $this; 566*04fd306cSNickeau } 567*04fd306cSNickeau 568*04fd306cSNickeau /** 569*04fd306cSNickeau * 570*04fd306cSNickeau * @return $this 571*04fd306cSNickeau * @deprecated use the {@link SiteConfig::setConsoleOn} instead 572*04fd306cSNickeau */ 573*04fd306cSNickeau public function setConsoleOn(): ExecutionContext 574*04fd306cSNickeau { 575*04fd306cSNickeau $this->getApp()->getConfig()->setCacheXhtmlOn(); 576*04fd306cSNickeau return $this; 577*04fd306cSNickeau } 578*04fd306cSNickeau 579*04fd306cSNickeau public function setConsoleOff(): ExecutionContext 580*04fd306cSNickeau { 581*04fd306cSNickeau $this->getConfig()->setConsoleOff(); 582*04fd306cSNickeau return $this; 583*04fd306cSNickeau } 584*04fd306cSNickeau 585*04fd306cSNickeau /** 586*04fd306cSNickeau * @return $this 587*04fd306cSNickeau * @deprecated use {@link SiteConfig::setDisableThemeSystem()} 588*04fd306cSNickeau */ 589*04fd306cSNickeau public function setDisableTemplating(): ExecutionContext 590*04fd306cSNickeau { 591*04fd306cSNickeau $this->getApp()->getConfig()->setDisableThemeSystem(); 592*04fd306cSNickeau return $this; 593*04fd306cSNickeau } 594*04fd306cSNickeau 595*04fd306cSNickeau 596*04fd306cSNickeau /** 597*04fd306cSNickeau * @return bool 598*04fd306cSNickeau * @deprecated use the {@link SiteConfig::isConsoleOn()} instead 599*04fd306cSNickeau */ 600*04fd306cSNickeau public function isConsoleOn(): bool 601*04fd306cSNickeau { 602*04fd306cSNickeau return $this->getApp()->getConfig()->isConsoleOn(); 603*04fd306cSNickeau } 604*04fd306cSNickeau 605*04fd306cSNickeau 606*04fd306cSNickeau /** 607*04fd306cSNickeau * Dokuwiki handler name 608*04fd306cSNickeau * @return array|mixed|string 609*04fd306cSNickeau */ 610*04fd306cSNickeau public function getExecutingAction() 611*04fd306cSNickeau { 612*04fd306cSNickeau global $ACT; 613*04fd306cSNickeau return $ACT; 614*04fd306cSNickeau } 615*04fd306cSNickeau 616*04fd306cSNickeau public function setLogExceptionToError(): ExecutionContext 617*04fd306cSNickeau { 618*04fd306cSNickeau $this->getConfig()->setLogExceptionToError(); 619*04fd306cSNickeau return $this; 620*04fd306cSNickeau } 621*04fd306cSNickeau 622*04fd306cSNickeau /** 623*04fd306cSNickeau * @return SnippetSystem 624*04fd306cSNickeau * It's not attached to the {@link FetcherMarkup} 625*04fd306cSNickeau * because the user may choose to not use it (ie {@link SiteConfig::isThemeSystemEnabled()} 626*04fd306cSNickeau */ 627*04fd306cSNickeau public function getSnippetSystem(): SnippetSystem 628*04fd306cSNickeau { 629*04fd306cSNickeau return SnippetSystem::getFromContext(); 630*04fd306cSNickeau } 631*04fd306cSNickeau 632*04fd306cSNickeau /** 633*04fd306cSNickeau * @return bool - does the action create a publication (render a page) 634*04fd306cSNickeau */ 635*04fd306cSNickeau public function isPublicationAction(): bool 636*04fd306cSNickeau { 637*04fd306cSNickeau 638*04fd306cSNickeau $act = $this->getExecutingAction(); 639*04fd306cSNickeau if (in_array($act, self::PRIVATES_ACTION_NO_REDIRECT)) { 640*04fd306cSNickeau return false; 641*04fd306cSNickeau } 642*04fd306cSNickeau 643*04fd306cSNickeau return true; 644*04fd306cSNickeau 645*04fd306cSNickeau } 646*04fd306cSNickeau 647*04fd306cSNickeau public function setEnableSectionEditing(): ExecutionContext 648*04fd306cSNickeau { 649*04fd306cSNickeau $this->setConf('maxseclevel', 999, null); 650*04fd306cSNickeau return $this; 651*04fd306cSNickeau } 652*04fd306cSNickeau 653*04fd306cSNickeau /** 654*04fd306cSNickeau * @param string $value 655*04fd306cSNickeau * @return $this 656*04fd306cSNickeau * @deprecated use the {@link SiteConfig::setCanonicalUrlType()} instead 657*04fd306cSNickeau */ 658*04fd306cSNickeau public function setCanonicalUrlType(string $value): ExecutionContext 659*04fd306cSNickeau { 660*04fd306cSNickeau $this->getConfig()->setCanonicalUrlType($value); 661*04fd306cSNickeau return $this; 662*04fd306cSNickeau } 663*04fd306cSNickeau 664*04fd306cSNickeau public function setUseHeadingAsTitle(): ExecutionContext 665*04fd306cSNickeau { 666*04fd306cSNickeau // https://www.dokuwiki.org/config:useheading 667*04fd306cSNickeau $this->setConf('useheading', 1, null); 668*04fd306cSNickeau return $this; 669*04fd306cSNickeau } 670*04fd306cSNickeau 671*04fd306cSNickeau public function response(): HttpResponse 672*04fd306cSNickeau { 673*04fd306cSNickeau return $this->response; 674*04fd306cSNickeau } 675*04fd306cSNickeau 676*04fd306cSNickeau /** 677*04fd306cSNickeau * @param string|null $executingId 678*04fd306cSNickeau * @return void 679*04fd306cSNickeau */ 680*04fd306cSNickeau private function setExecutingId(?string $executingId): void 681*04fd306cSNickeau { 682*04fd306cSNickeau global $ID; 683*04fd306cSNickeau if ($executingId == null) { 684*04fd306cSNickeau // ID should not be null 685*04fd306cSNickeau // to be able to check the ACL 686*04fd306cSNickeau return; 687*04fd306cSNickeau } 688*04fd306cSNickeau $executingId = WikiPath::removeRootSepIfPresent($executingId); 689*04fd306cSNickeau $ID = $executingId; 690*04fd306cSNickeau } 691*04fd306cSNickeau 692*04fd306cSNickeau public function setConfGlobal(string $key, string $value): ExecutionContext 693*04fd306cSNickeau { 694*04fd306cSNickeau $this->setConf($key, $value, null); 695*04fd306cSNickeau return $this; 696*04fd306cSNickeau } 697*04fd306cSNickeau 698*04fd306cSNickeau /** 699*04fd306cSNickeau * @return bool - if this execution is a test running 700*04fd306cSNickeau */ 701*04fd306cSNickeau public function isTestRun(): bool 702*04fd306cSNickeau { 703*04fd306cSNickeau /** 704*04fd306cSNickeau * Test Requested is loaded only in a test run 705*04fd306cSNickeau * Does not exist in a normal installation 706*04fd306cSNickeau * and is not found, triggering an exception 707*04fd306cSNickeau */ 708*04fd306cSNickeau if (class_exists('TestRequest')) { 709*04fd306cSNickeau $testRequest = TestRequest::getRunning(); 710*04fd306cSNickeau return $testRequest !== null; 711*04fd306cSNickeau } 712*04fd306cSNickeau return false; 713*04fd306cSNickeau 714*04fd306cSNickeau } 715*04fd306cSNickeau 716*04fd306cSNickeau private function setExecutingAction(?string $runningAct): ExecutionContext 717*04fd306cSNickeau { 718*04fd306cSNickeau global $ACT; 719*04fd306cSNickeau $ACT = $runningAct; 720*04fd306cSNickeau return $this; 721*04fd306cSNickeau } 722*04fd306cSNickeau 723*04fd306cSNickeau 724*04fd306cSNickeau /** 725*04fd306cSNickeau * Set the main fetcher, the entry point of the request (ie the url of the browser) 726*04fd306cSNickeau * that will return a string 727*04fd306cSNickeau * @throws ExceptionBadArgument 728*04fd306cSNickeau * @throws ExceptionInternal 729*04fd306cSNickeau * @throws ExceptionNotFound 730*04fd306cSNickeau */ 731*04fd306cSNickeau public function createStringMainFetcherFromRequestedUrl(Url $fetchUrl): IFetcherString 732*04fd306cSNickeau { 733*04fd306cSNickeau $this->executingMainFetcher = FetcherSystem::createFetcherStringFromUrl($fetchUrl); 734*04fd306cSNickeau return $this->executingMainFetcher; 735*04fd306cSNickeau } 736*04fd306cSNickeau 737*04fd306cSNickeau 738*04fd306cSNickeau /** 739*04fd306cSNickeau * Set the main fetcher (with the url of the browser) 740*04fd306cSNickeau * that will return a path (image, ...) 741*04fd306cSNickeau * @throws ExceptionBadArgument 742*04fd306cSNickeau * @throws ExceptionInternal 743*04fd306cSNickeau * @throws ExceptionNotFound 744*04fd306cSNickeau */ 745*04fd306cSNickeau public function createPathMainFetcherFromUrl(Url $fetchUrl): IFetcherPath 746*04fd306cSNickeau { 747*04fd306cSNickeau $this->executingMainFetcher = FetcherSystem::createPathFetcherFromUrl($fetchUrl); 748*04fd306cSNickeau return $this->executingMainFetcher; 749*04fd306cSNickeau } 750*04fd306cSNickeau 751*04fd306cSNickeau public function closeMainExecutingFetcher(): ExecutionContext 752*04fd306cSNickeau { 753*04fd306cSNickeau unset($this->executingMainFetcher); 754*04fd306cSNickeau /** 755*04fd306cSNickeau * Snippet are not yet fully coupled to the {@link FetcherMarkup} 756*04fd306cSNickeau */ 757*04fd306cSNickeau $this->closeAndRemoveRuntimeVariableIfExists(Snippet::CANONICAL); 758*04fd306cSNickeau return $this; 759*04fd306cSNickeau } 760*04fd306cSNickeau 761*04fd306cSNickeau /** 762*04fd306cSNickeau * This function sets the markup running context object globally, 763*04fd306cSNickeau * so that code may access it via this global variable 764*04fd306cSNickeau * (Fighting dokuwiki global scope) 765*04fd306cSNickeau * @param FetcherMarkup $markupHandler 766*04fd306cSNickeau * @return $this 767*04fd306cSNickeau */ 768*04fd306cSNickeau public function setExecutingMarkupHandler(FetcherMarkup $markupHandler): ExecutionContext 769*04fd306cSNickeau { 770*04fd306cSNickeau 771*04fd306cSNickeau 772*04fd306cSNickeau 773*04fd306cSNickeau /** 774*04fd306cSNickeau * Act 775*04fd306cSNickeau */ 776*04fd306cSNickeau $oldAct = $this->getExecutingAction(); 777*04fd306cSNickeau if (!$markupHandler->isPathExecution() && $oldAct !== ExecutionContext::PREVIEW_ACTION) { 778*04fd306cSNickeau /** 779*04fd306cSNickeau * Not sure that is is still needed 780*04fd306cSNickeau * as we have now the notion of document/fragment 781*04fd306cSNickeau * {@link FetcherMarkup::isDocument()} 782*04fd306cSNickeau */ 783*04fd306cSNickeau $runningAct = FetcherMarkup::MARKUP_DYNAMIC_EXECUTION_NAME; 784*04fd306cSNickeau $this->setExecutingAction($runningAct); 785*04fd306cSNickeau } 786*04fd306cSNickeau 787*04fd306cSNickeau /** 788*04fd306cSNickeau * Id 789*04fd306cSNickeau */ 790*04fd306cSNickeau try { 791*04fd306cSNickeau $oldExecutingId = $this->getExecutingWikiId(); 792*04fd306cSNickeau } catch (ExceptionNotFound $e) { 793*04fd306cSNickeau $oldExecutingId = null; 794*04fd306cSNickeau } 795*04fd306cSNickeau try { 796*04fd306cSNickeau 797*04fd306cSNickeau $executingPath = $markupHandler->getRequestedExecutingPath(); 798*04fd306cSNickeau $executingId = $executingPath->toAbsoluteId(); 799*04fd306cSNickeau $this->setExecutingId($executingId); 800*04fd306cSNickeau } catch (ExceptionNotFound $e) { 801*04fd306cSNickeau // no executing path dynamic markup execution 802*04fd306cSNickeau } 803*04fd306cSNickeau 804*04fd306cSNickeau /** 805*04fd306cSNickeau * $INFO (Fragment run, ...) 806*04fd306cSNickeau * We don't use {@link pageinfo()} for now 807*04fd306cSNickeau * We just advertise if this is a fragment run 808*04fd306cSNickeau * via the `id` 809*04fd306cSNickeau */ 810*04fd306cSNickeau global $INFO; 811*04fd306cSNickeau $oldContextId = $INFO['id']; 812*04fd306cSNickeau if ($markupHandler->isFragment()) { 813*04fd306cSNickeau $contextPath = $markupHandler->getRequestedContextPath(); 814*04fd306cSNickeau $INFO['id'] = $contextPath->getWikiId(); 815*04fd306cSNickeau } 816*04fd306cSNickeau 817*04fd306cSNickeau /** 818*04fd306cSNickeau * Call to Fetcher Markup can be recursive, 819*04fd306cSNickeau * we try to break a loop 820*04fd306cSNickeau * 821*04fd306cSNickeau * Note that the same object may call recursively: 822*04fd306cSNickeau * * the {@link FetcherMarkup::processMetaEventually()} metadata may call the {@link FetcherMarkup::getInstructions() instructions}, 823*04fd306cSNickeau */ 824*04fd306cSNickeau $id = $markupHandler->getId(); 825*04fd306cSNickeau if(array_key_exists($id,$this->executingMarkupHandlerStack)){ 826*04fd306cSNickeau LogUtility::internalError("The markup ($id) is already executing"); 827*04fd306cSNickeau $id = "$id-already-in-stack"; 828*04fd306cSNickeau } 829*04fd306cSNickeau $this->executingMarkupHandlerStack[$id] = [$markupHandler, $oldExecutingId, $oldContextId, $oldAct]; 830*04fd306cSNickeau return $this; 831*04fd306cSNickeau } 832*04fd306cSNickeau 833*04fd306cSNickeau public 834*04fd306cSNickeau function closeExecutingMarkupHandler(): ExecutionContext 835*04fd306cSNickeau { 836*04fd306cSNickeau /** @noinspection PhpUnusedLocalVariableInspection */ 837*04fd306cSNickeau [$markupHandler, $oldExecutingId, $oldContextId, $oldAct] = array_pop($this->executingMarkupHandlerStack); 838*04fd306cSNickeau 839*04fd306cSNickeau $this 840*04fd306cSNickeau ->setExecutingAction($oldAct) 841*04fd306cSNickeau ->setExecutingId($oldExecutingId); 842*04fd306cSNickeau 843*04fd306cSNickeau global $INFO; 844*04fd306cSNickeau if ($oldExecutingId === null) { 845*04fd306cSNickeau unset($INFO['id']); 846*04fd306cSNickeau } else { 847*04fd306cSNickeau $INFO['id'] = $oldContextId; 848*04fd306cSNickeau } 849*04fd306cSNickeau return $this; 850*04fd306cSNickeau } 851*04fd306cSNickeau 852*04fd306cSNickeau 853*04fd306cSNickeau /** 854*04fd306cSNickeau * @throws ExceptionNotFound - if there is no markup handler execution running 855*04fd306cSNickeau */ 856*04fd306cSNickeau public 857*04fd306cSNickeau function getExecutingMarkupHandler(): FetcherMarkup 858*04fd306cSNickeau { 859*04fd306cSNickeau $count = count($this->executingMarkupHandlerStack); 860*04fd306cSNickeau if ($count >= 1) { 861*04fd306cSNickeau return $this->executingMarkupHandlerStack[array_key_last($this->executingMarkupHandlerStack)][0]; 862*04fd306cSNickeau } 863*04fd306cSNickeau throw new ExceptionNotFound("No markup handler running"); 864*04fd306cSNickeau } 865*04fd306cSNickeau 866*04fd306cSNickeau /** 867*04fd306cSNickeau * @throws ExceptionNotFound - if there is no parent markup handler execution found 868*04fd306cSNickeau */ 869*04fd306cSNickeau public 870*04fd306cSNickeau function getExecutingParentMarkupHandler(): FetcherMarkup 871*04fd306cSNickeau { 872*04fd306cSNickeau return $this->getExecutingMarkupHandler()->getParent(); 873*04fd306cSNickeau } 874*04fd306cSNickeau 875*04fd306cSNickeau /** 876*04fd306cSNickeau * This function sets the default context path. 877*04fd306cSNickeau * 878*04fd306cSNickeau * Mostly used in test, to determine relative path 879*04fd306cSNickeau * when testing {@link LinkMarkup} and {@link WikiPath} 880*04fd306cSNickeau * and not use a {@link FetcherMarkup} 881*04fd306cSNickeau * 882*04fd306cSNickeau * @param WikiPath $contextPath - a markup file context path used (not a namespace) 883*04fd306cSNickeau * @return $this 884*04fd306cSNickeau * @deprecated 885*04fd306cSNickeau */ 886*04fd306cSNickeau public 887*04fd306cSNickeau function setDefaultContextPath(WikiPath $contextPath): ExecutionContext 888*04fd306cSNickeau { 889*04fd306cSNickeau $this->getConfig()->setDefaultContextPath($contextPath); 890*04fd306cSNickeau return $this; 891*04fd306cSNickeau } 892*04fd306cSNickeau 893*04fd306cSNickeau 894*04fd306cSNickeau /** 895*04fd306cSNickeau * @return WikiPath - the context path is a markup file that gives context. 896*04fd306cSNickeau * Ie this is the equivalent of the current directory. 897*04fd306cSNickeau * When a link/path is empty or relative, the program will check for the context path 898*04fd306cSNickeau * to calculate the absolute path 899*04fd306cSNickeau */ 900*04fd306cSNickeau public 901*04fd306cSNickeau function getContextPath(): WikiPath 902*04fd306cSNickeau { 903*04fd306cSNickeau 904*04fd306cSNickeau try { 905*04fd306cSNickeau 906*04fd306cSNickeau /** 907*04fd306cSNickeau * Do we a fetcher markup running ? 908*04fd306cSNickeau * (It's first as we may change it 909*04fd306cSNickeau * for a slot for instance) 910*04fd306cSNickeau */ 911*04fd306cSNickeau return $this 912*04fd306cSNickeau ->getExecutingMarkupHandler() 913*04fd306cSNickeau ->getRequestedContextPath(); 914*04fd306cSNickeau 915*04fd306cSNickeau } catch (ExceptionNotFound $e) { 916*04fd306cSNickeau try { 917*04fd306cSNickeau 918*04fd306cSNickeau /** 919*04fd306cSNickeau * Do we have a template page executing ? 920*04fd306cSNickeau */ 921*04fd306cSNickeau return $this->getExecutingPageTemplate() 922*04fd306cSNickeau ->getRequestedContextPath(); 923*04fd306cSNickeau 924*04fd306cSNickeau } catch (ExceptionNotFound $e) { 925*04fd306cSNickeau 926*04fd306cSNickeau /** 927*04fd306cSNickeau * Hack, hack, hack 928*04fd306cSNickeau * In preview mode, the context path is the last visited page 929*04fd306cSNickeau * for a slot 930*04fd306cSNickeau */ 931*04fd306cSNickeau global $ACT; 932*04fd306cSNickeau if ($ACT === ExecutionContext::PREVIEW_ACTION) { 933*04fd306cSNickeau global $ID; 934*04fd306cSNickeau if (!empty($ID)) { 935*04fd306cSNickeau try { 936*04fd306cSNickeau $markupPath = MarkupPath::createMarkupFromId($ID); 937*04fd306cSNickeau if ($markupPath->isSlot()) { 938*04fd306cSNickeau return SlotSystem::getContextPath()->toWikiPath(); 939*04fd306cSNickeau } 940*04fd306cSNickeau } catch (ExceptionCast|ExceptionNotFound $e) { 941*04fd306cSNickeau // ok 942*04fd306cSNickeau } 943*04fd306cSNickeau } 944*04fd306cSNickeau } 945*04fd306cSNickeau 946*04fd306cSNickeau /** 947*04fd306cSNickeau * Nope ? This is a dokuwiki run (admin page, ...) 948*04fd306cSNickeau */ 949*04fd306cSNickeau return $this->getConfig()->getDefaultContextPath(); 950*04fd306cSNickeau 951*04fd306cSNickeau } 952*04fd306cSNickeau 953*04fd306cSNickeau } 954*04fd306cSNickeau 955*04fd306cSNickeau 956*04fd306cSNickeau } 957*04fd306cSNickeau 958*04fd306cSNickeau 959*04fd306cSNickeau /** 960*04fd306cSNickeau * @return WikiPath 961*04fd306cSNickeau * @deprecated uses {@link SiteConfig::getDefaultContextPath()} 962*04fd306cSNickeau */ 963*04fd306cSNickeau public 964*04fd306cSNickeau function getDefaultContextPath(): WikiPath 965*04fd306cSNickeau { 966*04fd306cSNickeau return $this->getConfig()->getDefaultContextPath(); 967*04fd306cSNickeau } 968*04fd306cSNickeau 969*04fd306cSNickeau /** 970*04fd306cSNickeau * The page global context object 971*04fd306cSNickeau * @throws ExceptionNotFound 972*04fd306cSNickeau */ 973*04fd306cSNickeau public 974*04fd306cSNickeau function getExecutingPageTemplate(): TemplateForWebPage 975*04fd306cSNickeau { 976*04fd306cSNickeau if (isset($this->executingPageTemplate)) { 977*04fd306cSNickeau return $this->executingPageTemplate; 978*04fd306cSNickeau } 979*04fd306cSNickeau throw new ExceptionNotFound("No page template execution running"); 980*04fd306cSNickeau } 981*04fd306cSNickeau 982*04fd306cSNickeau /** 983*04fd306cSNickeau * Set the page template that is executing. 984*04fd306cSNickeau * It's the context object for all page related 985*04fd306cSNickeau * (mostly header event) 986*04fd306cSNickeau * @param TemplateForWebPage $pageTemplate 987*04fd306cSNickeau * @return $this 988*04fd306cSNickeau */ 989*04fd306cSNickeau public 990*04fd306cSNickeau function setExecutingPageTemplate(TemplateForWebPage $pageTemplate): ExecutionContext 991*04fd306cSNickeau { 992*04fd306cSNickeau $this->executingPageTemplate = $pageTemplate; 993*04fd306cSNickeau return $this; 994*04fd306cSNickeau } 995*04fd306cSNickeau 996*04fd306cSNickeau public 997*04fd306cSNickeau function closeExecutingPageTemplate(): ExecutionContext 998*04fd306cSNickeau { 999*04fd306cSNickeau unset($this->executingPageTemplate); 1000*04fd306cSNickeau return $this; 1001*04fd306cSNickeau } 1002*04fd306cSNickeau 1003*04fd306cSNickeau public 1004*04fd306cSNickeau function getApp(): Site 1005*04fd306cSNickeau { 1006*04fd306cSNickeau if (isset($this->app)) { 1007*04fd306cSNickeau return $this->app; 1008*04fd306cSNickeau } 1009*04fd306cSNickeau $this->app = new Site($this); 1010*04fd306cSNickeau return $this->app; 1011*04fd306cSNickeau } 1012*04fd306cSNickeau 1013*04fd306cSNickeau /** 1014*04fd306cSNickeau * @return SiteConfig short utility function to get access to the global app config 1015*04fd306cSNickeau */ 1016*04fd306cSNickeau public 1017*04fd306cSNickeau function getConfig(): SiteConfig 1018*04fd306cSNickeau { 1019*04fd306cSNickeau return $this->getApp()->getConfig(); 1020*04fd306cSNickeau } 1021*04fd306cSNickeau 1022*04fd306cSNickeau /** 1023*04fd306cSNickeau * @throws ExceptionNotFound - when there is no executing id (markup execution) 1024*04fd306cSNickeau */ 1025*04fd306cSNickeau public 1026*04fd306cSNickeau function getExecutingWikiPath(): WikiPath 1027*04fd306cSNickeau { 1028*04fd306cSNickeau try { 1029*04fd306cSNickeau return $this->getExecutingMarkupHandler() 1030*04fd306cSNickeau ->getRequestedExecutingPath() 1031*04fd306cSNickeau ->toWikiPath(); 1032*04fd306cSNickeau } catch (ExceptionCast|ExceptionNotFound $e) { 1033*04fd306cSNickeau // Execution without templating (ie without fetcher markup) 1034*04fd306cSNickeau return WikiPath::createMarkupPathFromId($this->getExecutingWikiId()); 1035*04fd306cSNickeau } 1036*04fd306cSNickeau 1037*04fd306cSNickeau } 1038*04fd306cSNickeau 1039*04fd306cSNickeau /** 1040*04fd306cSNickeau * @return array - data in context 1041*04fd306cSNickeau * This is the central point to get data in context as there is no 1042*04fd306cSNickeau * content object in dokuwiki 1043*04fd306cSNickeau * 1044*04fd306cSNickeau * It takes care of returning the context path 1045*04fd306cSNickeau * (in case of slot via the {@link self::getContextPath()} 1046*04fd306cSNickeau */ 1047*04fd306cSNickeau public 1048*04fd306cSNickeau function getContextData(): array 1049*04fd306cSNickeau { 1050*04fd306cSNickeau 1051*04fd306cSNickeau try { 1052*04fd306cSNickeau 1053*04fd306cSNickeau /** 1054*04fd306cSNickeau * Context data may be dynamically given 1055*04fd306cSNickeau * by the {@link \syntax_plugin_combo_iterator} 1056*04fd306cSNickeau */ 1057*04fd306cSNickeau return $this 1058*04fd306cSNickeau ->getExecutingMarkupHandler() 1059*04fd306cSNickeau ->getContextData(); 1060*04fd306cSNickeau 1061*04fd306cSNickeau } catch (ExceptionNotFound $e) { 1062*04fd306cSNickeau 1063*04fd306cSNickeau /** 1064*04fd306cSNickeau * Preview / slot 1065*04fd306cSNickeau */ 1066*04fd306cSNickeau return MarkupPath::createPageFromPathObject($this->getContextPath())->getMetadataForRendering(); 1067*04fd306cSNickeau 1068*04fd306cSNickeau } 1069*04fd306cSNickeau 1070*04fd306cSNickeau } 1071*04fd306cSNickeau 1072*04fd306cSNickeau /** 1073*04fd306cSNickeau * This method will delete the global identifier 1074*04fd306cSNickeau * and call the 'close' method if the method exists. 1075*04fd306cSNickeau * @param string $globalObjectIdentifier 1076*04fd306cSNickeau * @return void 1077*04fd306cSNickeau */ 1078*04fd306cSNickeau public 1079*04fd306cSNickeau function closeAndRemoveRuntimeVariableIfExists(string $globalObjectIdentifier) 1080*04fd306cSNickeau { 1081*04fd306cSNickeau 1082*04fd306cSNickeau if (!isset($this->executionScopedVariables[$globalObjectIdentifier])) { 1083*04fd306cSNickeau return; 1084*04fd306cSNickeau } 1085*04fd306cSNickeau 1086*04fd306cSNickeau /** 1087*04fd306cSNickeau * Get the object references 1088*04fd306cSNickeau */ 1089*04fd306cSNickeau $object = &$this->executionScopedVariables[$globalObjectIdentifier]; 1090*04fd306cSNickeau 1091*04fd306cSNickeau 1092*04fd306cSNickeau /** 1093*04fd306cSNickeau * Call the close method 1094*04fd306cSNickeau */ 1095*04fd306cSNickeau if (is_object($object)) { 1096*04fd306cSNickeau if (method_exists($object, 'close')) { 1097*04fd306cSNickeau $object->close(); 1098*04fd306cSNickeau } 1099*04fd306cSNickeau } 1100*04fd306cSNickeau 1101*04fd306cSNickeau /** 1102*04fd306cSNickeau * Close it really by setting null 1103*04fd306cSNickeau * 1104*04fd306cSNickeau * (Forwhatever reason, sqlite closing in php 1105*04fd306cSNickeau * is putting the variable to null) 1106*04fd306cSNickeau */ 1107*04fd306cSNickeau $object = null; 1108*04fd306cSNickeau 1109*04fd306cSNickeau /** 1110*04fd306cSNickeau * Delete it from the array 1111*04fd306cSNickeau */ 1112*04fd306cSNickeau unset($this->executionScopedVariables[$globalObjectIdentifier]); 1113*04fd306cSNickeau 1114*04fd306cSNickeau } 1115*04fd306cSNickeau 1116*04fd306cSNickeau /** 1117*04fd306cSNickeau * Close all execution variables 1118*04fd306cSNickeau */ 1119*04fd306cSNickeau public 1120*04fd306cSNickeau function closeExecutionVariables(): ExecutionContext 1121*04fd306cSNickeau { 1122*04fd306cSNickeau $scopedVariables = array_keys($this->executionScopedVariables); 1123*04fd306cSNickeau foreach ($scopedVariables as $executionScopedVariableKey) { 1124*04fd306cSNickeau $this->closeAndRemoveRuntimeVariableIfExists($executionScopedVariableKey); 1125*04fd306cSNickeau } 1126*04fd306cSNickeau return $this; 1127*04fd306cSNickeau } 1128*04fd306cSNickeau 1129*04fd306cSNickeau public 1130*04fd306cSNickeau function __toString() 1131*04fd306cSNickeau { 1132*04fd306cSNickeau return $this->creationTime; 1133*04fd306cSNickeau } 1134*04fd306cSNickeau 1135*04fd306cSNickeau public 1136*04fd306cSNickeau function isExecutingPageTemplate(): bool 1137*04fd306cSNickeau { 1138*04fd306cSNickeau try { 1139*04fd306cSNickeau $this->getExecutingPageTemplate(); 1140*04fd306cSNickeau return true; 1141*04fd306cSNickeau } catch (ExceptionNotFound $e) { 1142*04fd306cSNickeau return false; 1143*04fd306cSNickeau } 1144*04fd306cSNickeau } 1145*04fd306cSNickeau 1146*04fd306cSNickeau public 1147*04fd306cSNickeau function hasExecutingMarkupHandler(): bool 1148*04fd306cSNickeau { 1149*04fd306cSNickeau try { 1150*04fd306cSNickeau $this->getExecutingMarkupHandler(); 1151*04fd306cSNickeau return true; 1152*04fd306cSNickeau } catch (ExceptionNotFound $e) { 1153*04fd306cSNickeau return false; 1154*04fd306cSNickeau } 1155*04fd306cSNickeau } 1156*04fd306cSNickeau 1157*04fd306cSNickeau 1158*04fd306cSNickeau} 1159