104fd306cSNickeau<?php 204fd306cSNickeau 304fd306cSNickeaunamespace ComboStrap; 404fd306cSNickeau 504fd306cSNickeau 604fd306cSNickeauuse ComboStrap\Meta\Store\MetadataDbStore; 704fd306cSNickeauuse ComboStrap\Meta\Store\MetadataDokuWikiStore; 804fd306cSNickeauuse ComboStrap\Tag\WebCodeTag; 904fd306cSNickeauuse ComboStrap\Web\Url; 1004fd306cSNickeauuse dokuwiki\ActionRouter; 1104fd306cSNickeauuse dokuwiki\Extension\EventHandler; 1204fd306cSNickeauuse TestRequest; 1304fd306cSNickeau 1404fd306cSNickeau 1504fd306cSNickeau/** 1604fd306cSNickeau * An execution object permits to manage the variable state for 1704fd306cSNickeau * an execution (ie one HTTP request) 1804fd306cSNickeau * 1904fd306cSNickeau * 2004fd306cSNickeau * Note that normally every page has a page context 2104fd306cSNickeau * meaning that you can go from an admin page to show the page. 2204fd306cSNickeau * 2304fd306cSNickeau * 2404fd306cSNickeau * When an execution context has finished, it should be {@link ExecutionContext::close() closed} 2504fd306cSNickeau * or destroyed 2604fd306cSNickeau * 2704fd306cSNickeau * You can get the actual execution context with {@link ExecutionContext::getActualOrCreateFromEnv()} 2804fd306cSNickeau * 2904fd306cSNickeau * 3004fd306cSNickeau * Same concept than [routing context](https://vertx.io/docs/apidocs/index.html?io/vertx/ext/web/RoutingContext.html) 3104fd306cSNickeau * (Not yet fully implemented) 3204fd306cSNickeau * ```java 3304fd306cSNickeau * if (pet.isPresent()) 3404fd306cSNickeau * routingContext 3504fd306cSNickeau * .response() 3604fd306cSNickeau * .setStatusCode(200) 3704fd306cSNickeau * .putHeader(HttpHeaders.CONTENT_TYPE, "application/json") 3804fd306cSNickeau * .end(pet.get().encode()); // (4) 3904fd306cSNickeau * else 4004fd306cSNickeau * routingContext.fail(404, new Exception("Pet not found")); 4104fd306cSNickeau * } 4204fd306cSNickeau * ``` 4304fd306cSNickeau */ 4404fd306cSNickeauclass ExecutionContext 4504fd306cSNickeau{ 4604fd306cSNickeau 4704fd306cSNickeau /** 4804fd306cSNickeau * Dokuwiki do attribute 4904fd306cSNickeau */ 5004fd306cSNickeau const DO_ATTRIBUTE = "do"; 5104fd306cSNickeau 5204fd306cSNickeau 5304fd306cSNickeau const CANONICAL = "execution-context"; 5404fd306cSNickeau 5504fd306cSNickeau /** 5604fd306cSNickeau * All action (handler) 5704fd306cSNickeau * That's what you will found in the `do` parameters 5804fd306cSNickeau */ 5904fd306cSNickeau const SHOW_ACTION = "show"; 6004fd306cSNickeau const EDIT_ACTION = "edit"; 6104fd306cSNickeau /** 6204fd306cSNickeau * Preview is also used to 6304fd306cSNickeau * set the {@link FetcherMarkup::isFragment()} 6404fd306cSNickeau * processing to fragment 6504fd306cSNickeau */ 6604fd306cSNickeau const PREVIEW_ACTION = "preview"; 6704fd306cSNickeau const ADMIN_ACTION = "admin"; 6804fd306cSNickeau const DRAFT_ACTION = "draft"; 6904fd306cSNickeau const SEARCH_ACTION = "search"; 7004fd306cSNickeau const LOGIN_ACTION = "login"; 7104fd306cSNickeau const SAVE_ACTION = "save"; 7204fd306cSNickeau const DRAFT_DEL_ACTION = "draftdel"; 7304fd306cSNickeau const REDIRECT_ACTION = "redirect"; 7404fd306cSNickeau 7504fd306cSNickeau /** 7604fd306cSNickeau * private actions does not render a page to be indexed 7704fd306cSNickeau * by a search engine (ie no redirect) 7804fd306cSNickeau * May be easier, if not `show`, not public 7904fd306cSNickeau */ 8004fd306cSNickeau const PRIVATES_ACTION_NO_REDIRECT = [ 8104fd306cSNickeau self::EDIT_ACTION, 8204fd306cSNickeau self::PREVIEW_ACTION, 8304fd306cSNickeau self::ADMIN_ACTION, 8404fd306cSNickeau self::DRAFT_ACTION, 8504fd306cSNickeau self::DRAFT_DEL_ACTION, 8604fd306cSNickeau self::SEARCH_ACTION, 8704fd306cSNickeau self::LOGIN_ACTION, 8804fd306cSNickeau self::SAVE_ACTION, 8904fd306cSNickeau self::REDIRECT_ACTION, 9004fd306cSNickeau self::REGISTER_ACTION, 9104fd306cSNickeau self::RESEND_PWD_ACTION, 9204fd306cSNickeau self::PROFILE_ACTION, 9304fd306cSNickeau ]; 9404fd306cSNickeau const REGISTER_ACTION = "register"; 9504fd306cSNickeau const RESEND_PWD_ACTION = "resendpwd"; 9604fd306cSNickeau const PROFILE_ACTION = "profile"; 9704fd306cSNickeau const REVISIONS_ACTION = "revisions"; 9804fd306cSNickeau const DIFF_ACTION = "diff"; 9904fd306cSNickeau const INDEX_ACTION = "index"; 10004fd306cSNickeau 101*49b8fb24Sgerardnico /** 102*49b8fb24Sgerardnico * The media manager 103*49b8fb24Sgerardnico */ 104*49b8fb24Sgerardnico const MEDIA_ACTION = "media"; 105*49b8fb24Sgerardnico /** 106*49b8fb24Sgerardnico * The recent changes 107*49b8fb24Sgerardnico */ 108*49b8fb24Sgerardnico const RECENT_ACTION = "recent"; 109*49b8fb24Sgerardnico 11004fd306cSNickeau 11104fd306cSNickeau /** 11204fd306cSNickeau * @var array of objects that are scoped to this request 11304fd306cSNickeau */ 11404fd306cSNickeau private array $executionScopedVariables = []; 11504fd306cSNickeau 11604fd306cSNickeau private CacheManager $cacheManager; 11704fd306cSNickeau 11870bbd7f1Sgerardnico private IdManager $idManager; 11970bbd7f1Sgerardnico 12004fd306cSNickeau private Site $app; 12104fd306cSNickeau 12204fd306cSNickeau /** 12304fd306cSNickeau * A root execution context if any 12404fd306cSNickeau * Null because you can not unset a static variable 12504fd306cSNickeau */ 12604fd306cSNickeau private static ?ExecutionContext $actualExecutionContext = null; 12704fd306cSNickeau 12804fd306cSNickeau private ?string $capturedGlobalId; 12904fd306cSNickeau /** 13004fd306cSNickeau * It may be an array when preview/save/cancel 13104fd306cSNickeau * @var array|string|null 13204fd306cSNickeau */ 13304fd306cSNickeau private $capturedAct; 13404fd306cSNickeau 13504fd306cSNickeau 13604fd306cSNickeau private Url $url; 13704fd306cSNickeau 13804fd306cSNickeau 13904fd306cSNickeau public HttpResponse $response; 14004fd306cSNickeau 14104fd306cSNickeau /** 14204fd306cSNickeau * @var IFetcher - the fetcher that takes into account the HTTP request 14304fd306cSNickeau */ 14404fd306cSNickeau private IFetcher $executingMainFetcher; 14504fd306cSNickeau 14604fd306cSNickeau /** 14704fd306cSNickeau * @var array - a stack of: 14804fd306cSNickeau * * markup handler executing (ie handler that is taking a markup (file, string) and making it a HTML, pdf, ...) 14904fd306cSNickeau * * and old global environement, $executingId, $contextExecutingId, $act 15004fd306cSNickeau * 15104fd306cSNickeau * This fetcher is called by the main fetcher or by the {@link self::setExecutingMarkupHandler()} 15204fd306cSNickeau */ 15304fd306cSNickeau private array $executingMarkupHandlerStack = []; 15404fd306cSNickeau 15504fd306cSNickeau /** 15604fd306cSNickeau * @var TemplateForWebPage - the page template fetcher running (when a fetcher creates a page, it would uses this fetcher) 15704fd306cSNickeau * This class is called by the main fetcher to create a page 15804fd306cSNickeau */ 15904fd306cSNickeau private TemplateForWebPage $executingPageTemplate; 16004fd306cSNickeau private string $creationTime; 16104fd306cSNickeau 16204fd306cSNickeau 16304fd306cSNickeau public function __construct() 16404fd306cSNickeau { 16504fd306cSNickeau 16604fd306cSNickeau $this->creationTime = Iso8601Date::createFromNow()->toIsoStringMs(); 16704fd306cSNickeau 16804fd306cSNickeau $this->url = Url::createFromGetOrPostGlobalVariable(); 16904fd306cSNickeau 17004fd306cSNickeau $this->response = HttpResponse::createFromExecutionContext($this); 17104fd306cSNickeau 17204fd306cSNickeau /** 17304fd306cSNickeau * The requested action 17404fd306cSNickeau */ 17504fd306cSNickeau global $ACT; 17604fd306cSNickeau $this->capturedAct = $ACT; 17704fd306cSNickeau try { 17804fd306cSNickeau $urlAct = $this->url->getQueryPropertyValue(self::DO_ATTRIBUTE); 17904fd306cSNickeau } catch (ExceptionNotFound $e) { 18004fd306cSNickeau /** 18104fd306cSNickeau * The value is unknown 18204fd306cSNickeau * (in doku.php, the default is `show`, 18304fd306cSNickeau * we take the dokuwiki value because the execution context may be 18404fd306cSNickeau * created after the dokuwiki init) 18504fd306cSNickeau */ 18604fd306cSNickeau $urlAct = $ACT; 18704fd306cSNickeau } 18804fd306cSNickeau $ACT = $urlAct; 18904fd306cSNickeau 19004fd306cSNickeau /** 19104fd306cSNickeau * The requested id 19204fd306cSNickeau */ 19304fd306cSNickeau global $ID; 19404fd306cSNickeau $this->capturedGlobalId = $ID; 19504fd306cSNickeau try { 19604fd306cSNickeau 19704fd306cSNickeau $urlId = $this->url->getQueryPropertyValue(DokuwikiId::DOKUWIKI_ID_ATTRIBUTE); 19804fd306cSNickeau if (is_array($urlId)) { 19904fd306cSNickeau /** 20004fd306cSNickeau * hack because the dokuwiki request global object as `ID` and `id` as array 20104fd306cSNickeau * but our own {@link Url object} don't allow that and makes an array instead 20204fd306cSNickeau * We don't use this data anyway, anymore ... 20304fd306cSNickeau */ 20404fd306cSNickeau $urlId = $urlId[0]; 20504fd306cSNickeau } 20604fd306cSNickeau $ID = $urlId; 20704fd306cSNickeau 20804fd306cSNickeau } catch (ExceptionNotFound $e) { 20904fd306cSNickeau // none 21004fd306cSNickeau $ID = null; 21104fd306cSNickeau } 21204fd306cSNickeau 21304fd306cSNickeau 21404fd306cSNickeau } 21504fd306cSNickeau 21604fd306cSNickeau 21704fd306cSNickeau /** 21804fd306cSNickeau * @throws ExceptionNotFound 21904fd306cSNickeau */ 22004fd306cSNickeau public static function getExecutionContext(): ExecutionContext 22104fd306cSNickeau { 22204fd306cSNickeau if (!isset(self::$actualExecutionContext)) { 22304fd306cSNickeau throw new ExceptionNotFound("No root context"); 22404fd306cSNickeau } 22504fd306cSNickeau return self::$actualExecutionContext; 22604fd306cSNickeau } 22704fd306cSNickeau 22804fd306cSNickeau /** 22904fd306cSNickeau * Utility class to set the requested id (used only in test, 23004fd306cSNickeau * normally the environment is set from global PHP environment variable 23104fd306cSNickeau * that get the HTTP request 23204fd306cSNickeau * @param string $requestedId 23304fd306cSNickeau * @return ExecutionContext 23404fd306cSNickeau * @deprecated use {@link self::setDefaultContextPath()} if you want to set a context path 23504fd306cSNickeau * without using a {@link TemplateForWebPage} or {@link FetcherMarkup} 23604fd306cSNickeau */ 23704fd306cSNickeau public static function getOrCreateFromRequestedWikiId(string $requestedId): ExecutionContext 23804fd306cSNickeau { 23904fd306cSNickeau 24004fd306cSNickeau return self::getActualOrCreateFromEnv() 24104fd306cSNickeau ->setDefaultContextPath(WikiPath::createMarkupPathFromId($requestedId)); 24204fd306cSNickeau 24304fd306cSNickeau } 24404fd306cSNickeau 24504fd306cSNickeau 24604fd306cSNickeau /** 24704fd306cSNickeau * @return ExecutionContext 24804fd306cSNickeau * @deprecated uses {@link self::createBlank()} instead 24904fd306cSNickeau */ 25004fd306cSNickeau public static function createFromEnvironmentVariable(): ExecutionContext 25104fd306cSNickeau { 25204fd306cSNickeau return self::createBlank(); 25304fd306cSNickeau } 25404fd306cSNickeau 25504fd306cSNickeau 25604fd306cSNickeau public static function createBlank(): ExecutionContext 25704fd306cSNickeau { 25804fd306cSNickeau 25904fd306cSNickeau if (self::$actualExecutionContext !== null) { 26004fd306cSNickeau throw new ExceptionRuntimeInternal("The previous root context should be closed first"); 26104fd306cSNickeau } 26204fd306cSNickeau $rootExecutionContext = (new ExecutionContext()); 26304fd306cSNickeau self::$actualExecutionContext = $rootExecutionContext; 26404fd306cSNickeau return $rootExecutionContext; 26504fd306cSNickeau 26604fd306cSNickeau } 26704fd306cSNickeau 26804fd306cSNickeau /** 26904fd306cSNickeau * @return ExecutionContext - return the actual context or create a new one from the environment 27004fd306cSNickeau */ 27104fd306cSNickeau public static function getActualOrCreateFromEnv(): ExecutionContext 27204fd306cSNickeau { 27304fd306cSNickeau try { 27404fd306cSNickeau return self::getExecutionContext(); 27504fd306cSNickeau } catch (ExceptionNotFound $e) { 27604fd306cSNickeau return self::createBlank(); 27704fd306cSNickeau } 27804fd306cSNickeau } 27904fd306cSNickeau 28004fd306cSNickeau /** 28104fd306cSNickeau * We create the id manager in the execution 28204fd306cSNickeau * context 28304fd306cSNickeau * (because in case a user choose to not use templating, the {@link FetcherMarkup} 28404fd306cSNickeau * is not available) 28504fd306cSNickeau * And all dynamic component such as {@link \syntax_plugin_combo_dropdown} would not 28604fd306cSNickeau * work anymore. 28704fd306cSNickeau * 28804fd306cSNickeau * @return IdManager 28904fd306cSNickeau */ 29004fd306cSNickeau public function getIdManager(): IdManager 29104fd306cSNickeau { 29204fd306cSNickeau if (!isset($this->idManager)) { 29304fd306cSNickeau $this->idManager = new IdManager($this); 29404fd306cSNickeau } 29504fd306cSNickeau return $this->idManager; 29604fd306cSNickeau } 29704fd306cSNickeau 29804fd306cSNickeau /** 29904fd306cSNickeau * Return the actual context path 30004fd306cSNickeau */ 30104fd306cSNickeau public function getContextNamespacePath(): WikiPath 30204fd306cSNickeau { 30304fd306cSNickeau $requestedPath = $this->getContextPath(); 30404fd306cSNickeau try { 30504fd306cSNickeau return $requestedPath->getParent(); 30604fd306cSNickeau } catch (ExceptionNotFound $e) { 30704fd306cSNickeau // root 30804fd306cSNickeau return $requestedPath; 30904fd306cSNickeau } 31004fd306cSNickeau 31104fd306cSNickeau } 31204fd306cSNickeau 31304fd306cSNickeau 31404fd306cSNickeau /** 31504fd306cSNickeau * @throws ExceptionNotFound 31604fd306cSNickeau */ 31704fd306cSNickeau public function getExecutingWikiId(): string 31804fd306cSNickeau { 31904fd306cSNickeau global $ID; 32004fd306cSNickeau if (empty($ID)) { 32104fd306cSNickeau throw new ExceptionNotFound("No executing id was found"); 32204fd306cSNickeau } 32304fd306cSNickeau return $ID; 32404fd306cSNickeau } 32504fd306cSNickeau 32604fd306cSNickeau 32704fd306cSNickeau /** 32804fd306cSNickeau * @return void close the execution context 32904fd306cSNickeau */ 33004fd306cSNickeau public function close() 33104fd306cSNickeau { 33204fd306cSNickeau 33304fd306cSNickeau /** 33404fd306cSNickeau * Check that this execution context was not closed 33504fd306cSNickeau */ 33604fd306cSNickeau if (self::$actualExecutionContext->creationTime !== $this->creationTime) { 33704fd306cSNickeau throw new ExceptionRuntimeInternal("This execution context was already closed"); 33804fd306cSNickeau } 33904fd306cSNickeau 34004fd306cSNickeau /** 34104fd306cSNickeau * Restore the global $conf of dokuwiki 34204fd306cSNickeau */ 34304fd306cSNickeau $this->getApp()->getConfig()->restoreConfigState(); 34404fd306cSNickeau 34504fd306cSNickeau /** global dokuwiki messages variable */ 34604fd306cSNickeau global $MSG; 34704fd306cSNickeau unset($MSG); 34804fd306cSNickeau 34904fd306cSNickeau /** 35004fd306cSNickeau * Environment restoration 35104fd306cSNickeau * Execution context, change for now only this 35204fd306cSNickeau * global variables 35304fd306cSNickeau */ 35404fd306cSNickeau global $ACT; 35504fd306cSNickeau $ACT = $this->getCapturedAct(); 35604fd306cSNickeau global $ID; 35704fd306cSNickeau $ID = $this->getCapturedRunningId(); 35804fd306cSNickeau global $TOC; 35904fd306cSNickeau unset($TOC); 36004fd306cSNickeau 36104fd306cSNickeau // global scope store 36204fd306cSNickeau MetadataDbStore::resetAll(); 36304fd306cSNickeau MetadataDokuWikiStore::unsetGlobalVariables(); 36404fd306cSNickeau 36504fd306cSNickeau // Router: dokuwiki global 36604fd306cSNickeau // reset event handler 36704fd306cSNickeau global $EVENT_HANDLER; 36804fd306cSNickeau $EVENT_HANDLER = new EventHandler(); 36904fd306cSNickeau /** 37004fd306cSNickeau * We can't give the getInstance, a true value 37104fd306cSNickeau * because it will otherwise start the routing process 37204fd306cSNickeau * {@link ActionRouter::getInstance()} 37304fd306cSNickeau */ 37404fd306cSNickeau 37504fd306cSNickeau 37604fd306cSNickeau /** 37704fd306cSNickeau * Close execution variables 37804fd306cSNickeau * (and therefore also {@link Sqlite} 37904fd306cSNickeau */ 38004fd306cSNickeau $this->closeExecutionVariables(); 38104fd306cSNickeau 38204fd306cSNickeau /** 38304fd306cSNickeau * Is this really needed ? 38404fd306cSNickeau * as we unset the execution context below 38504fd306cSNickeau */ 38604fd306cSNickeau unset($this->executingMainFetcher); 38704fd306cSNickeau unset($this->executingMarkupHandlerStack); 38804fd306cSNickeau unset($this->cacheManager); 38904fd306cSNickeau unset($this->idManager); 39004fd306cSNickeau 39104fd306cSNickeau /** 39204fd306cSNickeau * Deleting 39304fd306cSNickeau */ 39404fd306cSNickeau self::$actualExecutionContext = null; 39504fd306cSNickeau 39604fd306cSNickeau 39704fd306cSNickeau } 39804fd306cSNickeau 39904fd306cSNickeau 40004fd306cSNickeau public function getCapturedRunningId(): ?string 40104fd306cSNickeau { 40204fd306cSNickeau return $this->capturedGlobalId; 40304fd306cSNickeau } 40404fd306cSNickeau 40504fd306cSNickeau public function getCapturedAct() 40604fd306cSNickeau { 40704fd306cSNickeau return $this->capturedAct; 40804fd306cSNickeau } 40904fd306cSNickeau 41004fd306cSNickeau public function getCacheManager(): CacheManager 41104fd306cSNickeau { 41204fd306cSNickeau $root = self::$actualExecutionContext; 41304fd306cSNickeau if (!isset($root->cacheManager)) { 41404fd306cSNickeau $root->cacheManager = new CacheManager($this); 41504fd306cSNickeau } 41604fd306cSNickeau return $root->cacheManager; 41704fd306cSNickeau 41804fd306cSNickeau } 41904fd306cSNickeau 42004fd306cSNickeau /** 42104fd306cSNickeau * Return the root path if nothing is found 42204fd306cSNickeau */ 42304fd306cSNickeau public function getRequestedPath(): WikiPath 42404fd306cSNickeau { 42504fd306cSNickeau /** 42604fd306cSNickeau * Do we have a template page executing ? 42704fd306cSNickeau */ 42804fd306cSNickeau try { 42904fd306cSNickeau return $this->getExecutingPageTemplate() 43004fd306cSNickeau ->getRequestedContextPath(); 43104fd306cSNickeau } catch (ExceptionNotFound $e) { 43204fd306cSNickeau try { 43304fd306cSNickeau /** 43404fd306cSNickeau * Case when the main handler 43504fd306cSNickeau * run the main content before 43604fd306cSNickeau * to inject it in the template page 43704fd306cSNickeau * {@link TemplateForWebPage::render()} 43804fd306cSNickeau */ 43904fd306cSNickeau return $this->getExecutingMarkupHandler() 44004fd306cSNickeau ->getRequestedContextPath(); 44104fd306cSNickeau } catch (ExceptionNotFound $e) { 44204fd306cSNickeau 44304fd306cSNickeau 44404fd306cSNickeau /** 44504fd306cSNickeau * not a template engine running 44604fd306cSNickeau * The id notion is a little bit everywhere 44704fd306cSNickeau * That's why we just don't check the action ($ACT) 44804fd306cSNickeau * 44904fd306cSNickeau * Example: 45004fd306cSNickeau * * `id` may be asked by acl to determine the right 45104fd306cSNickeau * * ... 45204fd306cSNickeau */ 45304fd306cSNickeau global $INPUT; 45404fd306cSNickeau $inputId = $INPUT->str("id"); 45504fd306cSNickeau if (!empty($inputId)) { 45604fd306cSNickeau return WikiPath::createMarkupPathFromId($inputId); 45704fd306cSNickeau } 45804fd306cSNickeau 45904fd306cSNickeau global $ID; 46004fd306cSNickeau if (!empty($ID)) { 46104fd306cSNickeau return WikiPath::createMarkupPathFromId($ID); 46204fd306cSNickeau } 46304fd306cSNickeau 46404fd306cSNickeau /** 46504fd306cSNickeau * This should be less used 46604fd306cSNickeau * but shows where the requested id is spilled in dokuwiki 46704fd306cSNickeau * 46804fd306cSNickeau * If the component is in a sidebar, we don't want the ID of the sidebar 46904fd306cSNickeau * but the ID of the page. 47004fd306cSNickeau */ 47104fd306cSNickeau global $INFO; 47204fd306cSNickeau if ($INFO !== null) { 47370bbd7f1Sgerardnico $callingId = $INFO['id'] ?? null; 47404fd306cSNickeau if (!empty($callingId)) { 47504fd306cSNickeau return WikiPath::createMarkupPathFromId($callingId); 47604fd306cSNickeau } 47704fd306cSNickeau } 47804fd306cSNickeau 47904fd306cSNickeau /** 48004fd306cSNickeau * This is the case with event triggered 48104fd306cSNickeau * before DokuWiki such as 48204fd306cSNickeau * https://www.dokuwiki.org/devel:event:init_lang_load 48304fd306cSNickeau * REQUEST is a mixed of post and get parameters 48404fd306cSNickeau */ 48504fd306cSNickeau global $_REQUEST; 48604fd306cSNickeau if (isset($_REQUEST[DokuwikiId::DOKUWIKI_ID_ATTRIBUTE])) { 48704fd306cSNickeau $requestId = $_REQUEST[DokuwikiId::DOKUWIKI_ID_ATTRIBUTE]; 48804fd306cSNickeau if (!empty($requestId)) { 48904fd306cSNickeau return WikiPath::createMarkupPathFromId($requestId); 49004fd306cSNickeau } 49104fd306cSNickeau } 49204fd306cSNickeau 49304fd306cSNickeau // not that show action is the default even if it's not set 49404fd306cSNickeau // we can't then control if the id should exists or not 49504fd306cSNickeau // markup based on string (test) or snippet of code 49604fd306cSNickeau // return the default context path (ie the root page) 49704fd306cSNickeau return $this->getConfig()->getDefaultContextPath(); 49804fd306cSNickeau } 49904fd306cSNickeau 50004fd306cSNickeau } 50104fd306cSNickeau 50204fd306cSNickeau } 50304fd306cSNickeau 50404fd306cSNickeau /** 50504fd306cSNickeau * @throws ExceptionNotFound 50604fd306cSNickeau */ 50704fd306cSNickeau public function &getRuntimeObject(string $objectIdentifier) 50804fd306cSNickeau { 50904fd306cSNickeau if (isset($this->executionScopedVariables[$objectIdentifier])) { 51004fd306cSNickeau return $this->executionScopedVariables[$objectIdentifier]; 51104fd306cSNickeau } 51204fd306cSNickeau throw new ExceptionNotFound("No object $objectIdentifier found"); 51304fd306cSNickeau } 51404fd306cSNickeau 51504fd306cSNickeau public function setRuntimeObject($objectIdentifier, &$object): ExecutionContext 51604fd306cSNickeau { 51704fd306cSNickeau $this->executionScopedVariables[$objectIdentifier] = &$object; 51804fd306cSNickeau return $this; 51904fd306cSNickeau } 52004fd306cSNickeau 52104fd306cSNickeau public function getUrl(): Url 52204fd306cSNickeau { 52304fd306cSNickeau return $this->url; 52404fd306cSNickeau } 52504fd306cSNickeau 52604fd306cSNickeau 52704fd306cSNickeau /** 52804fd306cSNickeau * @param string $key 52904fd306cSNickeau * @param $value 53004fd306cSNickeau * @param string|null $pluginNamespace - if null, stored in the global conf namespace 53104fd306cSNickeau * @return $this 53204fd306cSNickeau * @deprecated use {@link SiteConfig::setConf()} instead 53304fd306cSNickeau */ 53404fd306cSNickeau public function setConf(string $key, $value, ?string $pluginNamespace = PluginUtility::PLUGIN_BASE_NAME): ExecutionContext 53504fd306cSNickeau { 53604fd306cSNickeau $this->getApp()->getConfig()->setConf($key, $value, $pluginNamespace); 53704fd306cSNickeau return $this; 53804fd306cSNickeau } 53904fd306cSNickeau 54004fd306cSNickeau /** 54104fd306cSNickeau * @param string $key 54204fd306cSNickeau * @param string|null $default 54304fd306cSNickeau * @return mixed|null 54404fd306cSNickeau * @deprecated use 54504fd306cSNickeau */ 54604fd306cSNickeau public function getConfValue(string $key, string $default = null) 54704fd306cSNickeau { 54804fd306cSNickeau return $this->getApp()->getConfig()->getValue($key, $default); 54904fd306cSNickeau } 55004fd306cSNickeau 55104fd306cSNickeau public function setRuntimeBoolean(string $key, bool $b): ExecutionContext 55204fd306cSNickeau { 55304fd306cSNickeau $this->executionScopedVariables[$key] = $b; 55404fd306cSNickeau return $this; 55504fd306cSNickeau } 55604fd306cSNickeau 55704fd306cSNickeau /** 55804fd306cSNickeau * @throws ExceptionNotFound 55904fd306cSNickeau */ 56004fd306cSNickeau public function getRuntimeBoolean(string $name): bool 56104fd306cSNickeau { 56270bbd7f1Sgerardnico $var = $this->executionScopedVariables[$name] ?? null; 56304fd306cSNickeau if (!isset($var)) { 56404fd306cSNickeau throw new ExceptionNotFound("No $name runtime env was found"); 56504fd306cSNickeau } 56604fd306cSNickeau return DataType::toBoolean($var); 56704fd306cSNickeau } 56804fd306cSNickeau 56904fd306cSNickeau /** 57004fd306cSNickeau * @return $this 57104fd306cSNickeau * @deprecated uses {@link SiteConfig::setCacheXhtmlOn()} 57204fd306cSNickeau */ 57304fd306cSNickeau public function setCacheXhtmlOn(): ExecutionContext 57404fd306cSNickeau { 57504fd306cSNickeau $this->getApp()->getConfig()->setCacheXhtmlOn(); 57604fd306cSNickeau return $this; 57704fd306cSNickeau } 57804fd306cSNickeau 57904fd306cSNickeau /** 58004fd306cSNickeau * 58104fd306cSNickeau * @return $this 58204fd306cSNickeau * @deprecated use the {@link SiteConfig::setConsoleOn} instead 58304fd306cSNickeau */ 58404fd306cSNickeau public function setConsoleOn(): ExecutionContext 58504fd306cSNickeau { 58604fd306cSNickeau $this->getApp()->getConfig()->setCacheXhtmlOn(); 58704fd306cSNickeau return $this; 58804fd306cSNickeau } 58904fd306cSNickeau 59004fd306cSNickeau public function setConsoleOff(): ExecutionContext 59104fd306cSNickeau { 59204fd306cSNickeau $this->getConfig()->setConsoleOff(); 59304fd306cSNickeau return $this; 59404fd306cSNickeau } 59504fd306cSNickeau 59604fd306cSNickeau /** 59704fd306cSNickeau * @return $this 59804fd306cSNickeau * @deprecated use {@link SiteConfig::setDisableThemeSystem()} 59904fd306cSNickeau */ 60004fd306cSNickeau public function setDisableTemplating(): ExecutionContext 60104fd306cSNickeau { 60204fd306cSNickeau $this->getApp()->getConfig()->setDisableThemeSystem(); 60304fd306cSNickeau return $this; 60404fd306cSNickeau } 60504fd306cSNickeau 60604fd306cSNickeau 60704fd306cSNickeau /** 60804fd306cSNickeau * @return bool 60904fd306cSNickeau * @deprecated use the {@link SiteConfig::isConsoleOn()} instead 61004fd306cSNickeau */ 61104fd306cSNickeau public function isConsoleOn(): bool 61204fd306cSNickeau { 61304fd306cSNickeau return $this->getApp()->getConfig()->isConsoleOn(); 61404fd306cSNickeau } 61504fd306cSNickeau 61604fd306cSNickeau 61704fd306cSNickeau /** 61804fd306cSNickeau * Dokuwiki handler name 61904fd306cSNickeau * @return array|mixed|string 62004fd306cSNickeau */ 62104fd306cSNickeau public function getExecutingAction() 62204fd306cSNickeau { 62304fd306cSNickeau global $ACT; 62404fd306cSNickeau return $ACT; 62504fd306cSNickeau } 62604fd306cSNickeau 62704fd306cSNickeau public function setLogExceptionToError(): ExecutionContext 62804fd306cSNickeau { 62904fd306cSNickeau $this->getConfig()->setLogExceptionToError(); 63004fd306cSNickeau return $this; 63104fd306cSNickeau } 63204fd306cSNickeau 63304fd306cSNickeau /** 63404fd306cSNickeau * @return SnippetSystem 63504fd306cSNickeau * It's not attached to the {@link FetcherMarkup} 63604fd306cSNickeau * because the user may choose to not use it (ie {@link SiteConfig::isThemeSystemEnabled()} 63704fd306cSNickeau */ 63804fd306cSNickeau public function getSnippetSystem(): SnippetSystem 63904fd306cSNickeau { 64004fd306cSNickeau return SnippetSystem::getFromContext(); 64104fd306cSNickeau } 64204fd306cSNickeau 64304fd306cSNickeau /** 64404fd306cSNickeau * @return bool - does the action create a publication (render a page) 64504fd306cSNickeau */ 64604fd306cSNickeau public function isPublicationAction(): bool 64704fd306cSNickeau { 64804fd306cSNickeau 64904fd306cSNickeau $act = $this->getExecutingAction(); 65004fd306cSNickeau if (in_array($act, self::PRIVATES_ACTION_NO_REDIRECT)) { 65104fd306cSNickeau return false; 65204fd306cSNickeau } 65304fd306cSNickeau 65404fd306cSNickeau return true; 65504fd306cSNickeau 65604fd306cSNickeau } 65704fd306cSNickeau 65804fd306cSNickeau public function setEnableSectionEditing(): ExecutionContext 65904fd306cSNickeau { 66004fd306cSNickeau $this->setConf('maxseclevel', 999, null); 66104fd306cSNickeau return $this; 66204fd306cSNickeau } 66304fd306cSNickeau 66404fd306cSNickeau /** 66504fd306cSNickeau * @param string $value 66604fd306cSNickeau * @return $this 66704fd306cSNickeau * @deprecated use the {@link SiteConfig::setCanonicalUrlType()} instead 66804fd306cSNickeau */ 66904fd306cSNickeau public function setCanonicalUrlType(string $value): ExecutionContext 67004fd306cSNickeau { 67104fd306cSNickeau $this->getConfig()->setCanonicalUrlType($value); 67204fd306cSNickeau return $this; 67304fd306cSNickeau } 67404fd306cSNickeau 67504fd306cSNickeau public function setUseHeadingAsTitle(): ExecutionContext 67604fd306cSNickeau { 67704fd306cSNickeau // https://www.dokuwiki.org/config:useheading 67804fd306cSNickeau $this->setConf('useheading', 1, null); 67904fd306cSNickeau return $this; 68004fd306cSNickeau } 68104fd306cSNickeau 68204fd306cSNickeau public function response(): HttpResponse 68304fd306cSNickeau { 68404fd306cSNickeau return $this->response; 68504fd306cSNickeau } 68604fd306cSNickeau 68704fd306cSNickeau /** 68804fd306cSNickeau * @param string|null $executingId 68904fd306cSNickeau * @return void 69004fd306cSNickeau */ 69104fd306cSNickeau private function setExecutingId(?string $executingId): void 69204fd306cSNickeau { 69304fd306cSNickeau global $ID; 69404fd306cSNickeau if ($executingId == null) { 69504fd306cSNickeau // ID should not be null 69604fd306cSNickeau // to be able to check the ACL 69704fd306cSNickeau return; 69804fd306cSNickeau } 69904fd306cSNickeau $executingId = WikiPath::removeRootSepIfPresent($executingId); 70004fd306cSNickeau $ID = $executingId; 70104fd306cSNickeau } 70204fd306cSNickeau 70304fd306cSNickeau public function setConfGlobal(string $key, string $value): ExecutionContext 70404fd306cSNickeau { 70504fd306cSNickeau $this->setConf($key, $value, null); 70604fd306cSNickeau return $this; 70704fd306cSNickeau } 70804fd306cSNickeau 70904fd306cSNickeau /** 71004fd306cSNickeau * @return bool - if this execution is a test running 71104fd306cSNickeau */ 71204fd306cSNickeau public function isTestRun(): bool 71304fd306cSNickeau { 71404fd306cSNickeau /** 71504fd306cSNickeau * Test Requested is loaded only in a test run 71604fd306cSNickeau * Does not exist in a normal installation 71704fd306cSNickeau * and is not found, triggering an exception 71804fd306cSNickeau */ 71904fd306cSNickeau if (class_exists('TestRequest')) { 72004fd306cSNickeau $testRequest = TestRequest::getRunning(); 72104fd306cSNickeau return $testRequest !== null; 72204fd306cSNickeau } 72304fd306cSNickeau return false; 72404fd306cSNickeau 72504fd306cSNickeau } 72604fd306cSNickeau 72704fd306cSNickeau private function setExecutingAction(?string $runningAct): ExecutionContext 72804fd306cSNickeau { 72904fd306cSNickeau global $ACT; 73004fd306cSNickeau $ACT = $runningAct; 73104fd306cSNickeau return $this; 73204fd306cSNickeau } 73304fd306cSNickeau 73404fd306cSNickeau 73504fd306cSNickeau /** 73604fd306cSNickeau * Set the main fetcher, the entry point of the request (ie the url of the browser) 73704fd306cSNickeau * that will return a string 73804fd306cSNickeau * @throws ExceptionBadArgument 73904fd306cSNickeau * @throws ExceptionInternal 74004fd306cSNickeau * @throws ExceptionNotFound 74104fd306cSNickeau */ 74204fd306cSNickeau public function createStringMainFetcherFromRequestedUrl(Url $fetchUrl): IFetcherString 74304fd306cSNickeau { 74404fd306cSNickeau $this->executingMainFetcher = FetcherSystem::createFetcherStringFromUrl($fetchUrl); 74504fd306cSNickeau return $this->executingMainFetcher; 74604fd306cSNickeau } 74704fd306cSNickeau 74804fd306cSNickeau 74904fd306cSNickeau /** 75004fd306cSNickeau * Set the main fetcher (with the url of the browser) 75104fd306cSNickeau * that will return a path (image, ...) 75204fd306cSNickeau * @throws ExceptionBadArgument 75304fd306cSNickeau * @throws ExceptionInternal 75404fd306cSNickeau * @throws ExceptionNotFound 75504fd306cSNickeau */ 75604fd306cSNickeau public function createPathMainFetcherFromUrl(Url $fetchUrl): IFetcherPath 75704fd306cSNickeau { 75804fd306cSNickeau $this->executingMainFetcher = FetcherSystem::createPathFetcherFromUrl($fetchUrl); 75904fd306cSNickeau return $this->executingMainFetcher; 76004fd306cSNickeau } 76104fd306cSNickeau 76204fd306cSNickeau public function closeMainExecutingFetcher(): ExecutionContext 76304fd306cSNickeau { 76404fd306cSNickeau unset($this->executingMainFetcher); 76504fd306cSNickeau /** 76604fd306cSNickeau * Snippet are not yet fully coupled to the {@link FetcherMarkup} 76704fd306cSNickeau */ 76804fd306cSNickeau $this->closeAndRemoveRuntimeVariableIfExists(Snippet::CANONICAL); 76904fd306cSNickeau return $this; 77004fd306cSNickeau } 77104fd306cSNickeau 77204fd306cSNickeau /** 77304fd306cSNickeau * This function sets the markup running context object globally, 77404fd306cSNickeau * so that code may access it via this global variable 77504fd306cSNickeau * (Fighting dokuwiki global scope) 77604fd306cSNickeau * @param FetcherMarkup $markupHandler 77704fd306cSNickeau * @return $this 77804fd306cSNickeau */ 77904fd306cSNickeau public function setExecutingMarkupHandler(FetcherMarkup $markupHandler): ExecutionContext 78004fd306cSNickeau { 78104fd306cSNickeau 78204fd306cSNickeau 78304fd306cSNickeau /** 78404fd306cSNickeau * Act 78504fd306cSNickeau */ 78604fd306cSNickeau $oldAct = $this->getExecutingAction(); 78704fd306cSNickeau if (!$markupHandler->isPathExecution() && $oldAct !== ExecutionContext::PREVIEW_ACTION) { 78804fd306cSNickeau /** 78904fd306cSNickeau * Not sure that is is still needed 79004fd306cSNickeau * as we have now the notion of document/fragment 79104fd306cSNickeau * {@link FetcherMarkup::isDocument()} 79204fd306cSNickeau */ 79304fd306cSNickeau $runningAct = FetcherMarkup::MARKUP_DYNAMIC_EXECUTION_NAME; 79404fd306cSNickeau $this->setExecutingAction($runningAct); 79504fd306cSNickeau } 79604fd306cSNickeau 79704fd306cSNickeau /** 79804fd306cSNickeau * Id 79904fd306cSNickeau */ 80004fd306cSNickeau try { 80104fd306cSNickeau $oldExecutingId = $this->getExecutingWikiId(); 80204fd306cSNickeau } catch (ExceptionNotFound $e) { 80304fd306cSNickeau $oldExecutingId = null; 80404fd306cSNickeau } 80504fd306cSNickeau try { 80604fd306cSNickeau 80704fd306cSNickeau $executingPath = $markupHandler->getRequestedExecutingPath(); 80804fd306cSNickeau $executingId = $executingPath->toAbsoluteId(); 80904fd306cSNickeau $this->setExecutingId($executingId); 81004fd306cSNickeau } catch (ExceptionNotFound $e) { 81104fd306cSNickeau // no executing path dynamic markup execution 81204fd306cSNickeau } 81304fd306cSNickeau 81404fd306cSNickeau /** 81504fd306cSNickeau * $INFO (Fragment run, ...) 81604fd306cSNickeau * We don't use {@link pageinfo()} for now 81704fd306cSNickeau * We just advertise if this is a fragment run 81804fd306cSNickeau * via the `id` 81904fd306cSNickeau */ 82004fd306cSNickeau global $INFO; 82194bd6462Sgerardnico $oldContextId = $INFO['id'] ?? null; 82204fd306cSNickeau if ($markupHandler->isFragment()) { 82304fd306cSNickeau $contextPath = $markupHandler->getRequestedContextPath(); 82470bbd7f1Sgerardnico $wikiId = $contextPath->getWikiId(); 82570bbd7f1Sgerardnico $INFO['id'] = $wikiId; 82670bbd7f1Sgerardnico $INFO['namespace'] = getNS($wikiId); // php8 Undefined array key 82704fd306cSNickeau } 82804fd306cSNickeau 82904fd306cSNickeau /** 83004fd306cSNickeau * Call to Fetcher Markup can be recursive, 83104fd306cSNickeau * we try to break a loop 83204fd306cSNickeau * 83304fd306cSNickeau * Note that the same object may call recursively: 83404fd306cSNickeau * * the {@link FetcherMarkup::processMetaEventually()} metadata may call the {@link FetcherMarkup::getInstructions() instructions}, 83504fd306cSNickeau */ 83604fd306cSNickeau $id = $markupHandler->getId(); 83704fd306cSNickeau if (array_key_exists($id, $this->executingMarkupHandlerStack)) { 83804fd306cSNickeau LogUtility::internalError("The markup ($id) is already executing"); 83904fd306cSNickeau $id = "$id-already-in-stack"; 84004fd306cSNickeau } 84104fd306cSNickeau $this->executingMarkupHandlerStack[$id] = [$markupHandler, $oldExecutingId, $oldContextId, $oldAct]; 84204fd306cSNickeau return $this; 84304fd306cSNickeau } 84404fd306cSNickeau 84504fd306cSNickeau public 84604fd306cSNickeau function closeExecutingMarkupHandler(): ExecutionContext 84704fd306cSNickeau { 84804fd306cSNickeau /** @noinspection PhpUnusedLocalVariableInspection */ 84904fd306cSNickeau [$markupHandler, $oldExecutingId, $oldContextId, $oldAct] = array_pop($this->executingMarkupHandlerStack); 85004fd306cSNickeau 85104fd306cSNickeau $this 85204fd306cSNickeau ->setExecutingAction($oldAct) 85304fd306cSNickeau ->setExecutingId($oldExecutingId); 85404fd306cSNickeau 85504fd306cSNickeau global $INFO; 85604fd306cSNickeau if ($oldExecutingId === null) { 85704fd306cSNickeau unset($INFO['id']); 85804fd306cSNickeau } else { 85904fd306cSNickeau $INFO['id'] = $oldContextId; 86070bbd7f1Sgerardnico $INFO['namespace'] = getNS($oldContextId); 86104fd306cSNickeau } 86204fd306cSNickeau return $this; 86304fd306cSNickeau } 86404fd306cSNickeau 86504fd306cSNickeau 86604fd306cSNickeau /** 86704fd306cSNickeau * @throws ExceptionNotFound - if there is no markup handler execution running 86804fd306cSNickeau */ 86904fd306cSNickeau public 87004fd306cSNickeau function getExecutingMarkupHandler(): FetcherMarkup 87104fd306cSNickeau { 87204fd306cSNickeau $count = count($this->executingMarkupHandlerStack); 87304fd306cSNickeau if ($count >= 1) { 87404fd306cSNickeau return $this->executingMarkupHandlerStack[array_key_last($this->executingMarkupHandlerStack)][0]; 87504fd306cSNickeau } 87604fd306cSNickeau throw new ExceptionNotFound("No markup handler running"); 87704fd306cSNickeau } 87804fd306cSNickeau 87904fd306cSNickeau /** 88004fd306cSNickeau * @throws ExceptionNotFound - if there is no parent markup handler execution found 88104fd306cSNickeau */ 88204fd306cSNickeau public 88304fd306cSNickeau function getExecutingParentMarkupHandler(): FetcherMarkup 88404fd306cSNickeau { 88504fd306cSNickeau return $this->getExecutingMarkupHandler()->getParent(); 88604fd306cSNickeau } 88704fd306cSNickeau 88804fd306cSNickeau /** 88904fd306cSNickeau * This function sets the default context path. 89004fd306cSNickeau * 89104fd306cSNickeau * Mostly used in test, to determine relative path 89204fd306cSNickeau * when testing {@link LinkMarkup} and {@link WikiPath} 89304fd306cSNickeau * and not use a {@link FetcherMarkup} 89404fd306cSNickeau * 89504fd306cSNickeau * @param WikiPath $contextPath - a markup file context path used (not a namespace) 89604fd306cSNickeau * @return $this 89704fd306cSNickeau * @deprecated 89804fd306cSNickeau */ 89904fd306cSNickeau public 90004fd306cSNickeau function setDefaultContextPath(WikiPath $contextPath): ExecutionContext 90104fd306cSNickeau { 90204fd306cSNickeau $this->getConfig()->setDefaultContextPath($contextPath); 90304fd306cSNickeau return $this; 90404fd306cSNickeau } 90504fd306cSNickeau 90604fd306cSNickeau 90704fd306cSNickeau /** 90804fd306cSNickeau * @return WikiPath - the context path is a markup file that gives context. 90904fd306cSNickeau * Ie this is the equivalent of the current directory. 91004fd306cSNickeau * When a link/path is empty or relative, the program will check for the context path 91104fd306cSNickeau * to calculate the absolute path 91204fd306cSNickeau */ 91304fd306cSNickeau public 91404fd306cSNickeau function getContextPath(): WikiPath 91504fd306cSNickeau { 91604fd306cSNickeau 91704fd306cSNickeau try { 91804fd306cSNickeau 91904fd306cSNickeau /** 92004fd306cSNickeau * Do we a fetcher markup running ? 92104fd306cSNickeau * (It's first as we may change it 92204fd306cSNickeau * for a slot for instance) 92304fd306cSNickeau */ 92404fd306cSNickeau return $this 92504fd306cSNickeau ->getExecutingMarkupHandler() 92604fd306cSNickeau ->getRequestedContextPath(); 92704fd306cSNickeau 92804fd306cSNickeau } catch (ExceptionNotFound $e) { 92904fd306cSNickeau try { 93004fd306cSNickeau 93104fd306cSNickeau /** 93204fd306cSNickeau * Do we have a template page executing ? 93304fd306cSNickeau */ 93404fd306cSNickeau return $this->getExecutingPageTemplate() 93504fd306cSNickeau ->getRequestedContextPath(); 93604fd306cSNickeau 93704fd306cSNickeau } catch (ExceptionNotFound $e) { 93804fd306cSNickeau 93904fd306cSNickeau /** 94004fd306cSNickeau * Hack, hack, hack 94104fd306cSNickeau * In preview mode, the context path is the last visited page 94204fd306cSNickeau * for a slot 94304fd306cSNickeau */ 94404fd306cSNickeau global $ACT; 94504fd306cSNickeau if ($ACT === ExecutionContext::PREVIEW_ACTION) { 94604fd306cSNickeau global $ID; 94704fd306cSNickeau if (!empty($ID)) { 94804fd306cSNickeau try { 94904fd306cSNickeau $markupPath = MarkupPath::createMarkupFromId($ID); 95004fd306cSNickeau if ($markupPath->isSlot()) { 95104fd306cSNickeau return SlotSystem::getContextPath()->toWikiPath(); 95204fd306cSNickeau } 95304fd306cSNickeau } catch (ExceptionCast|ExceptionNotFound $e) { 95404fd306cSNickeau // ok 95504fd306cSNickeau } 95604fd306cSNickeau } 95704fd306cSNickeau } 95804fd306cSNickeau 95904fd306cSNickeau /** 96004fd306cSNickeau * Nope ? This is a dokuwiki run (admin page, ...) 96104fd306cSNickeau */ 96204fd306cSNickeau return $this->getConfig()->getDefaultContextPath(); 96304fd306cSNickeau 96404fd306cSNickeau } 96504fd306cSNickeau 96604fd306cSNickeau } 96704fd306cSNickeau 96804fd306cSNickeau 96904fd306cSNickeau } 97004fd306cSNickeau 97104fd306cSNickeau 97204fd306cSNickeau /** 97304fd306cSNickeau * @return WikiPath 97404fd306cSNickeau * @deprecated uses {@link SiteConfig::getDefaultContextPath()} 97504fd306cSNickeau */ 97604fd306cSNickeau public 97704fd306cSNickeau function getDefaultContextPath(): WikiPath 97804fd306cSNickeau { 97904fd306cSNickeau return $this->getConfig()->getDefaultContextPath(); 98004fd306cSNickeau } 98104fd306cSNickeau 98204fd306cSNickeau /** 98304fd306cSNickeau * The page global context object 98404fd306cSNickeau * @throws ExceptionNotFound 98504fd306cSNickeau */ 98604fd306cSNickeau public 98704fd306cSNickeau function getExecutingPageTemplate(): TemplateForWebPage 98804fd306cSNickeau { 98904fd306cSNickeau if (isset($this->executingPageTemplate)) { 99004fd306cSNickeau return $this->executingPageTemplate; 99104fd306cSNickeau } 99204fd306cSNickeau throw new ExceptionNotFound("No page template execution running"); 99304fd306cSNickeau } 99404fd306cSNickeau 99504fd306cSNickeau /** 99604fd306cSNickeau * Set the page template that is executing. 99704fd306cSNickeau * It's the context object for all page related 99804fd306cSNickeau * (mostly header event) 99904fd306cSNickeau * @param TemplateForWebPage $pageTemplate 100004fd306cSNickeau * @return $this 100104fd306cSNickeau */ 100204fd306cSNickeau public 100304fd306cSNickeau function setExecutingPageTemplate(TemplateForWebPage $pageTemplate): ExecutionContext 100404fd306cSNickeau { 100504fd306cSNickeau $this->executingPageTemplate = $pageTemplate; 100604fd306cSNickeau return $this; 100704fd306cSNickeau } 100804fd306cSNickeau 100904fd306cSNickeau public 101004fd306cSNickeau function closeExecutingPageTemplate(): ExecutionContext 101104fd306cSNickeau { 101204fd306cSNickeau unset($this->executingPageTemplate); 101304fd306cSNickeau return $this; 101404fd306cSNickeau } 101504fd306cSNickeau 101604fd306cSNickeau public 101704fd306cSNickeau function getApp(): Site 101804fd306cSNickeau { 101904fd306cSNickeau if (isset($this->app)) { 102004fd306cSNickeau return $this->app; 102104fd306cSNickeau } 102204fd306cSNickeau $this->app = new Site($this); 102304fd306cSNickeau return $this->app; 102404fd306cSNickeau } 102504fd306cSNickeau 102604fd306cSNickeau /** 102704fd306cSNickeau * @return SiteConfig short utility function to get access to the global app config 102804fd306cSNickeau */ 102904fd306cSNickeau public 103004fd306cSNickeau function getConfig(): SiteConfig 103104fd306cSNickeau { 103204fd306cSNickeau return $this->getApp()->getConfig(); 103304fd306cSNickeau } 103404fd306cSNickeau 103504fd306cSNickeau /** 103604fd306cSNickeau * @throws ExceptionNotFound - when there is no executing id (markup execution) 103704fd306cSNickeau */ 103804fd306cSNickeau public 103904fd306cSNickeau function getExecutingWikiPath(): WikiPath 104004fd306cSNickeau { 104104fd306cSNickeau try { 104204fd306cSNickeau return $this->getExecutingMarkupHandler() 104304fd306cSNickeau ->getRequestedExecutingPath() 104404fd306cSNickeau ->toWikiPath(); 104504fd306cSNickeau } catch (ExceptionCast|ExceptionNotFound $e) { 104604fd306cSNickeau // Execution without templating (ie without fetcher markup) 104704fd306cSNickeau return WikiPath::createMarkupPathFromId($this->getExecutingWikiId()); 104804fd306cSNickeau } 104904fd306cSNickeau 105004fd306cSNickeau } 105104fd306cSNickeau 105204fd306cSNickeau /** 105304fd306cSNickeau * @return array - data in context 105404fd306cSNickeau * This is the central point to get data in context as there is no 105504fd306cSNickeau * content object in dokuwiki 105604fd306cSNickeau * 105704fd306cSNickeau * It takes care of returning the context path 105804fd306cSNickeau * (in case of slot via the {@link self::getContextPath()} 105904fd306cSNickeau */ 106004fd306cSNickeau public 106104fd306cSNickeau function getContextData(): array 106204fd306cSNickeau { 106304fd306cSNickeau 106404fd306cSNickeau try { 106504fd306cSNickeau 106604fd306cSNickeau /** 106704fd306cSNickeau * Context data may be dynamically given 106804fd306cSNickeau * by the {@link \syntax_plugin_combo_iterator} 106904fd306cSNickeau */ 107004fd306cSNickeau return $this 107104fd306cSNickeau ->getExecutingMarkupHandler() 107204fd306cSNickeau ->getContextData(); 107304fd306cSNickeau 107404fd306cSNickeau } catch (ExceptionNotFound $e) { 107504fd306cSNickeau 107604fd306cSNickeau /** 107704fd306cSNickeau * Preview / slot 107804fd306cSNickeau */ 107904fd306cSNickeau return MarkupPath::createPageFromPathObject($this->getContextPath())->getMetadataForRendering(); 108004fd306cSNickeau 108104fd306cSNickeau } 108204fd306cSNickeau 108304fd306cSNickeau } 108404fd306cSNickeau 108504fd306cSNickeau /** 108604fd306cSNickeau * This method will delete the global identifier 108704fd306cSNickeau * and call the 'close' method if the method exists. 108804fd306cSNickeau * @param string $globalObjectIdentifier 108904fd306cSNickeau * @return void 109004fd306cSNickeau */ 109104fd306cSNickeau public 109204fd306cSNickeau function closeAndRemoveRuntimeVariableIfExists(string $globalObjectIdentifier) 109304fd306cSNickeau { 109404fd306cSNickeau 109504fd306cSNickeau if (!isset($this->executionScopedVariables[$globalObjectIdentifier])) { 109604fd306cSNickeau return; 109704fd306cSNickeau } 109804fd306cSNickeau 109904fd306cSNickeau /** 110004fd306cSNickeau * Get the object references 110104fd306cSNickeau */ 110204fd306cSNickeau $object = &$this->executionScopedVariables[$globalObjectIdentifier]; 110304fd306cSNickeau 110404fd306cSNickeau 110504fd306cSNickeau /** 110604fd306cSNickeau * Call the close method 110704fd306cSNickeau */ 110804fd306cSNickeau if (is_object($object)) { 110904fd306cSNickeau if (method_exists($object, 'close')) { 111004fd306cSNickeau $object->close(); 111104fd306cSNickeau } 111204fd306cSNickeau } 111304fd306cSNickeau 111404fd306cSNickeau /** 111504fd306cSNickeau * Close it really by setting null 111604fd306cSNickeau * 111704fd306cSNickeau * (Forwhatever reason, sqlite closing in php 111804fd306cSNickeau * is putting the variable to null) 111904fd306cSNickeau */ 112004fd306cSNickeau $object = null; 112104fd306cSNickeau 112204fd306cSNickeau /** 112304fd306cSNickeau * Delete it from the array 112404fd306cSNickeau */ 112504fd306cSNickeau unset($this->executionScopedVariables[$globalObjectIdentifier]); 112604fd306cSNickeau 112704fd306cSNickeau } 112804fd306cSNickeau 112904fd306cSNickeau /** 113004fd306cSNickeau * Close all execution variables 113104fd306cSNickeau */ 113204fd306cSNickeau public 113304fd306cSNickeau function closeExecutionVariables(): ExecutionContext 113404fd306cSNickeau { 113504fd306cSNickeau $scopedVariables = array_keys($this->executionScopedVariables); 113604fd306cSNickeau foreach ($scopedVariables as $executionScopedVariableKey) { 113704fd306cSNickeau $this->closeAndRemoveRuntimeVariableIfExists($executionScopedVariableKey); 113804fd306cSNickeau } 113904fd306cSNickeau return $this; 114004fd306cSNickeau } 114104fd306cSNickeau 114204fd306cSNickeau public 114304fd306cSNickeau function __toString() 114404fd306cSNickeau { 114504fd306cSNickeau return $this->creationTime; 114604fd306cSNickeau } 114704fd306cSNickeau 114804fd306cSNickeau public 114904fd306cSNickeau function isExecutingPageTemplate(): bool 115004fd306cSNickeau { 115104fd306cSNickeau try { 115204fd306cSNickeau $this->getExecutingPageTemplate(); 115304fd306cSNickeau return true; 115404fd306cSNickeau } catch (ExceptionNotFound $e) { 115504fd306cSNickeau return false; 115604fd306cSNickeau } 115704fd306cSNickeau } 115804fd306cSNickeau 115904fd306cSNickeau public 116004fd306cSNickeau function hasExecutingMarkupHandler(): bool 116104fd306cSNickeau { 116204fd306cSNickeau try { 116304fd306cSNickeau $this->getExecutingMarkupHandler(); 116404fd306cSNickeau return true; 116504fd306cSNickeau } catch (ExceptionNotFound $e) { 116604fd306cSNickeau return false; 116704fd306cSNickeau } 116804fd306cSNickeau } 116904fd306cSNickeau 117004fd306cSNickeau 117104fd306cSNickeau} 1172