137748cd8SNickeau<?php 237748cd8SNickeau 337748cd8SNickeau 404fd306cSNickeauuse ComboStrap\ExceptionBadArgument; 504fd306cSNickeauuse ComboStrap\ExceptionNotFound; 604fd306cSNickeauuse ComboStrap\ExceptionSqliteNotAvailable; 704fd306cSNickeauuse ComboStrap\ExecutionContext; 804fd306cSNickeauuse ComboStrap\FetcherMarkup; 904fd306cSNickeauuse ComboStrap\FragmentTag; 1004fd306cSNickeauuse ComboStrap\MarkupCacheDependencies; 114cadd4f8SNickeauuse ComboStrap\CacheManager; 124cadd4f8SNickeauuse ComboStrap\Call; 1337748cd8SNickeauuse ComboStrap\CallStack; 1404fd306cSNickeauuse ComboStrap\MarkupDynamicRender; 1504fd306cSNickeauuse ComboStrap\ExceptionCompile; 164cadd4f8SNickeauuse ComboStrap\LogUtility; 1704fd306cSNickeauuse ComboStrap\MarkupPath; 1804fd306cSNickeauuse ComboStrap\PageImageTag; 1904fd306cSNickeauuse ComboStrap\PagePath; 204cadd4f8SNickeauuse ComboStrap\PageSql; 214cadd4f8SNickeauuse ComboStrap\PageSqlTreeListener; 2237748cd8SNickeauuse ComboStrap\PluginUtility; 234cadd4f8SNickeauuse ComboStrap\Sqlite; 2437748cd8SNickeauuse ComboStrap\TagAttributes; 2504fd306cSNickeauuse ComboStrap\WikiPath; 2604fd306cSNickeauuse 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"; 8504fd306cSNickeau 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 /** 9304fd306cSNickeau * @param TagAttributes $tagAttributes 9404fd306cSNickeau * @return WikiPath the context path for element that are in a fragment 9504fd306cSNickeau */ 9604fd306cSNickeau public static function getContextPathForComponentThatMayBeInFragment(TagAttributes $tagAttributes): WikiPath 9704fd306cSNickeau { 9804fd306cSNickeau $pathString = $tagAttributes->getComponentAttributeValueAndRemoveIfPresent(PagePath::PROPERTY_NAME); 9904fd306cSNickeau if ($pathString != null) { 10004fd306cSNickeau try { 10104fd306cSNickeau return WikiPath::createMarkupPathFromPath($pathString); 10204fd306cSNickeau } catch (ExceptionBadArgument $e) { 10304fd306cSNickeau LogUtility::warning("Error while creating the path for the page image with the path value ($pathString)", PageImageTag::CANONICAL, $e); 10404fd306cSNickeau } 10504fd306cSNickeau } 10604fd306cSNickeau 10704fd306cSNickeau $executionContext = ExecutionContext::getActualOrCreateFromEnv(); 10804fd306cSNickeau 10904fd306cSNickeau try { 11004fd306cSNickeau $markupHandler = $executionContext->getExecutingMarkupHandler(); 11104fd306cSNickeau $contextData = $markupHandler 11204fd306cSNickeau ->getContextData(); 11304fd306cSNickeau $path = $contextData[PagePath::PROPERTY_NAME]; 11404fd306cSNickeau if ($path !== null) { 11504fd306cSNickeau try { 11604fd306cSNickeau return WikiPath::createMarkupPathFromPath($path); 11704fd306cSNickeau } catch (ExceptionBadArgument $e) { 11804fd306cSNickeau LogUtility::internalError("The path string should be absolute, we should not get this error", PageImageTag::CANONICAL, $e); 11904fd306cSNickeau } 12004fd306cSNickeau } 12104fd306cSNickeau return $markupHandler->getRequestedContextPath(); 12204fd306cSNickeau } catch (ExceptionNotFound $e) { 12304fd306cSNickeau // no markup handler 12404fd306cSNickeau } 12504fd306cSNickeau return $executionContext->getContextPath(); 12604fd306cSNickeau 12704fd306cSNickeau } 12804fd306cSNickeau 12904fd306cSNickeau 13004fd306cSNickeau /** 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 * 14504fd306cSNickeau * * 'normal' - Inline 14604fd306cSNickeau * * 'block' - Block (p are not created inside) 14704fd306cSNickeau * * '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 18604fd306cSNickeau $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; 24404fd306cSNickeau $pageSqlAttribute = []; 2454cadd4f8SNickeau $beforeTemplateCallStack = []; 2464cadd4f8SNickeau $templateStack = []; 2474cadd4f8SNickeau $afterTemplateCallStack = []; 2484cadd4f8SNickeau $parsingState = "before"; 2494cadd4f8SNickeau $complexMarkupFound = false; 2504cadd4f8SNickeau while ($actualCall = $callStack->next()) { 2514cadd4f8SNickeau $tagName = $actualCall->getTagName(); 25204fd306cSNickeau 25304fd306cSNickeau if ($tagName === syntax_plugin_combo_edit::TAG) { 25404fd306cSNickeau /** 25504fd306cSNickeau * Not capturing the edit button because the markup is generated 25604fd306cSNickeau */ 25704fd306cSNickeau continue; 25804fd306cSNickeau } 25904fd306cSNickeau 2604cadd4f8SNickeau switch ($tagName) { 2614cadd4f8SNickeau case syntax_plugin_combo_iteratordata::TAG: 26204fd306cSNickeau switch ($actualCall->getState()) { 26304fd306cSNickeau case DOKU_LEXER_UNMATCHED: 2644cadd4f8SNickeau $pageSql = $actualCall->getCapturedContent(); 26504fd306cSNickeau break; 26604fd306cSNickeau case DOKU_LEXER_ENTER: 26704fd306cSNickeau $pageSqlAttribute = $actualCall->getAttributes(); 26804fd306cSNickeau break; 2691fa8c418SNickeau } 2704cadd4f8SNickeau continue 2; 27104fd306cSNickeau case FragmentTag::FRAGMENT_TAG: 2724cadd4f8SNickeau $parsingState = "after"; 2734cadd4f8SNickeau if ($actualCall->getState() === DOKU_LEXER_EXIT) { 27404fd306cSNickeau $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 30504fd306cSNickeau /** 30604fd306cSNickeau * Enter Tag is the driver tag 30704fd306cSNickeau * (To be able to add class by third party component) 30804fd306cSNickeau */ 30904fd306cSNickeau $openTag->setPluginData(self::PAGE_SQL, $pageSql); 31004fd306cSNickeau $openTag->setPluginData(self::PAGE_SQL_ATTRIBUTES, $pageSqlAttribute); 31104fd306cSNickeau $openTag->setPluginData(self::COMPLEX_MARKUP_FOUND, $complexMarkupFound); 31204fd306cSNickeau $openTag->setPluginData(self::BEFORE_TEMPLATE_CALLSTACK, $beforeTemplateCallStack); 31304fd306cSNickeau $openTag->setPluginData(self::AFTER_TEMPLATE_CALLSTACK, $afterTemplateCallStack); 31404fd306cSNickeau $openTag->setPluginData(self::TEMPLATE_CALLSTACK, $templateStack); 31504fd306cSNickeau 3164cadd4f8SNickeau return array( 31704fd306cSNickeau 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) { 34004fd306cSNickeau case DOKU_LEXER_EXIT: 3414cadd4f8SNickeau return true; 3424cadd4f8SNickeau case DOKU_LEXER_UNMATCHED: 3434cadd4f8SNickeau $renderer->doc .= PluginUtility::renderUnmatched($data); 3444cadd4f8SNickeau return true; 34504fd306cSNickeau 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 */ 36404fd306cSNickeau try { 3654cadd4f8SNickeau $sqlite = Sqlite::createOrGetSqlite(); 36604fd306cSNickeau } catch (ExceptionSqliteNotAvailable $e) { 3674cadd4f8SNickeau $renderer->doc .= "The iterator component needs Sqlite to be able to work"; 3684cadd4f8SNickeau return false; 3694cadd4f8SNickeau } 3704cadd4f8SNickeau 37104fd306cSNickeau $executionContext = ExecutionContext::getActualOrCreateFromEnv(); 3724cadd4f8SNickeau 3734cadd4f8SNickeau /** 3744cadd4f8SNickeau * Create the SQL 3754cadd4f8SNickeau */ 3764cadd4f8SNickeau try { 37704fd306cSNickeau $tagAttributes = TagAttributes::createFromCallStackArray($data[self::PAGE_SQL_ATTRIBUTES]); 37804fd306cSNickeau $path = $tagAttributes->getValue(PagePath::PROPERTY_NAME); 37904fd306cSNickeau if ($path !== null) { 38004fd306cSNickeau $contextualPage = MarkupPath::createPageFromAbsoluteId($path); 38104fd306cSNickeau } else { 38204fd306cSNickeau $contextualPage = MarkupPath::createPageFromPathObject($executionContext->getContextPath()); 38304fd306cSNickeau } 38404fd306cSNickeau $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(); 39104fd306cSNickeau 39204fd306cSNickeau try { 39304fd306cSNickeau $cacheDependencies = $executionContext 39404fd306cSNickeau ->getExecutingMarkupHandler() 39504fd306cSNickeau ->getOutputCacheDependencies(); 39604fd306cSNickeau 3974cadd4f8SNickeau switch ($table) { 3984cadd4f8SNickeau case PageSqlTreeListener::BACKLINKS: 39904fd306cSNickeau $cacheDependencies->addDependency(MarkupCacheDependencies::BACKLINKS_DEPENDENCY); 40004fd306cSNickeau // The requested page dependency could be determined by the backlinks dependency 40104fd306cSNickeau $cacheDependencies->addDependency(MarkupCacheDependencies::REQUESTED_PAGE_DEPENDENCY); 40204fd306cSNickeau break; 40304fd306cSNickeau case PageSqlTreeListener::DESCENDANTS: 40404fd306cSNickeau $cacheDependencies->addDependency(MarkupCacheDependencies::PAGE_SYSTEM_DEPENDENCY); 4054cadd4f8SNickeau break; 4064cadd4f8SNickeau default: 4074cadd4f8SNickeau } 40804fd306cSNickeau } catch (ExceptionNotFound $e) { 40904fd306cSNickeau // not a fetcher markup run 41004fd306cSNickeau } 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(); 42604fd306cSNickeau } 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) { 43504fd306cSNickeau 4364cadd4f8SNickeau /** 4374cadd4f8SNickeau * We use id until path is full in the database 4384cadd4f8SNickeau */ 4394cadd4f8SNickeau $id = $sourceRow["ID"]; 44004fd306cSNickeau $contextualPage = MarkupPath::createMarkupFromId($id); 44104fd306cSNickeau if ($contextualPage->isHidden()) { 4424cadd4f8SNickeau continue; 4434cadd4f8SNickeau } 44404fd306cSNickeau if (!$contextualPage->exists()) { 44504fd306cSNickeau LogUtility::error("Internal Error: the page selected ($contextualPage) was not added. It does not exist and was deleted from the database index.", self::CANONICAL); 44604fd306cSNickeau $contextualPage->getDatabasePage()->delete(); 4474cadd4f8SNickeau continue; 4484cadd4f8SNickeau } 44904fd306cSNickeau $standardMetadata = $contextualPage->getMetadataForRendering(); 45004fd306cSNickeau $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); 46404fd306cSNickeau 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 /** 48004fd306cSNickeau * Split template 48104fd306cSNickeau * Splits the template into header, main and footer 48204fd306cSNickeau * in case of complex header 4834cadd4f8SNickeau */ 48404fd306cSNickeau $templateHeader = array(); 48504fd306cSNickeau $templateMain = $iteratorTemplateInstructions; 48604fd306cSNickeau $templateFooter = array(); 4874cadd4f8SNickeau $complexMarkupFound = $data[self::COMPLEX_MARKUP_FOUND]; 4884cadd4f8SNickeau if ($complexMarkupFound) { 4894cadd4f8SNickeau 4904cadd4f8SNickeau /** 4914cadd4f8SNickeau * @var Call $actualCall 4924cadd4f8SNickeau */ 4934cadd4f8SNickeau $templateCallStack = CallStack::createFromInstructions($iteratorTemplateInstructions); 49404fd306cSNickeau 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; 50204fd306cSNickeau $actualStack = [$actualCall->toCallArray()]; 5034cadd4f8SNickeau continue 2; 5044cadd4f8SNickeau case "listitem_close": 5054cadd4f8SNickeau case "tablerow_close": 50604fd306cSNickeau $actualStack[] = $actualCall->toCallArray(); 5074cadd4f8SNickeau $templateMain = $actualStack; 5084cadd4f8SNickeau $actualStack = []; 5094cadd4f8SNickeau continue 2; 5104cadd4f8SNickeau default: 51104fd306cSNickeau $actualStack[] = $actualCall->toCallArray(); 5124cadd4f8SNickeau } 5134cadd4f8SNickeau } 5144cadd4f8SNickeau $templateFooter = $actualStack; 51504fd306cSNickeau } 5164cadd4f8SNickeau 51704fd306cSNickeau $contextPath = $executionContext->getContextPath(); 51804fd306cSNickeau 51904fd306cSNickeau /** 52004fd306cSNickeau * Rendering 52104fd306cSNickeau */ 52204fd306cSNickeau $renderDoc = ""; 52304fd306cSNickeau 52404fd306cSNickeau /** 52504fd306cSNickeau * Header 52604fd306cSNickeau */ 52704fd306cSNickeau $iteratorHeaderInstructions = $data[self::BEFORE_TEMPLATE_CALLSTACK]; 52804fd306cSNickeau 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)) { 53604fd306cSNickeau $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 } 54604fd306cSNickeau } 5474cadd4f8SNickeau 5484cadd4f8SNickeau /** 54904fd306cSNickeau * Template 5504cadd4f8SNickeau */ 55104fd306cSNickeau try { 552*70bbd7f1Sgerardnico if (!empty($iteratorHeaderInstructions)) { 553*70bbd7f1Sgerardnico /** 554*70bbd7f1Sgerardnico * Hack: Rebuild the whole header to have also the table open 555*70bbd7f1Sgerardnico * to avoid the row_counter problem 556*70bbd7f1Sgerardnico */ 557*70bbd7f1Sgerardnico $templateHeader = array_merge($iteratorHeaderInstructions, $templateHeader); 558*70bbd7f1Sgerardnico } 559*70bbd7f1Sgerardnico $fetcherMarkup = FetcherMarkup::confChild() 56004fd306cSNickeau ->setRequestedContextPath($contextPath) 56104fd306cSNickeau ->setRequestedMimeToXhtml() 56204fd306cSNickeau ->setIsDocument(false) 563*70bbd7f1Sgerardnico ->setRequestedInstructions($templateHeader) 564*70bbd7f1Sgerardnico ->build(); 565*70bbd7f1Sgerardnico $renderDoc .= $fetcherMarkup->getFetchString(); 56604fd306cSNickeau } catch (ExceptionCompile $e) { 56704fd306cSNickeau LogUtility::error("Error while rendering the template header. Error: {$e->getMessage()}", self::CANONICAL); 56804fd306cSNickeau return false; 5694cadd4f8SNickeau } 5704cadd4f8SNickeau foreach ($rows as $row) { 57104fd306cSNickeau try { 572*70bbd7f1Sgerardnico $renderDoc .= $fetcherMarkup 573*70bbd7f1Sgerardnico ->setNextIteratorInstructionsWithContext($templateMain, $row) 57404fd306cSNickeau ->getFetchString(); 57504fd306cSNickeau } catch (ExceptionCompile $e) { 576*70bbd7f1Sgerardnico LogUtility::error("Error while rendering a data row. Error: {$e->getMessage()}", self::CANONICAL, $e); 57704fd306cSNickeau continue; 5784cadd4f8SNickeau } 5794cadd4f8SNickeau } 58004fd306cSNickeau try { 581*70bbd7f1Sgerardnico $renderDoc .= $fetcherMarkup 582*70bbd7f1Sgerardnico ->setNextIteratorInstructionsWithContext($templateFooter) 58304fd306cSNickeau ->getFetchString(); 58404fd306cSNickeau } catch (ExceptionCompile $e) { 58504fd306cSNickeau LogUtility::error("Error while rendering the template footer. Error: {$e->getMessage()}", self::CANONICAL); 58604fd306cSNickeau return false; 58704fd306cSNickeau } 5884cadd4f8SNickeau 5894cadd4f8SNickeau 5904cadd4f8SNickeau /** 59104fd306cSNickeau * Iterator Footer 5924cadd4f8SNickeau */ 5934cadd4f8SNickeau $callStackFooterInstructions = $data[self::AFTER_TEMPLATE_CALLSTACK]; 5944cadd4f8SNickeau if (!empty($callStackFooterInstructions)) { 59504fd306cSNickeau try { 596*70bbd7f1Sgerardnico $renderDoc .= $fetcherMarkup 597*70bbd7f1Sgerardnico ->setNextIteratorInstructionsWithContext($callStackFooterInstructions) 59804fd306cSNickeau ->getFetchString(); 59904fd306cSNickeau } catch (ExceptionCompile $e) { 60004fd306cSNickeau LogUtility::error("Error while rendering the iterator footer. Error: {$e->getMessage()}", self::CANONICAL); 60104fd306cSNickeau return false; 6024cadd4f8SNickeau } 60304fd306cSNickeau } 6044cadd4f8SNickeau 6054cadd4f8SNickeau /** 60604fd306cSNickeau * Renderer 6074cadd4f8SNickeau */ 60804fd306cSNickeau $renderer->doc .= $renderDoc; 6094cadd4f8SNickeau return true; 61004fd306cSNickeau 6114cadd4f8SNickeau } 6124cadd4f8SNickeau } 61337748cd8SNickeau // unsupported $mode 61437748cd8SNickeau return false; 61537748cd8SNickeau } 61637748cd8SNickeau 61737748cd8SNickeau 61837748cd8SNickeau} 61937748cd8SNickeau 620