137748cd8SNickeau<?php 237748cd8SNickeau 337748cd8SNickeau 4*04fd306cSNickeauuse ComboStrap\ExceptionBadArgument; 5*04fd306cSNickeauuse ComboStrap\ExceptionNotFound; 6*04fd306cSNickeauuse ComboStrap\ExceptionSqliteNotAvailable; 7*04fd306cSNickeauuse ComboStrap\ExecutionContext; 8*04fd306cSNickeauuse ComboStrap\FetcherMarkup; 9*04fd306cSNickeauuse ComboStrap\FragmentTag; 10*04fd306cSNickeauuse ComboStrap\MarkupCacheDependencies; 114cadd4f8SNickeauuse ComboStrap\CacheManager; 124cadd4f8SNickeauuse ComboStrap\Call; 1337748cd8SNickeauuse ComboStrap\CallStack; 14*04fd306cSNickeauuse ComboStrap\MarkupDynamicRender; 15*04fd306cSNickeauuse ComboStrap\ExceptionCompile; 164cadd4f8SNickeauuse ComboStrap\LogUtility; 17*04fd306cSNickeauuse ComboStrap\MarkupPath; 18*04fd306cSNickeauuse ComboStrap\PageImageTag; 19*04fd306cSNickeauuse ComboStrap\PagePath; 204cadd4f8SNickeauuse ComboStrap\PageSql; 214cadd4f8SNickeauuse ComboStrap\PageSqlTreeListener; 2237748cd8SNickeauuse ComboStrap\PluginUtility; 234cadd4f8SNickeauuse ComboStrap\Sqlite; 2437748cd8SNickeauuse ComboStrap\TagAttributes; 25*04fd306cSNickeauuse ComboStrap\WikiPath; 26*04fd306cSNickeauuse ComboStrap\XmlTagProcessing; 2737748cd8SNickeau 2837748cd8SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 2937748cd8SNickeau 3037748cd8SNickeau 3137748cd8SNickeau/** 3237748cd8SNickeau * 3337748cd8SNickeau * An iterator to iterate over templates. 3437748cd8SNickeau * 3537748cd8SNickeau * ******************* 3637748cd8SNickeau * Iteration driver 3737748cd8SNickeau * ******************* 3837748cd8SNickeau * The end tag of the template node is driving the iteration. 3937748cd8SNickeau * This way, the tags just after the template 4037748cd8SNickeau * sees them in the {@link CallStack} and can change their context 4137748cd8SNickeau * 4237748cd8SNickeau * For instance, a {@link syntax_plugin_combo_masonry} 4337748cd8SNickeau * component will change the context of all card inside it. 4437748cd8SNickeau * 4537748cd8SNickeau * ******************** 4637748cd8SNickeau * Header and footer delimitation 4737748cd8SNickeau * ******************** 4837748cd8SNickeau * The iterator delimits also the header and footer. 4937748cd8SNickeau * Some component needs the header to be generate completely. 5037748cd8SNickeau * This is the case of a complex markup such as a table 5137748cd8SNickeau * 5237748cd8SNickeau * ****************************** 5337748cd8SNickeau * Delete if no data 5437748cd8SNickeau * ****************************** 5537748cd8SNickeau * It gives also the possibility to {@link syntax_plugin_combo_iterator::EMPTY_ROWS_COUNT_ATTRIBUTE 5637748cd8SNickeau * delete the whole block} 5737748cd8SNickeau * (header and footer also) if there is no data 5837748cd8SNickeau * 5937748cd8SNickeau * ***************************** 6037748cd8SNickeau * Always Contextual 6137748cd8SNickeau * ***************************** 6237748cd8SNickeau * We don't capture the text markup such as in a {@link syntax_plugin_combo_code} 6337748cd8SNickeau * in order to loop because you can't pass the actual handler (ie callstack) 6437748cd8SNickeau * when you {@link p_get_instructions() parse again} a markup. 6537748cd8SNickeau * 6637748cd8SNickeau * The markup is then seen as a new single page without any context. 6737748cd8SNickeau * That may lead to problems. 6837748cd8SNickeau * Example: `heading` may then think that they are `outline heading` ... 6937748cd8SNickeau * 7037748cd8SNickeau */ 7137748cd8SNickeauclass syntax_plugin_combo_iterator extends DokuWiki_Syntax_Plugin 7237748cd8SNickeau{ 7337748cd8SNickeau 7437748cd8SNickeau /** 7537748cd8SNickeau * Tag in Dokuwiki cannot have a `-` 7637748cd8SNickeau * This is the last part of the class 7737748cd8SNickeau */ 7837748cd8SNickeau const TAG = "iterator"; 7937748cd8SNickeau 8037748cd8SNickeau /** 8137748cd8SNickeau * Page canonical and tag pattern 8237748cd8SNickeau */ 8337748cd8SNickeau const CANONICAL = "iterator"; 844cadd4f8SNickeau const PAGE_SQL = "page-sql"; 85*04fd306cSNickeau const PAGE_SQL_ATTRIBUTES = "page-sql-attributes"; 864cadd4f8SNickeau const COMPLEX_MARKUP_FOUND = "complex-markup-found"; 874cadd4f8SNickeau const BEFORE_TEMPLATE_CALLSTACK = "header-callstack"; 884cadd4f8SNickeau const AFTER_TEMPLATE_CALLSTACK = "footer-callstack"; 894cadd4f8SNickeau const TEMPLATE_CALLSTACK = "template-callstack"; 9037748cd8SNickeau 9137748cd8SNickeau 9237748cd8SNickeau /** 93*04fd306cSNickeau * @param TagAttributes $tagAttributes 94*04fd306cSNickeau * @return WikiPath the context path for element that are in a fragment 95*04fd306cSNickeau */ 96*04fd306cSNickeau public static function getContextPathForComponentThatMayBeInFragment(TagAttributes $tagAttributes): WikiPath 97*04fd306cSNickeau { 98*04fd306cSNickeau $pathString = $tagAttributes->getComponentAttributeValueAndRemoveIfPresent(PagePath::PROPERTY_NAME); 99*04fd306cSNickeau if ($pathString != null) { 100*04fd306cSNickeau try { 101*04fd306cSNickeau return WikiPath::createMarkupPathFromPath($pathString); 102*04fd306cSNickeau } catch (ExceptionBadArgument $e) { 103*04fd306cSNickeau LogUtility::warning("Error while creating the path for the page image with the path value ($pathString)", PageImageTag::CANONICAL, $e); 104*04fd306cSNickeau } 105*04fd306cSNickeau } 106*04fd306cSNickeau 107*04fd306cSNickeau $executionContext = ExecutionContext::getActualOrCreateFromEnv(); 108*04fd306cSNickeau 109*04fd306cSNickeau try { 110*04fd306cSNickeau $markupHandler = $executionContext->getExecutingMarkupHandler(); 111*04fd306cSNickeau $contextData = $markupHandler 112*04fd306cSNickeau ->getContextData(); 113*04fd306cSNickeau $path = $contextData[PagePath::PROPERTY_NAME]; 114*04fd306cSNickeau if ($path !== null) { 115*04fd306cSNickeau try { 116*04fd306cSNickeau return WikiPath::createMarkupPathFromPath($path); 117*04fd306cSNickeau } catch (ExceptionBadArgument $e) { 118*04fd306cSNickeau LogUtility::internalError("The path string should be absolute, we should not get this error", PageImageTag::CANONICAL, $e); 119*04fd306cSNickeau } 120*04fd306cSNickeau } 121*04fd306cSNickeau return $markupHandler->getRequestedContextPath(); 122*04fd306cSNickeau } catch (ExceptionNotFound $e) { 123*04fd306cSNickeau // no markup handler 124*04fd306cSNickeau } 125*04fd306cSNickeau return $executionContext->getContextPath(); 126*04fd306cSNickeau 127*04fd306cSNickeau } 128*04fd306cSNickeau 129*04fd306cSNickeau 130*04fd306cSNickeau /** 13137748cd8SNickeau * Syntax Type. 13237748cd8SNickeau * 13337748cd8SNickeau * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 13437748cd8SNickeau * @see https://www.dokuwiki.org/devel:syntax_plugins#syntax_types 13537748cd8SNickeau * @see DokuWiki_Syntax_Plugin::getType() 13637748cd8SNickeau */ 1374cadd4f8SNickeau function getType(): string 13837748cd8SNickeau { 13937748cd8SNickeau return 'container'; 14037748cd8SNickeau } 14137748cd8SNickeau 14237748cd8SNickeau /** 14337748cd8SNickeau * How Dokuwiki will add P element 14437748cd8SNickeau * 145*04fd306cSNickeau * * 'normal' - Inline 146*04fd306cSNickeau * * 'block' - Block (p are not created inside) 147*04fd306cSNickeau * * 'stack' - Block (p can be created inside) 14837748cd8SNickeau * 14937748cd8SNickeau * @see DokuWiki_Syntax_Plugin::getPType() 15037748cd8SNickeau * @see https://www.dokuwiki.org/devel:syntax_plugins#ptype 15137748cd8SNickeau */ 1524cadd4f8SNickeau function getPType(): string 15337748cd8SNickeau { 15437748cd8SNickeau return 'block'; 15537748cd8SNickeau } 15637748cd8SNickeau 15737748cd8SNickeau /** 15837748cd8SNickeau * @return array 15937748cd8SNickeau * Allow which kind of plugin inside 16037748cd8SNickeau * 16137748cd8SNickeau * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 16237748cd8SNickeau * because we manage self the content and we call self the parser 16337748cd8SNickeau * 16437748cd8SNickeau * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php 16537748cd8SNickeau */ 1664cadd4f8SNickeau function getAllowedTypes(): array 16737748cd8SNickeau { 16837748cd8SNickeau return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); 16937748cd8SNickeau } 17037748cd8SNickeau 1714cadd4f8SNickeau function getSort(): int 17237748cd8SNickeau { 17337748cd8SNickeau return 201; 17437748cd8SNickeau } 17537748cd8SNickeau 1764cadd4f8SNickeau public function accepts($mode): bool 17737748cd8SNickeau { 17837748cd8SNickeau return syntax_plugin_combo_preformatted::disablePreformatted($mode); 17937748cd8SNickeau } 18037748cd8SNickeau 18137748cd8SNickeau 18237748cd8SNickeau function connectTo($mode) 18337748cd8SNickeau { 18437748cd8SNickeau 18537748cd8SNickeau 186*04fd306cSNickeau $pattern = XmlTagProcessing::getContainerTagPattern(self::TAG); 18737748cd8SNickeau $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 18837748cd8SNickeau 18937748cd8SNickeau 19037748cd8SNickeau } 19137748cd8SNickeau 19237748cd8SNickeau 19337748cd8SNickeau public function postConnect() 19437748cd8SNickeau { 19537748cd8SNickeau 19637748cd8SNickeau $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeFromTag($this->getPluginComponent())); 19737748cd8SNickeau 19837748cd8SNickeau 19937748cd8SNickeau } 20037748cd8SNickeau 20137748cd8SNickeau 20237748cd8SNickeau /** 20337748cd8SNickeau * 20437748cd8SNickeau * The handle function goal is to parse the matched syntax through the pattern function 20537748cd8SNickeau * and to return the result for use in the renderer 20637748cd8SNickeau * This result is always cached until the page is modified. 20737748cd8SNickeau * @param string $match 20837748cd8SNickeau * @param int $state 20937748cd8SNickeau * @param int $pos - byte position in the original source file 21037748cd8SNickeau * @param Doku_Handler $handler 2114cadd4f8SNickeau * @return array 21237748cd8SNickeau * @see DokuWiki_Syntax_Plugin::handle() 21337748cd8SNickeau * 21437748cd8SNickeau */ 2154cadd4f8SNickeau function handle($match, $state, $pos, Doku_Handler $handler): array 21637748cd8SNickeau { 21737748cd8SNickeau 21837748cd8SNickeau switch ($state) { 21937748cd8SNickeau 22037748cd8SNickeau case DOKU_LEXER_ENTER : 22137748cd8SNickeau 22237748cd8SNickeau $tagAttributes = TagAttributes::createFromTagMatch($match); 22337748cd8SNickeau $callStackArray = $tagAttributes->toCallStackArray(); 22437748cd8SNickeau return array( 22537748cd8SNickeau PluginUtility::STATE => $state, 22637748cd8SNickeau PluginUtility::ATTRIBUTES => $callStackArray 22737748cd8SNickeau ); 22837748cd8SNickeau 22937748cd8SNickeau case DOKU_LEXER_UNMATCHED : 23037748cd8SNickeau 23137748cd8SNickeau // We should not ever come here but a user does not not known that 23237748cd8SNickeau return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler); 23337748cd8SNickeau 23437748cd8SNickeau 23537748cd8SNickeau case DOKU_LEXER_EXIT : 23637748cd8SNickeau 2371fa8c418SNickeau $callStack = CallStack::createFromHandler($handler); 2384cadd4f8SNickeau $openTag = $callStack->moveToPreviousCorrespondingOpeningCall(); 2394cadd4f8SNickeau /** 2404cadd4f8SNickeau * Scanning the callstack and extracting the information 2414cadd4f8SNickeau * such as sql and template instructions 2424cadd4f8SNickeau */ 2434cadd4f8SNickeau $pageSql = null; 244*04fd306cSNickeau $pageSqlAttribute = []; 2454cadd4f8SNickeau $beforeTemplateCallStack = []; 2464cadd4f8SNickeau $templateStack = []; 2474cadd4f8SNickeau $afterTemplateCallStack = []; 2484cadd4f8SNickeau $parsingState = "before"; 2494cadd4f8SNickeau $complexMarkupFound = false; 2504cadd4f8SNickeau while ($actualCall = $callStack->next()) { 2514cadd4f8SNickeau $tagName = $actualCall->getTagName(); 252*04fd306cSNickeau 253*04fd306cSNickeau if ($tagName === syntax_plugin_combo_edit::TAG) { 254*04fd306cSNickeau /** 255*04fd306cSNickeau * Not capturing the edit button because the markup is generated 256*04fd306cSNickeau */ 257*04fd306cSNickeau continue; 258*04fd306cSNickeau } 259*04fd306cSNickeau 2604cadd4f8SNickeau switch ($tagName) { 2614cadd4f8SNickeau case syntax_plugin_combo_iteratordata::TAG: 262*04fd306cSNickeau switch ($actualCall->getState()) { 263*04fd306cSNickeau case DOKU_LEXER_UNMATCHED: 2644cadd4f8SNickeau $pageSql = $actualCall->getCapturedContent(); 265*04fd306cSNickeau break; 266*04fd306cSNickeau case DOKU_LEXER_ENTER: 267*04fd306cSNickeau $pageSqlAttribute = $actualCall->getAttributes(); 268*04fd306cSNickeau break; 2691fa8c418SNickeau } 2704cadd4f8SNickeau continue 2; 271*04fd306cSNickeau case FragmentTag::FRAGMENT_TAG: 2724cadd4f8SNickeau $parsingState = "after"; 2734cadd4f8SNickeau if ($actualCall->getState() === DOKU_LEXER_EXIT) { 274*04fd306cSNickeau $templateStack = $actualCall->getPluginData(FragmentTag::CALLSTACK); 2754cadd4f8SNickeau /** 2764cadd4f8SNickeau * Do we have markup where the instructions should be generated at once 2774cadd4f8SNickeau * and not line by line 2784cadd4f8SNickeau * 2794cadd4f8SNickeau * ie a list or a table 2804cadd4f8SNickeau */ 2814cadd4f8SNickeau foreach ($templateStack as $templateInstructions) { 2824cadd4f8SNickeau $templateCall = Call::createFromInstruction($templateInstructions); 2834cadd4f8SNickeau if (in_array($templateCall->getComponentName(), Call::BLOCK_MARKUP_DOKUWIKI_COMPONENTS)) { 2844cadd4f8SNickeau $complexMarkupFound = true; 2854cadd4f8SNickeau } 2864cadd4f8SNickeau 2874cadd4f8SNickeau } 2884cadd4f8SNickeau } 2894cadd4f8SNickeau continue 2; 2904cadd4f8SNickeau default: 2914cadd4f8SNickeau if ($parsingState === "before") { 2924cadd4f8SNickeau $beforeTemplateCallStack[] = $actualCall->toCallArray(); 2934cadd4f8SNickeau } else { 2944cadd4f8SNickeau $afterTemplateCallStack[] = $actualCall->toCallArray(); 2954cadd4f8SNickeau }; 2964cadd4f8SNickeau break; 2974cadd4f8SNickeau } 2984cadd4f8SNickeau } 2994cadd4f8SNickeau 3004cadd4f8SNickeau /** 3014cadd4f8SNickeau * Wipe the content of iterator 3024cadd4f8SNickeau */ 3034cadd4f8SNickeau $callStack->deleteAllCallsAfter($openTag); 3044cadd4f8SNickeau 305*04fd306cSNickeau /** 306*04fd306cSNickeau * Enter Tag is the driver tag 307*04fd306cSNickeau * (To be able to add class by third party component) 308*04fd306cSNickeau */ 309*04fd306cSNickeau $openTag->setPluginData(self::PAGE_SQL, $pageSql); 310*04fd306cSNickeau $openTag->setPluginData(self::PAGE_SQL_ATTRIBUTES, $pageSqlAttribute); 311*04fd306cSNickeau $openTag->setPluginData(self::COMPLEX_MARKUP_FOUND, $complexMarkupFound); 312*04fd306cSNickeau $openTag->setPluginData(self::BEFORE_TEMPLATE_CALLSTACK, $beforeTemplateCallStack); 313*04fd306cSNickeau $openTag->setPluginData(self::AFTER_TEMPLATE_CALLSTACK, $afterTemplateCallStack); 314*04fd306cSNickeau $openTag->setPluginData(self::TEMPLATE_CALLSTACK, $templateStack); 315*04fd306cSNickeau 3164cadd4f8SNickeau return array( 317*04fd306cSNickeau PluginUtility::STATE => $state 3184cadd4f8SNickeau ); 31937748cd8SNickeau 32037748cd8SNickeau } 32137748cd8SNickeau return array(); 32237748cd8SNickeau 32337748cd8SNickeau } 32437748cd8SNickeau 32537748cd8SNickeau /** 32637748cd8SNickeau * Render the output 32737748cd8SNickeau * @param string $format 32837748cd8SNickeau * @param Doku_Renderer $renderer 32937748cd8SNickeau * @param array $data - what the function handle() return'ed 33037748cd8SNickeau * @return boolean - rendered correctly? (however, returned value is not used at the moment) 33137748cd8SNickeau * @see DokuWiki_Syntax_Plugin::render() 33237748cd8SNickeau * 33337748cd8SNickeau * 33437748cd8SNickeau */ 3354cadd4f8SNickeau function render($format, Doku_Renderer $renderer, $data): bool 33637748cd8SNickeau { 3374cadd4f8SNickeau if ($format === "xhtml") { 3384cadd4f8SNickeau $state = $data[PluginUtility::STATE]; 3394cadd4f8SNickeau switch ($state) { 340*04fd306cSNickeau case DOKU_LEXER_EXIT: 3414cadd4f8SNickeau return true; 3424cadd4f8SNickeau case DOKU_LEXER_UNMATCHED: 3434cadd4f8SNickeau $renderer->doc .= PluginUtility::renderUnmatched($data); 3444cadd4f8SNickeau return true; 345*04fd306cSNickeau case DOKU_LEXER_ENTER: 3464cadd4f8SNickeau 3474cadd4f8SNickeau $pageSql = $data[self::PAGE_SQL]; 3484cadd4f8SNickeau 3494cadd4f8SNickeau /** 3504cadd4f8SNickeau * Data Processing 3514cadd4f8SNickeau */ 3524cadd4f8SNickeau if ($pageSql === null) { 353a4e629a3Sgerardnico $renderer->doc .= "A data node could not be found as a child of the iterator."; 3544cadd4f8SNickeau return false; 3554cadd4f8SNickeau } 3564cadd4f8SNickeau if (empty($pageSql)) { 3574cadd4f8SNickeau $renderer->doc .= "The data node definition needs a logical sql content"; 3584cadd4f8SNickeau return false; 3594cadd4f8SNickeau } 3604cadd4f8SNickeau 3614cadd4f8SNickeau /** 3624cadd4f8SNickeau * Sqlite available ? 3634cadd4f8SNickeau */ 364*04fd306cSNickeau try { 3654cadd4f8SNickeau $sqlite = Sqlite::createOrGetSqlite(); 366*04fd306cSNickeau } catch (ExceptionSqliteNotAvailable $e) { 3674cadd4f8SNickeau $renderer->doc .= "The iterator component needs Sqlite to be able to work"; 3684cadd4f8SNickeau return false; 3694cadd4f8SNickeau } 3704cadd4f8SNickeau 371*04fd306cSNickeau $executionContext = ExecutionContext::getActualOrCreateFromEnv(); 3724cadd4f8SNickeau 3734cadd4f8SNickeau /** 3744cadd4f8SNickeau * Create the SQL 3754cadd4f8SNickeau */ 3764cadd4f8SNickeau try { 377*04fd306cSNickeau $tagAttributes = TagAttributes::createFromCallStackArray($data[self::PAGE_SQL_ATTRIBUTES]); 378*04fd306cSNickeau $path = $tagAttributes->getValue(PagePath::PROPERTY_NAME); 379*04fd306cSNickeau if ($path !== null) { 380*04fd306cSNickeau $contextualPage = MarkupPath::createPageFromAbsoluteId($path); 381*04fd306cSNickeau } else { 382*04fd306cSNickeau $contextualPage = MarkupPath::createPageFromPathObject($executionContext->getContextPath()); 383*04fd306cSNickeau } 384*04fd306cSNickeau $pageSql = PageSql::create($pageSql, $contextualPage); 3854cadd4f8SNickeau } catch (Exception $e) { 3864cadd4f8SNickeau $renderer->doc .= "The page sql is not valid. Error Message: {$e->getMessage()}. Page Sql: ($pageSql)"; 3874cadd4f8SNickeau return false; 3884cadd4f8SNickeau } 3894cadd4f8SNickeau 3904cadd4f8SNickeau $table = $pageSql->getTable(); 391*04fd306cSNickeau 392*04fd306cSNickeau try { 393*04fd306cSNickeau $cacheDependencies = $executionContext 394*04fd306cSNickeau ->getExecutingMarkupHandler() 395*04fd306cSNickeau ->getOutputCacheDependencies(); 396*04fd306cSNickeau 3974cadd4f8SNickeau switch ($table) { 3984cadd4f8SNickeau case PageSqlTreeListener::BACKLINKS: 399*04fd306cSNickeau $cacheDependencies->addDependency(MarkupCacheDependencies::BACKLINKS_DEPENDENCY); 400*04fd306cSNickeau // The requested page dependency could be determined by the backlinks dependency 401*04fd306cSNickeau $cacheDependencies->addDependency(MarkupCacheDependencies::REQUESTED_PAGE_DEPENDENCY); 402*04fd306cSNickeau break; 403*04fd306cSNickeau case PageSqlTreeListener::DESCENDANTS: 404*04fd306cSNickeau $cacheDependencies->addDependency(MarkupCacheDependencies::PAGE_SYSTEM_DEPENDENCY); 4054cadd4f8SNickeau break; 4064cadd4f8SNickeau default: 4074cadd4f8SNickeau } 408*04fd306cSNickeau } catch (ExceptionNotFound $e) { 409*04fd306cSNickeau // not a fetcher markup run 410*04fd306cSNickeau } 4114cadd4f8SNickeau 4124cadd4f8SNickeau /** 4134cadd4f8SNickeau * Execute the generated SQL 4144cadd4f8SNickeau */ 4154cadd4f8SNickeau try { 4164cadd4f8SNickeau $executableSql = $pageSql->getExecutableSql(); 4174cadd4f8SNickeau $parameters = $pageSql->getParameters(); 4184cadd4f8SNickeau $request = $sqlite 4194cadd4f8SNickeau ->createRequest() 4204cadd4f8SNickeau ->setQueryParametrized($executableSql, $parameters); 4214cadd4f8SNickeau $rowsInDb = []; 4224cadd4f8SNickeau try { 4234cadd4f8SNickeau $rowsInDb = $request 4244cadd4f8SNickeau ->execute() 4254cadd4f8SNickeau ->getRows(); 426*04fd306cSNickeau } catch (ExceptionCompile $e) { 4274cadd4f8SNickeau $renderer->doc .= "The sql statement generated returns an error. Sql statement: $executableSql"; 4284cadd4f8SNickeau return false; 4294cadd4f8SNickeau } finally { 4304cadd4f8SNickeau $request->close(); 4314cadd4f8SNickeau } 4324cadd4f8SNickeau 4334cadd4f8SNickeau $rows = []; 4344cadd4f8SNickeau foreach ($rowsInDb as $sourceRow) { 435*04fd306cSNickeau 4364cadd4f8SNickeau /** 4374cadd4f8SNickeau * We use id until path is full in the database 4384cadd4f8SNickeau */ 4394cadd4f8SNickeau $id = $sourceRow["ID"]; 440*04fd306cSNickeau $contextualPage = MarkupPath::createMarkupFromId($id); 441*04fd306cSNickeau if ($contextualPage->isHidden()) { 4424cadd4f8SNickeau continue; 4434cadd4f8SNickeau } 444*04fd306cSNickeau if (!$contextualPage->exists()) { 445*04fd306cSNickeau LogUtility::error("Internal Error: the page selected ($contextualPage) was not added. It does not exist and was deleted from the database index.", self::CANONICAL); 446*04fd306cSNickeau $contextualPage->getDatabasePage()->delete(); 4474cadd4f8SNickeau continue; 4484cadd4f8SNickeau } 449*04fd306cSNickeau $standardMetadata = $contextualPage->getMetadataForRendering(); 450*04fd306cSNickeau $rows[] = $standardMetadata; 4514cadd4f8SNickeau } 4524cadd4f8SNickeau } catch (Exception $e) { 4534cadd4f8SNickeau $renderer->doc .= "Error during Sql Execution. Error: {$e->getMessage()}"; 4544cadd4f8SNickeau return false; 4554cadd4f8SNickeau } 4564cadd4f8SNickeau 4574cadd4f8SNickeau 4584cadd4f8SNickeau /** 4594cadd4f8SNickeau * Loop 4604cadd4f8SNickeau */ 4614cadd4f8SNickeau $elementCounts = sizeof($rows); 4624cadd4f8SNickeau if ($elementCounts === 0) { 4634cadd4f8SNickeau $parametersString = implode(", ", $parameters); 464*04fd306cSNickeau LogUtility::debug("The physical query (Sql: {$pageSql->getExecutableSql()}, Parameters: $parametersString) does not return any data", syntax_plugin_combo_iterator::CANONICAL); 4654cadd4f8SNickeau return true; 4664cadd4f8SNickeau } 4674cadd4f8SNickeau 4684cadd4f8SNickeau 4694cadd4f8SNickeau /** 4704cadd4f8SNickeau * Template stack processing 4714cadd4f8SNickeau */ 4724cadd4f8SNickeau $iteratorTemplateInstructions = $data[self::TEMPLATE_CALLSTACK]; 4734cadd4f8SNickeau if ($iteratorTemplateInstructions === null) { 4744cadd4f8SNickeau $renderer->doc .= "No template was found in this iterator."; 4754cadd4f8SNickeau return false; 4764cadd4f8SNickeau } 4774cadd4f8SNickeau 4784cadd4f8SNickeau 4794cadd4f8SNickeau /** 480*04fd306cSNickeau * Split template 481*04fd306cSNickeau * Splits the template into header, main and footer 482*04fd306cSNickeau * in case of complex header 4834cadd4f8SNickeau */ 484*04fd306cSNickeau $templateHeader = array(); 485*04fd306cSNickeau $templateMain = $iteratorTemplateInstructions; 486*04fd306cSNickeau $templateFooter = array(); 4874cadd4f8SNickeau $complexMarkupFound = $data[self::COMPLEX_MARKUP_FOUND]; 4884cadd4f8SNickeau if ($complexMarkupFound) { 4894cadd4f8SNickeau 4904cadd4f8SNickeau /** 4914cadd4f8SNickeau * @var Call $actualCall 4924cadd4f8SNickeau */ 4934cadd4f8SNickeau $templateCallStack = CallStack::createFromInstructions($iteratorTemplateInstructions); 494*04fd306cSNickeau 4954cadd4f8SNickeau $actualStack = array(); 4964cadd4f8SNickeau $templateCallStack->moveToStart(); 4974cadd4f8SNickeau while ($actualCall = $templateCallStack->next()) { 4984cadd4f8SNickeau switch ($actualCall->getComponentName()) { 4994cadd4f8SNickeau case "listitem_open": 5004cadd4f8SNickeau case "tablerow_open": 5014cadd4f8SNickeau $templateHeader = $actualStack; 502*04fd306cSNickeau $actualStack = [$actualCall->toCallArray()]; 5034cadd4f8SNickeau continue 2; 5044cadd4f8SNickeau case "listitem_close": 5054cadd4f8SNickeau case "tablerow_close": 506*04fd306cSNickeau $actualStack[] = $actualCall->toCallArray(); 5074cadd4f8SNickeau $templateMain = $actualStack; 5084cadd4f8SNickeau $actualStack = []; 5094cadd4f8SNickeau continue 2; 5104cadd4f8SNickeau default: 511*04fd306cSNickeau $actualStack[] = $actualCall->toCallArray(); 5124cadd4f8SNickeau } 5134cadd4f8SNickeau } 5144cadd4f8SNickeau $templateFooter = $actualStack; 515*04fd306cSNickeau } 5164cadd4f8SNickeau 517*04fd306cSNickeau $contextPath = $executionContext->getContextPath(); 518*04fd306cSNickeau 519*04fd306cSNickeau /** 520*04fd306cSNickeau * Rendering 521*04fd306cSNickeau */ 522*04fd306cSNickeau $renderDoc = ""; 523*04fd306cSNickeau 524*04fd306cSNickeau /** 525*04fd306cSNickeau * Header 526*04fd306cSNickeau */ 527*04fd306cSNickeau $iteratorHeaderInstructions = $data[self::BEFORE_TEMPLATE_CALLSTACK]; 528*04fd306cSNickeau if (!empty($iteratorHeaderInstructions)) { 5294cadd4f8SNickeau /** 5304cadd4f8SNickeau * Table with an header 5314cadd4f8SNickeau * If this is the case, the table_close of the header 5324cadd4f8SNickeau * and the table_open of the template should be 5334cadd4f8SNickeau * deleted to create one table 5344cadd4f8SNickeau */ 5354cadd4f8SNickeau if (!empty($templateHeader)) { 536*04fd306cSNickeau $firstTemplateCall = Call::createFromInstruction($templateHeader[0]); 5374cadd4f8SNickeau if ($firstTemplateCall->getComponentName() === "table_open") { 5384cadd4f8SNickeau $lastIterationHeaderElement = sizeof($iteratorHeaderInstructions) - 1; 5394cadd4f8SNickeau $lastIterationHeaderInstruction = Call::createFromInstruction($iteratorHeaderInstructions[$lastIterationHeaderElement]); 5404cadd4f8SNickeau if ($lastIterationHeaderInstruction->getComponentName() === "table_close") { 5414cadd4f8SNickeau unset($iteratorHeaderInstructions[$lastIterationHeaderElement]); 5424cadd4f8SNickeau unset($templateHeader[0]); 5434cadd4f8SNickeau } 5444cadd4f8SNickeau } 5454cadd4f8SNickeau } 546*04fd306cSNickeau try { 547*04fd306cSNickeau $renderDoc .= FetcherMarkup::confChild() 548*04fd306cSNickeau ->setRequestedInstructions($iteratorHeaderInstructions) 549*04fd306cSNickeau ->setRequestedContextPath($contextPath) 550*04fd306cSNickeau ->setRequestedMimeToXhtml() 551*04fd306cSNickeau ->setIsDocument(false) 552*04fd306cSNickeau ->build() 553*04fd306cSNickeau ->getFetchString(); 554*04fd306cSNickeau } catch (ExceptionCompile $e) { 555*04fd306cSNickeau LogUtility::error("Error while rendering the iterator header. Error: {$e->getMessage()}", self::CANONICAL, $e); 556*04fd306cSNickeau return false; 557*04fd306cSNickeau } 558*04fd306cSNickeau } 5594cadd4f8SNickeau 5604cadd4f8SNickeau /** 561*04fd306cSNickeau * Template 5624cadd4f8SNickeau */ 563*04fd306cSNickeau try { 564*04fd306cSNickeau $renderDoc .= FetcherMarkup::confChild() 565*04fd306cSNickeau ->setRequestedInstructions($templateHeader) 566*04fd306cSNickeau ->setRequestedContextPath($contextPath) 567*04fd306cSNickeau ->setRequestedMimeToXhtml() 568*04fd306cSNickeau ->setIsDocument(false) 569*04fd306cSNickeau ->build() 570*04fd306cSNickeau ->getFetchString(); 571*04fd306cSNickeau } catch (ExceptionCompile $e) { 572*04fd306cSNickeau LogUtility::error("Error while rendering the template header. Error: {$e->getMessage()}", self::CANONICAL); 573*04fd306cSNickeau return false; 5744cadd4f8SNickeau } 5754cadd4f8SNickeau foreach ($rows as $row) { 576*04fd306cSNickeau try { 577*04fd306cSNickeau $renderDoc .= FetcherMarkup::confChild() 578*04fd306cSNickeau ->setRequestedInstructions($templateMain) 579*04fd306cSNickeau ->setContextData($row) 580*04fd306cSNickeau ->setRequestedContextPath($contextPath) 581*04fd306cSNickeau ->setRequestedMimeToXhtml() 582*04fd306cSNickeau ->setIsDocument(false) 583*04fd306cSNickeau ->build() 584*04fd306cSNickeau ->getFetchString(); 585*04fd306cSNickeau } catch (ExceptionCompile $e) { 586*04fd306cSNickeau LogUtility::error("Error while rendering a data row. Error: {$e->getMessage()}", self::CANONICAL); 587*04fd306cSNickeau continue; 5884cadd4f8SNickeau } 5894cadd4f8SNickeau } 590*04fd306cSNickeau try { 591*04fd306cSNickeau $renderDoc .= FetcherMarkup::confChild() 592*04fd306cSNickeau ->setRequestedInstructions($templateFooter) 593*04fd306cSNickeau ->setRequestedContextPath($contextPath) 594*04fd306cSNickeau ->setRequestedMimeToXhtml() 595*04fd306cSNickeau ->setIsDocument(false) 596*04fd306cSNickeau ->build() 597*04fd306cSNickeau ->getFetchString(); 598*04fd306cSNickeau } catch (ExceptionCompile $e) { 599*04fd306cSNickeau LogUtility::error("Error while rendering the template footer. Error: {$e->getMessage()}", self::CANONICAL); 600*04fd306cSNickeau return false; 601*04fd306cSNickeau } 6024cadd4f8SNickeau 6034cadd4f8SNickeau 6044cadd4f8SNickeau /** 605*04fd306cSNickeau * Iterator Footer 6064cadd4f8SNickeau */ 6074cadd4f8SNickeau $callStackFooterInstructions = $data[self::AFTER_TEMPLATE_CALLSTACK]; 6084cadd4f8SNickeau if (!empty($callStackFooterInstructions)) { 609*04fd306cSNickeau try { 610*04fd306cSNickeau $renderDoc .= FetcherMarkup::confChild() 611*04fd306cSNickeau ->setRequestedInstructions($callStackFooterInstructions) 612*04fd306cSNickeau ->setRequestedContextPath($contextPath) 613*04fd306cSNickeau ->setRequestedMimeToXhtml() 614*04fd306cSNickeau ->setIsDocument(false) 615*04fd306cSNickeau ->build() 616*04fd306cSNickeau ->getFetchString(); 617*04fd306cSNickeau } catch (ExceptionCompile $e) { 618*04fd306cSNickeau LogUtility::error("Error while rendering the iterator footer. Error: {$e->getMessage()}", self::CANONICAL); 619*04fd306cSNickeau return false; 6204cadd4f8SNickeau } 621*04fd306cSNickeau } 6224cadd4f8SNickeau 6234cadd4f8SNickeau /** 624*04fd306cSNickeau * Renderer 6254cadd4f8SNickeau */ 626*04fd306cSNickeau $renderer->doc .= $renderDoc; 6274cadd4f8SNickeau return true; 628*04fd306cSNickeau 6294cadd4f8SNickeau } 6304cadd4f8SNickeau } 63137748cd8SNickeau // unsupported $mode 63237748cd8SNickeau return false; 63337748cd8SNickeau } 63437748cd8SNickeau 63537748cd8SNickeau 63637748cd8SNickeau} 63737748cd8SNickeau 638