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