xref: /plugin/combo/syntax/iterator.php (revision 70bbd7f1f72440223cc13f3495efdcb2b0a11514)
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