104fd306cSNickeau<?php 204fd306cSNickeau 304fd306cSNickeaunamespace ComboStrap; 404fd306cSNickeau 504fd306cSNickeau 604fd306cSNickeauuse ComboStrap\Meta\Field\PageTemplateName; 704fd306cSNickeauuse ComboStrap\Web\Url; 804fd306cSNickeau 904fd306cSNickeau/** 1004fd306cSNickeau * Bundle page from the same namespace 1104fd306cSNickeau * with {@link FetcherPageBundler::getBundledOutline() corrected outline} 1204fd306cSNickeau * 1304fd306cSNickeau * From a wiki app, just add: `?do=combo_pagebundler` 1404fd306cSNickeau * 1504fd306cSNickeau */ 1604fd306cSNickeauclass FetcherPageBundler extends IFetcherAbs implements IFetcherString 1704fd306cSNickeau{ 1804fd306cSNickeau 1904fd306cSNickeau use FetcherTraitWikiPath; 2004fd306cSNickeau 2104fd306cSNickeau const CANONICAL = self::NAME; 2204fd306cSNickeau const NAME = "pagebundler"; 23*7dbcdecdSNico private ?Outline $bundledOutline = null; 2404fd306cSNickeau 2504fd306cSNickeau public static function createPageBundler(): FetcherPageBundler 2604fd306cSNickeau { 2704fd306cSNickeau return new FetcherPageBundler(); 2804fd306cSNickeau } 2904fd306cSNickeau 3004fd306cSNickeau public function buildFromUrl(Url $url): FetcherPageBundler 3104fd306cSNickeau { 3204fd306cSNickeau /** 3304fd306cSNickeau * Just to return the good type 3404fd306cSNickeau */ 3504fd306cSNickeau parent::buildFromUrl($url); 3604fd306cSNickeau return $this; 3704fd306cSNickeau } 3804fd306cSNickeau 3904fd306cSNickeau /** 4004fd306cSNickeau * @throws ExceptionBadArgument 4104fd306cSNickeau * @throws ExceptionBadSyntax 4204fd306cSNickeau * @throws ExceptionNotExists 4304fd306cSNickeau * @throws ExceptionNotFound 4404fd306cSNickeau */ 4504fd306cSNickeau public function buildFromTagAttributes(TagAttributes $tagAttributes): FetcherPageBundler 4604fd306cSNickeau { 4704fd306cSNickeau parent::buildFromTagAttributes($tagAttributes); 4804fd306cSNickeau $this->buildOriginalPathFromTagAttributes($tagAttributes); 4904fd306cSNickeau return $this; 5004fd306cSNickeau } 5104fd306cSNickeau 5204fd306cSNickeau 5304fd306cSNickeau function getBuster(): string 5404fd306cSNickeau { 5504fd306cSNickeau return ""; 5604fd306cSNickeau } 5704fd306cSNickeau 5804fd306cSNickeau /** 5904fd306cSNickeau * @return Mime 6004fd306cSNickeau */ 6104fd306cSNickeau public function getMime(): Mime 6204fd306cSNickeau { 6304fd306cSNickeau return Mime::getHtml(); 6404fd306cSNickeau } 6504fd306cSNickeau 6604fd306cSNickeau public function getFetcherName(): string 6704fd306cSNickeau { 6804fd306cSNickeau return self::NAME; 6904fd306cSNickeau } 7004fd306cSNickeau 7104fd306cSNickeau public function getFetchString(): string 7204fd306cSNickeau { 7304fd306cSNickeau 7404fd306cSNickeau $outline = $this->getBundledOutline(); 7504fd306cSNickeau $instructionsCalls = $outline->toHtmlSectionOutlineCalls(); 7604fd306cSNickeau $mainContent = MarkupRenderer::createFromInstructions($instructionsCalls) 7704fd306cSNickeau ->setRequestedExecutingPath($this->getStartPath()) 7804fd306cSNickeau ->setRequestedContextPath($this->getRequestedContextPath()) 7904fd306cSNickeau ->setRequestedMime($this->getMime()) 8004fd306cSNickeau ->getOutput(); 8104fd306cSNickeau 8204fd306cSNickeau 8304fd306cSNickeau $startMarkup = $this->getStartPath(); 8404fd306cSNickeau $title = PageTitle::createForMarkup($startMarkup)->getValueOrDefault(); 8504fd306cSNickeau $lang = Lang::createForMarkup($startMarkup); 8604fd306cSNickeau try { 8704fd306cSNickeau $startMarkupWikiPath = WikiPath::createFromPathObject($startMarkup->getPathObject()); 8804fd306cSNickeau } catch (ExceptionBadArgument $e) { 8904fd306cSNickeau /** 9004fd306cSNickeau * should not happen as this class accepts only wiki path as {@link FetcherPageBundler::setContextPath() context path} 9104fd306cSNickeau */ 9204fd306cSNickeau throw new ExceptionRuntimeInternal("We were unable to get the start markup wiki path. Error:{$e->getMessage()}", self::CANONICAL); 9304fd306cSNickeau } 9404fd306cSNickeau 9504fd306cSNickeau $layoutName = PageTemplateName::BLANK_TEMPLATE_VALUE; 9604fd306cSNickeau try { 9704fd306cSNickeau $toc = Toc::createEmpty() 9804fd306cSNickeau ->setValue($this->getBundledOutline()->toTocDokuwikiFormat()); 9904fd306cSNickeau } catch (ExceptionBadArgument $e) { 10004fd306cSNickeau // this is an array 10104fd306cSNickeau throw new ExceptionRuntimeInternal("The toc could not be created. Error:{$e->getMessage()}", self::CANONICAL, 1, $e); 10204fd306cSNickeau } 10304fd306cSNickeau try { 10404fd306cSNickeau return TemplateForWebPage::create() 10504fd306cSNickeau ->setRequestedTemplateName($layoutName) 10604fd306cSNickeau ->setRequestedContextPath($startMarkupWikiPath) 10704fd306cSNickeau ->setRequestedTitle($title) 10804fd306cSNickeau ->setRequestedLang($lang) 10904fd306cSNickeau ->setToc($toc) 11004fd306cSNickeau ->setIsSocial(false) 11104fd306cSNickeau ->setRequestedEnableTaskRunner(false) 11204fd306cSNickeau ->setMainContent($mainContent) 11304fd306cSNickeau ->render(); 11404fd306cSNickeau } catch (ExceptionBadSyntax|ExceptionNotFound|ExceptionBadArgument $e) { 11504fd306cSNickeau // layout should be good 11604fd306cSNickeau throw new ExceptionRuntimeInternal("The $layoutName template returns an error", self::CANONICAL, 1, $e); 11704fd306cSNickeau } 11804fd306cSNickeau 11904fd306cSNickeau 12004fd306cSNickeau } 12104fd306cSNickeau 12204fd306cSNickeau public function getBundledOutline(): Outline 12304fd306cSNickeau { 12404fd306cSNickeau 12504fd306cSNickeau if (isset($this->bundledOutline)) { 12604fd306cSNickeau return $this->bundledOutline; 12704fd306cSNickeau } 12804fd306cSNickeau 12904fd306cSNickeau $startPath = $this->getStartPath(); 130*7dbcdecdSNico $actualLevel = 0; 131*7dbcdecdSNico $this->buildOutlineRecursive($startPath,$actualLevel); 13204fd306cSNickeau 13304fd306cSNickeau return $this->bundledOutline; 13404fd306cSNickeau 13504fd306cSNickeau } 13604fd306cSNickeau 13704fd306cSNickeau /** 13804fd306cSNickeau * The path from where the bundle should start 13904fd306cSNickeau * If this is not an index markup, the index markup will be chosen {@link FetcherPageBundler::getStartPath()} 14004fd306cSNickeau * 14104fd306cSNickeau * @throws ExceptionBadArgument - if the path is not a {@link WikiPath web path} 14204fd306cSNickeau */ 14304fd306cSNickeau public function setContextPath(Path $requestedPath): FetcherPageBundler 14404fd306cSNickeau { 14504fd306cSNickeau $this->setSourcePath(WikiPath::createFromPathObject($requestedPath)); 14604fd306cSNickeau return $this; 14704fd306cSNickeau } 14804fd306cSNickeau 14904fd306cSNickeau private function getRequestedContextPath(): WikiPath 15004fd306cSNickeau { 15104fd306cSNickeau return $this->getSourcePath(); 15204fd306cSNickeau } 15304fd306cSNickeau 15404fd306cSNickeau 15504fd306cSNickeau /** 15604fd306cSNickeau * 15704fd306cSNickeau * @return MarkupPath The index path or the request path is none 15804fd306cSNickeau * 15904fd306cSNickeau */ 16004fd306cSNickeau private function getStartPath(): MarkupPath 16104fd306cSNickeau { 16204fd306cSNickeau $requestedPath = MarkupPath::createPageFromPathObject($this->getRequestedContextPath()); 16304fd306cSNickeau if ($requestedPath->isIndexPage()) { 16404fd306cSNickeau return $requestedPath; 16504fd306cSNickeau } 16604fd306cSNickeau try { 16704fd306cSNickeau /** 16804fd306cSNickeau * Parent is an index path in the {@link MarkupFileSystem} 16904fd306cSNickeau */ 17004fd306cSNickeau return $requestedPath->getParent(); 17104fd306cSNickeau } catch (ExceptionNotFound $e) { 17204fd306cSNickeau // home markup case (should not happen - home page is a index page) 17304fd306cSNickeau return $requestedPath; 17404fd306cSNickeau } 17504fd306cSNickeau 17604fd306cSNickeau } 17704fd306cSNickeau 17804fd306cSNickeau /** 17904fd306cSNickeau * If a page does not have any h1 18004fd306cSNickeau * (Case of index page for instance) 18104fd306cSNickeau * 18204fd306cSNickeau * If this is the case, the outline is broken. 18304fd306cSNickeau * @param Outline $outline 18404fd306cSNickeau * @return Outline 18504fd306cSNickeau */ 18604fd306cSNickeau private function addFirstSectionIfMissing(Outline $outline): Outline 18704fd306cSNickeau { 18804fd306cSNickeau $rootOutlineSection = $outline->getRootOutlineSection(); 18904fd306cSNickeau $addFirstSection = false; 19004fd306cSNickeau try { 19104fd306cSNickeau $firstChild = $rootOutlineSection->getFirstChild(); 19204fd306cSNickeau if ($firstChild->getLevel() >= 2) { 19304fd306cSNickeau $addFirstSection = true; 19404fd306cSNickeau } 19504fd306cSNickeau } catch (ExceptionNotFound $e) { 19604fd306cSNickeau $addFirstSection = true; 19704fd306cSNickeau } 19804fd306cSNickeau if ($addFirstSection) { 19904fd306cSNickeau $enterHeading = Call::createComboCall( 20004fd306cSNickeau HeadingTag::HEADING_TAG, 20104fd306cSNickeau DOKU_LEXER_ENTER, 20204fd306cSNickeau array(HeadingTag::LEVEL => 1), 20304fd306cSNickeau HeadingTag::TYPE_OUTLINE, 20404fd306cSNickeau null, 20504fd306cSNickeau null, 20604fd306cSNickeau null, 20704fd306cSNickeau \syntax_plugin_combo_xmlblocktag::TAG 20804fd306cSNickeau ); 20904fd306cSNickeau $title = PageTitle::createForMarkup($outline->getMarkupPath())->getValueOrDefault(); 21004fd306cSNickeau $unmatchedHeading = Call::createComboCall( 21104fd306cSNickeau HeadingTag::HEADING_TAG, 21204fd306cSNickeau DOKU_LEXER_UNMATCHED, 21304fd306cSNickeau [], 21404fd306cSNickeau null, 21504fd306cSNickeau $title, 21604fd306cSNickeau $title, 21704fd306cSNickeau null, 21804fd306cSNickeau \syntax_plugin_combo_xmlblocktag::TAG 21904fd306cSNickeau ); 22004fd306cSNickeau $exitHeading = Call::createComboCall( 22104fd306cSNickeau HeadingTag::HEADING_TAG, 22204fd306cSNickeau DOKU_LEXER_EXIT, 22304fd306cSNickeau array(HeadingTag::LEVEL => 1), 22404fd306cSNickeau null, 22504fd306cSNickeau null, 22604fd306cSNickeau null, 22704fd306cSNickeau null, 22804fd306cSNickeau \syntax_plugin_combo_xmlblocktag::TAG 22904fd306cSNickeau ); 23004fd306cSNickeau $h1Section = OutlineSection::createFromEnterHeadingCall($enterHeading) 23104fd306cSNickeau ->addHeaderCall($unmatchedHeading) 23204fd306cSNickeau ->addHeaderCall($exitHeading); 23304fd306cSNickeau $children = $rootOutlineSection->getChildren(); 23404fd306cSNickeau foreach ($children as $child) { 23504fd306cSNickeau $child->detachBeforeAppend(); 23604fd306cSNickeau try { 23704fd306cSNickeau $h1Section->appendChild($child); 23804fd306cSNickeau } catch (ExceptionBadState $e) { 23904fd306cSNickeau LogUtility::error("An error occurs when trying to move the h2 children below the recreated heading title ($title)", self::CANONICAL); 24004fd306cSNickeau } 24104fd306cSNickeau } 24204fd306cSNickeau /** 24304fd306cSNickeau * Without h1 24404fd306cSNickeau * The content is in the root heading 24504fd306cSNickeau */ 24604fd306cSNickeau foreach ($rootOutlineSection->getContentCalls() as $rootHeadingCall) { 24704fd306cSNickeau $h1Section->addContentCall($rootHeadingCall); 24804fd306cSNickeau } 24904fd306cSNickeau $rootOutlineSection->deleteContentCalls(); 25004fd306cSNickeau try { 25104fd306cSNickeau $rootOutlineSection->appendChild($h1Section); 25204fd306cSNickeau } catch (ExceptionBadState $e) { 25304fd306cSNickeau LogUtility::error("An error occurs when trying to add the recreated title heading ($title) to the root", self::CANONICAL); 25404fd306cSNickeau } 25504fd306cSNickeau } 25604fd306cSNickeau return $outline; 25704fd306cSNickeau } 25804fd306cSNickeau 25904fd306cSNickeau public function getLabel(): string 26004fd306cSNickeau { 26104fd306cSNickeau return self::CANONICAL; 26204fd306cSNickeau } 263*7dbcdecdSNico 264*7dbcdecdSNico private function buildOutlineRecursive(MarkupPath $indexPath, int $actualLevel) 265*7dbcdecdSNico { 266*7dbcdecdSNico /** 267*7dbcdecdSNico * Index Page 268*7dbcdecdSNico */ 269*7dbcdecdSNico if (FileSystems::exists($indexPath)) { 270*7dbcdecdSNico $indexOutline = $this->addFirstSectionIfMissing($indexPath->getOutline()); 271*7dbcdecdSNico } else { 272*7dbcdecdSNico $title = PageTitle::createForMarkup($indexPath)->getValueOrDefault(); 273*7dbcdecdSNico $content = <<<EOF 274*7dbcdecdSNico====== $title ====== 275*7dbcdecdSNicoEOF; 276*7dbcdecdSNico $indexOutline = Outline::createFromMarkup($content, $this->getStartPath(), $this->getRequestedContextPath()); 277*7dbcdecdSNico } 278*7dbcdecdSNico 279*7dbcdecdSNico if(!$this->bundledOutline){ 280*7dbcdecdSNico $this->bundledOutline = $indexOutline; 281*7dbcdecdSNico } else { 282*7dbcdecdSNico Outline::merge($this->bundledOutline, $indexOutline, $actualLevel); 283*7dbcdecdSNico } 284*7dbcdecdSNico 285*7dbcdecdSNico /** 286*7dbcdecdSNico * Children Pages (Same level) 287*7dbcdecdSNico */ 288*7dbcdecdSNico $childrenPages = MarkupFileSystem::getOrCreate()->getChildren($indexPath, FileSystems::LEAF); 289*7dbcdecdSNico foreach ($childrenPages as $child) { 290*7dbcdecdSNico if ($child->isSlot()) { 291*7dbcdecdSNico continue; 292*7dbcdecdSNico } 293*7dbcdecdSNico $outer = $this->addFirstSectionIfMissing($child->getOutline()); 294*7dbcdecdSNico Outline::merge($this->bundledOutline, $outer, $actualLevel); 295*7dbcdecdSNico } 296*7dbcdecdSNico $containerPages = MarkupFileSystem::getOrCreate()->getChildren($indexPath, FileSystems::CONTAINER); 297*7dbcdecdSNico $nextLevel = $actualLevel+1; 298*7dbcdecdSNico foreach ($containerPages as $child) { 299*7dbcdecdSNico $this->buildOutlineRecursive($child,$nextLevel); 300*7dbcdecdSNico } 301*7dbcdecdSNico 302*7dbcdecdSNico } 30304fd306cSNickeau} 304