xref: /template/strap/ComboStrap/PageSqlTreeListener.php (revision 5b7a56ccb7c57144ce99d82ebd684c7eb5d4f441)
137748cd8SNickeau<?php
237748cd8SNickeau
337748cd8SNickeau
437748cd8SNickeaunamespace ComboStrap;
537748cd8SNickeau
637748cd8SNickeau
737748cd8SNickeauuse Antlr\Antlr4\Runtime\ParserRuleContext;
837748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\ErrorNode;
937748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\ParseTreeListener;
1037748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\ParseTreeWalker;
1137748cd8SNickeauuse Antlr\Antlr4\Runtime\Tree\TerminalNode;
1237748cd8SNickeauuse ComboStrap\PageSqlParser\PageSqlLexer;
1337748cd8SNickeauuse ComboStrap\PageSqlParser\PageSqlParser;
1437748cd8SNickeau
151fa8c418SNickeau
1637748cd8SNickeau/**
1737748cd8SNickeau * Class SqlTreeListener
1837748cd8SNickeau * @package ComboStrap\LogicalSqlAntlr
1937748cd8SNickeau *
2037748cd8SNickeau * The listener that is called by {@link  ParseTreeWalker::walk()}
2137748cd8SNickeau * that performs a walk on the given parse tree starting at the root
2237748cd8SNickeau * and going down recursively with depth-first search.
2337748cd8SNickeau *
2437748cd8SNickeau * The process is to check all token and to process them
2537748cd8SNickeau * with context
2637748cd8SNickeau */
2737748cd8SNickeaufinal class PageSqlTreeListener implements ParseTreeListener
2837748cd8SNickeau{
29c3437056SNickeau    const BACKLINKS = "backlinks";
3004fd306cSNickeau    const DESCENDANTS = "descendants";
3104fd306cSNickeau    const DEPTH = "depth";
3204fd306cSNickeau    const CANONICAL = PageSql::CANONICAL;
3337748cd8SNickeau    /**
3437748cd8SNickeau     * @var PageSqlLexer
3537748cd8SNickeau     */
3637748cd8SNickeau    private $lexer;
3737748cd8SNickeau    /**
3837748cd8SNickeau     * @var PageSqlParser
3937748cd8SNickeau     */
4037748cd8SNickeau    private $parser;
4137748cd8SNickeau    /**
4237748cd8SNickeau     * @var String
4337748cd8SNickeau     */
4437748cd8SNickeau    private $physicalSql;
4537748cd8SNickeau    /**
4637748cd8SNickeau     * @var int
4737748cd8SNickeau     */
4837748cd8SNickeau    private $ruleState;
4937748cd8SNickeau
5037748cd8SNickeau    private const STATE_VALUES = [
5137748cd8SNickeau        PageSqlParser::RULE_columns,
5237748cd8SNickeau        PageSqlParser::RULE_tables,
5337748cd8SNickeau        PageSqlParser::RULE_predicates,
5437748cd8SNickeau        PageSqlParser::RULE_orderBys,
5537748cd8SNickeau        PageSqlParser::RULE_limit,
5637748cd8SNickeau    ];
5737748cd8SNickeau    /**
5837748cd8SNickeau     * @var string[]
5937748cd8SNickeau     */
6037748cd8SNickeau    private $parameters = [];
6137748cd8SNickeau    /**
6237748cd8SNickeau     * @var array
6337748cd8SNickeau     */
641fa8c418SNickeau    private $columns = [];
651fa8c418SNickeau    /**
661fa8c418SNickeau     * @var string
671fa8c418SNickeau     */
681fa8c418SNickeau    private $pageSqlString;
69c3437056SNickeau    /**
70c3437056SNickeau     * backlinks or pages
71c3437056SNickeau     * @var string
72c3437056SNickeau     */
7304fd306cSNickeau    private $tableName;
7404fd306cSNickeau    /**
7504fd306cSNickeau     * @var string - to store the predicate column
7604fd306cSNickeau     */
7704fd306cSNickeau    private $actualPredicateColumn;
7804fd306cSNickeau    /**
7904fd306cSNickeau     * @var MarkupPath|null
8004fd306cSNickeau     */
8104fd306cSNickeau    private ?MarkupPath $requestedPage;
8204fd306cSNickeau
8337748cd8SNickeau
8437748cd8SNickeau    /**
8537748cd8SNickeau     * SqlTreeListener constructor.
8637748cd8SNickeau     *
8737748cd8SNickeau     * @param PageSqlLexer $lexer
8837748cd8SNickeau     * @param PageSqlParser $parser
891fa8c418SNickeau     * @param string $sql
9004fd306cSNickeau     * @param MarkupPath|null $pageContext
9137748cd8SNickeau     */
9204fd306cSNickeau    public function __construct(PageSqlLexer $lexer, PageSqlParser $parser, string $sql, MarkupPath $pageContext = null)
9337748cd8SNickeau    {
9437748cd8SNickeau        $this->lexer = $lexer;
9537748cd8SNickeau        $this->parser = $parser;
961fa8c418SNickeau        $this->pageSqlString = $sql;
9704fd306cSNickeau        if ($pageContext == null) {
9804fd306cSNickeau            $this->requestedPage = MarkupPath::createPageFromPathObject(ExecutionContext::getActualOrCreateFromEnv()->getContextPath());
9904fd306cSNickeau        } else {
10004fd306cSNickeau            $this->requestedPage = $pageContext;
10104fd306cSNickeau        }
10237748cd8SNickeau    }
10337748cd8SNickeau
10437748cd8SNickeau
10537748cd8SNickeau    /**
10637748cd8SNickeau     * Leaf node
10737748cd8SNickeau     * @param TerminalNode $node
10837748cd8SNickeau     */
10937748cd8SNickeau    public function visitTerminal(TerminalNode $node): void
11037748cd8SNickeau    {
11137748cd8SNickeau
11237748cd8SNickeau        $type = $node->getSymbol()->getType();
11337748cd8SNickeau        $text = $node->getText();
11437748cd8SNickeau        switch ($type) {
11537748cd8SNickeau            case PageSqlParser::SELECT:
11637748cd8SNickeau                $this->physicalSql .= "select\n\t*\n";
11737748cd8SNickeau
11837748cd8SNickeau                /**
11937748cd8SNickeau                 * The from select is optional
12037748cd8SNickeau                 * Check if it's there
12137748cd8SNickeau                 */
12237748cd8SNickeau                $parent = $node->getParent();
12337748cd8SNickeau                for ($i = 0; $i < $parent->getChildCount(); $i++) {
12437748cd8SNickeau                    $child = $parent->getChild($i);
12537748cd8SNickeau                    if ($child instanceof ParserRuleContext) {
12637748cd8SNickeau                        /**
12737748cd8SNickeau                         * @var ParserRuleContext $child
12837748cd8SNickeau                         */
12937748cd8SNickeau                        if ($child->getRuleIndex() === PageSqlParser::RULE_tables) {
13037748cd8SNickeau                            return;
13137748cd8SNickeau                        }
13237748cd8SNickeau                    }
13337748cd8SNickeau                }
13437748cd8SNickeau                $this->physicalSql .= "from\n\tpages\n";
13537748cd8SNickeau                break;
13637748cd8SNickeau            case PageSqlParser::SqlName:
13737748cd8SNickeau                switch ($this->ruleState) {
13837748cd8SNickeau                    case PageSqlParser::RULE_predicates:
13937748cd8SNickeau
140c3437056SNickeau                        if (substr($this->physicalSql, -1) === "\n") {
141c3437056SNickeau                            $this->physicalSql .= "\t";
142c3437056SNickeau                        }
14304fd306cSNickeau
14404fd306cSNickeau                        // variable name
14504fd306cSNickeau                        $variableName = strtolower($text);
146*5b7a56ccSgerardnico                        switch ($variableName) {
147*5b7a56ccSgerardnico                            case DatabasePageRow::IS_HOME_COLUMN:
148*5b7a56ccSgerardnico                            {
14904fd306cSNickeau                                /**
15004fd306cSNickeau                                 * Deprecation of is_home for is_index
15104fd306cSNickeau                                 */
15204fd306cSNickeau                                $variableName = DatabasePageRow::IS_INDEX_COLUMN;
153*5b7a56ccSgerardnico                                break;
15404fd306cSNickeau                            }
155*5b7a56ccSgerardnico                            case CreationDate::PROPERTY_NAME:
156*5b7a56ccSgerardnico                            case ModificationDate::PROPERTY_NAME:
157*5b7a56ccSgerardnico                            case PagePublicationDate::PROPERTY_NAME:
158*5b7a56ccSgerardnico                            case StartDate::PROPERTY_NAME:
159*5b7a56ccSgerardnico                            case ReplicationDate::PROPERTY_NAME:
160*5b7a56ccSgerardnico                            case EndDate::PROPERTY_NAME:
161*5b7a56ccSgerardnico                            {
162*5b7a56ccSgerardnico                                $variableName = "date({$variableName})";
163*5b7a56ccSgerardnico                            }
164*5b7a56ccSgerardnico                        }
165*5b7a56ccSgerardnico
16604fd306cSNickeau                        $this->actualPredicateColumn = $variableName;
16704fd306cSNickeau                        if ($this->tableName === self::BACKLINKS) {
168c3437056SNickeau                            $variableName = "p." . $variableName;
169c3437056SNickeau                        }
17004fd306cSNickeau                        if ($variableName === self::DEPTH) {
17104fd306cSNickeau                            $variableName = "level";
17204fd306cSNickeau                        }
173c3437056SNickeau                        $this->physicalSql .= "{$variableName} ";
17437748cd8SNickeau                        break;
17504fd306cSNickeau                    case PageSqlParser::RULE_orderBys:
176c3437056SNickeau                        $variableName = strtolower($text);
17704fd306cSNickeau                        if ($this->tableName === self::BACKLINKS) {
178c3437056SNickeau                            $variableName = "p." . $variableName;
179c3437056SNickeau                        }
180c3437056SNickeau                        $this->physicalSql .= "\t{$variableName} ";
18137748cd8SNickeau                        break;
18237748cd8SNickeau                    case PageSqlParser::RULE_columns:
18337748cd8SNickeau                        $this->columns[] = $text;
18437748cd8SNickeau                        break;
18537748cd8SNickeau                }
18637748cd8SNickeau                break;
18737748cd8SNickeau            case PageSqlParser::EQUAL:
18837748cd8SNickeau            case PageSqlParser::LIKE:
18937748cd8SNickeau            case PageSqlParser::GLOB:
19037748cd8SNickeau            case PageSqlParser::LESS_THAN_OR_EQUAL:
19137748cd8SNickeau            case PageSqlParser::LESS_THAN:
19237748cd8SNickeau            case PageSqlParser::GREATER_THAN:
19337748cd8SNickeau            case PageSqlParser::GREATER_THAN_OR_EQUAL:
194824bea8fSgerardnico            case PageSqlParser::NOT_EQUAL:
19537748cd8SNickeau                switch ($this->ruleState) {
19637748cd8SNickeau                    case PageSqlParser::RULE_predicates:
19737748cd8SNickeau                        $this->physicalSql .= "{$text} ";
19837748cd8SNickeau                }
19937748cd8SNickeau                break;
20004fd306cSNickeau            case PageSqlParser::RANDOM:
20104fd306cSNickeau                $this->physicalSql .= "\trandom()";
20204fd306cSNickeau                break;
203*5b7a56ccSgerardnico            case PageSqlParser::NOW:
204*5b7a56ccSgerardnico                $this->physicalSql .= "date('now')";
205*5b7a56ccSgerardnico                break;
20637748cd8SNickeau            case PageSqlParser::StringLiteral:
20737748cd8SNickeau                switch ($this->ruleState) {
20837748cd8SNickeau                    case PageSqlParser::RULE_predicates:
20937748cd8SNickeau                        // Parameters
21037748cd8SNickeau                        if (
21137748cd8SNickeau                            ($text[0] === "'" and $text[strlen($text) - 1] === "'")
21237748cd8SNickeau                            ||
21337748cd8SNickeau                            ($text[0] === '"' and $text[strlen($text) - 1] === '"')) {
21437748cd8SNickeau                            $quote = $text[0];
21537748cd8SNickeau                            $text = substr($text, 1, strlen($text) - 2);
21637748cd8SNickeau                            $text = str_replace("$quote$quote", "$quote", $text);
21737748cd8SNickeau                        }
21837748cd8SNickeau                        $this->parameters[] = $text;
21937748cd8SNickeau                        $this->physicalSql .= "?";
22037748cd8SNickeau                        break;
22137748cd8SNickeau                }
22237748cd8SNickeau                break;
22337748cd8SNickeau            case PageSqlParser:: AND:
22437748cd8SNickeau            case PageSqlParser:: OR:
22537748cd8SNickeau                if ($this->ruleState === PageSqlParser::RULE_predicates) {
22637748cd8SNickeau                    $this->physicalSql .= " {$text}\n";
22737748cd8SNickeau                }
22837748cd8SNickeau                return;
2291fa8c418SNickeau            case PageSqlParser::LIMIT:
23037748cd8SNickeau            case PageSqlParser::NOT:
23137748cd8SNickeau                $this->physicalSql .= "{$text} ";
23237748cd8SNickeau                return;
23337748cd8SNickeau            case PageSqlParser::DESC:
23437748cd8SNickeau            case PageSqlParser::LPAREN:
23537748cd8SNickeau            case PageSqlParser::RPAREN:
23637748cd8SNickeau            case PageSqlParser::ASC:
23737748cd8SNickeau                $this->physicalSql .= "{$text}";
23837748cd8SNickeau                break;
23937748cd8SNickeau            case PageSqlParser::COMMA:
24037748cd8SNickeau                switch ($this->ruleState) {
24137748cd8SNickeau                    case PageSqlParser::RULE_columns:
24237748cd8SNickeau                        return;
24337748cd8SNickeau                    case PageSqlParser::RULE_orderBys:
24437748cd8SNickeau                        $this->physicalSql .= "{$text}\n";
24537748cd8SNickeau                        return;
24637748cd8SNickeau                    default:
24737748cd8SNickeau                        $this->physicalSql .= "{$text}";
24837748cd8SNickeau                        return;
24937748cd8SNickeau                }
25037748cd8SNickeau            case PageSqlParser::ESCAPE:
25137748cd8SNickeau                $this->physicalSql .= " {$text} ";
25237748cd8SNickeau                return;
25337748cd8SNickeau            case PageSqlParser::Number:
25437748cd8SNickeau                switch ($this->ruleState) {
25537748cd8SNickeau                    case PageSqlParser::RULE_limit:
25637748cd8SNickeau                        $this->physicalSql .= "{$text}";
25737748cd8SNickeau                        return;
25837748cd8SNickeau                    case PageSqlParser::RULE_predicates:
25904fd306cSNickeau                        switch ($this->actualPredicateColumn) {
26004fd306cSNickeau                            case self::DEPTH:
26104fd306cSNickeau                                if ($this->requestedPage !== null) {
26204fd306cSNickeau                                    $level = PageLevel::createForPage($this->requestedPage)->getValue();
26304fd306cSNickeau                                    try {
26404fd306cSNickeau                                        $predicateValue = DataType::toInteger($text);
26504fd306cSNickeau                                    } catch (ExceptionCompile $e) {
26604fd306cSNickeau                                        // should not happen due to the parsing but yeah
26704fd306cSNickeau                                        LogUtility::msg("The value of the depth attribute ($text) is not an integer", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
26804fd306cSNickeau                                        $predicateValue = 0;
26904fd306cSNickeau                                    }
27004fd306cSNickeau                                    $this->parameters[] = $predicateValue + $level;
27104fd306cSNickeau                                } else {
27204fd306cSNickeau                                    LogUtility::msg("The requested page is unknown and is mandatory with the depth attribute", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
27337748cd8SNickeau                                    $this->parameters[] = $text;
27404fd306cSNickeau                                }
27504fd306cSNickeau                                break;
27604fd306cSNickeau                            default:
27704fd306cSNickeau                                try {
27804fd306cSNickeau                                    if (strpos($text, ".") !== false) {
27904fd306cSNickeau                                        $this->parameters[] = DataType::toFloat($text);
28004fd306cSNickeau                                    } else {
28104fd306cSNickeau                                        $this->parameters[] = DataType::toInteger($text);
28204fd306cSNickeau                                    }
28304fd306cSNickeau                                } catch (ExceptionBadArgument $e) {
28404fd306cSNickeau                                    LogUtility::error("The value of the column $this->actualPredicateColumn ($text) could not be transformed as a number. Error: {$e->getMessage()}", self::CANONICAL);
28504fd306cSNickeau                                    $this->parameters[] = $text;
28604fd306cSNickeau                                }
28704fd306cSNickeau                                break;
28804fd306cSNickeau                        }
28937748cd8SNickeau                        $this->physicalSql .= "?";
29037748cd8SNickeau                        return;
29137748cd8SNickeau                    default:
29237748cd8SNickeau                        $this->physicalSql .= "{$text} ";
29337748cd8SNickeau                        return;
29437748cd8SNickeau                }
29537748cd8SNickeau            default:
29637748cd8SNickeau                // We do nothing because the token may have been printed at a higher level such as order by
29737748cd8SNickeau        }
29837748cd8SNickeau    }
29937748cd8SNickeau
30037748cd8SNickeau
30137748cd8SNickeau    public
30237748cd8SNickeau    function visitErrorNode(ErrorNode $node): void
30337748cd8SNickeau    {
3041fa8c418SNickeau        $charPosition = $node->getSymbol()->getStartIndex();
3051fa8c418SNickeau        $textMakingTheError = $node->getText(); // $this->lexer->getText();
3061fa8c418SNickeau
3071fa8c418SNickeau        $position = "at position: $charPosition";
3081fa8c418SNickeau        if ($charPosition != 0) {
3091fa8c418SNickeau            $position .= ", in `" . substr($this->pageSqlString, $charPosition, -1) . "`";
3101fa8c418SNickeau        }
3111fa8c418SNickeau        $message = "PageSql Parsing Error: The token `$textMakingTheError` was unexpected ($position).";
3121fa8c418SNickeau        throw new \RuntimeException($message);
3131fa8c418SNickeau
31437748cd8SNickeau    }
31537748cd8SNickeau
31637748cd8SNickeau
31737748cd8SNickeau    /**
31837748cd8SNickeau     *
31937748cd8SNickeau     * Parent Node
32037748cd8SNickeau     *
32137748cd8SNickeau     * On each node, enterRule is called before recursively walking down into child nodes,
32237748cd8SNickeau     * then {@link PageSqlTreeListener::exitEveryRule()} is called after the recursive call to wind up.
32337748cd8SNickeau     * Parameters:
32437748cd8SNickeau     * @param ParserRuleContext $ctx
32537748cd8SNickeau     */
32637748cd8SNickeau    public
32737748cd8SNickeau    function enterEveryRule(ParserRuleContext $ctx): void
32837748cd8SNickeau    {
32937748cd8SNickeau
33037748cd8SNickeau        $ruleIndex = $ctx->getRuleIndex();
33137748cd8SNickeau        if (in_array($ruleIndex, self::STATE_VALUES)) {
33237748cd8SNickeau            $this->ruleState = $ruleIndex;
33337748cd8SNickeau        }
33437748cd8SNickeau        switch ($ruleIndex) {
33537748cd8SNickeau            case PageSqlParser::RULE_orderBys:
33637748cd8SNickeau                $this->physicalSql .= "order by\n";
33737748cd8SNickeau                break;
33837748cd8SNickeau            case PageSqlParser::RULE_tables:
33937748cd8SNickeau                $this->physicalSql .= "from\n";
34037748cd8SNickeau                break;
34137748cd8SNickeau            case PageSqlParser::RULE_predicates:
342c3437056SNickeau                /**
34304fd306cSNickeau                 * Backlinks/Descendant query adds already a where clause
344c3437056SNickeau                 */
34504fd306cSNickeau                switch ($this->tableName) {
34604fd306cSNickeau                    case self::BACKLINKS:
347c3437056SNickeau                        $this->physicalSql .= "\tand ";
34804fd306cSNickeau                        break;
34904fd306cSNickeau                    case self::DESCENDANTS:
35004fd306cSNickeau                        $this->physicalSql .= "\tand (";
35104fd306cSNickeau                        break;
35204fd306cSNickeau                    default:
35337748cd8SNickeau                        $this->physicalSql .= "where\n";
35404fd306cSNickeau                        break;
355c3437056SNickeau                }
35637748cd8SNickeau                break;
35704fd306cSNickeau            case
35804fd306cSNickeau            PageSqlParser::RULE_functionNames:
35937748cd8SNickeau                // Print the function name
36037748cd8SNickeau                $this->physicalSql .= $ctx->getText();
36137748cd8SNickeau                break;
36237748cd8SNickeau            case PageSqlParser::RULE_tableNames:
36337748cd8SNickeau                // Print the table name
364c3437056SNickeau                $tableName = strtolower($ctx->getText());
36504fd306cSNickeau                $this->tableName = $tableName;
36604fd306cSNickeau                switch ($tableName) {
36704fd306cSNickeau                    case self::BACKLINKS:
368c3437056SNickeau                        $tableName = <<<EOF
369c3437056SNickeau    pages p
370c3437056SNickeau    join page_references pr on pr.page_id = p.page_id
371c3437056SNickeauwhere
372c3437056SNickeau    pr.reference = ?
373c3437056SNickeau
374c3437056SNickeauEOF;
37504fd306cSNickeau
37604fd306cSNickeau                        if ($this->requestedPage !== null) {
37704fd306cSNickeau                            $this->parameters[] = $this->requestedPage->getPathObject()->toAbsoluteId();
378c3437056SNickeau                        } else {
37904fd306cSNickeau                            LogUtility::msg("The page is unknown. A Page SQL with backlinks should be asked within a page request scope.", LogUtility::LVL_MSG_ERROR, PageSql::CANONICAL);
38004fd306cSNickeau                            $this->parameters[] = "unknown page";
38104fd306cSNickeau                        }
38204fd306cSNickeau                        break;
38304fd306cSNickeau                    case self::DESCENDANTS:
38404fd306cSNickeau                        if ($this->requestedPage !== null) {
38504fd306cSNickeau
38604fd306cSNickeau                            if (!$this->requestedPage->isIndexPage()) {
38704fd306cSNickeau                                LogUtility::warning("Descendants should be asked from an index page.", PageSql::CANONICAL);
38804fd306cSNickeau                            }
38904fd306cSNickeau
39004fd306cSNickeau                            $path = $this->requestedPage->getPathObject();
39104fd306cSNickeau                            $this->parameters[] = $path->toAbsoluteId();
39204fd306cSNickeau                            try {
39304fd306cSNickeau                                $likePredicatequery = $path->getParent()->resolve("%")->toAbsoluteId();
39404fd306cSNickeau                            } catch (ExceptionNotFound $e) {
39504fd306cSNickeau                                // root
39604fd306cSNickeau                                $likePredicatequery = "%";
39704fd306cSNickeau                            }
39804fd306cSNickeau                            $this->parameters[] = $likePredicatequery;
39904fd306cSNickeau                            $level = PageLevel::createForPage($this->requestedPage)->getValue();
40004fd306cSNickeau                            $this->parameters[] = $level;
40104fd306cSNickeau
40204fd306cSNickeau                        } else {
40304fd306cSNickeau                            LogUtility::msg("The page is unknown. A Page SQL with a depth attribute should be asked within a page request scope. The start depth has been set to 0", LogUtility::LVL_MSG_ERROR, PageSql::CANONICAL);
40404fd306cSNickeau                            $this->parameters[] = "";
40504fd306cSNickeau                            $this->parameters[] = "";
40604fd306cSNickeau                            $this->parameters[] = "";
40704fd306cSNickeau                        }
40804fd306cSNickeau                        $tableName = "\tpages\nwhere\n\tpath != ?\n\tand path like ?\n\tand level >= ?\n";
40904fd306cSNickeau                        break;
41004fd306cSNickeau                    default:
411c3437056SNickeau                        $tableName = "\t$tableName\n";
41204fd306cSNickeau                        break;
413c3437056SNickeau                }
414c3437056SNickeau                $this->physicalSql .= $tableName;
41537748cd8SNickeau                break;
41637748cd8SNickeau        }
41737748cd8SNickeau
41837748cd8SNickeau
41937748cd8SNickeau    }
42037748cd8SNickeau
42137748cd8SNickeau    /**
42237748cd8SNickeau     *
42337748cd8SNickeau     * Parent Node
42437748cd8SNickeau     *
42537748cd8SNickeau     * On each node, {@link PageSqlTreeListener::enterEveryRule()} is called before recursively walking down into child nodes,
42637748cd8SNickeau     * then {@link PageSqlTreeListener::exitEveryRule()} is called after the recursive call to wind up.
42737748cd8SNickeau     * @param ParserRuleContext $ctx
42837748cd8SNickeau     */
42937748cd8SNickeau    public
43037748cd8SNickeau    function exitEveryRule(ParserRuleContext $ctx): void
43137748cd8SNickeau    {
43237748cd8SNickeau        $ruleIndex = $ctx->getRuleIndex();
43337748cd8SNickeau        switch ($ruleIndex) {
43437748cd8SNickeau            case PageSqlParser::RULE_orderBys:
43537748cd8SNickeau                $this->physicalSql .= "\n";
43637748cd8SNickeau                break;
43704fd306cSNickeau            case PageSqlParser::RULE_predicates:
43804fd306cSNickeau                if ($this->tableName == self::DESCENDANTS) {
43904fd306cSNickeau                    $this->physicalSql .= ")";
44004fd306cSNickeau                }
44104fd306cSNickeau                $this->physicalSql .= "\n";
44204fd306cSNickeau                break;
44337748cd8SNickeau        }
44437748cd8SNickeau
44537748cd8SNickeau    }
44637748cd8SNickeau
44737748cd8SNickeau    public
44837748cd8SNickeau    function getParameters(): array
44937748cd8SNickeau    {
45037748cd8SNickeau        return $this->parameters;
45137748cd8SNickeau    }
45237748cd8SNickeau
45337748cd8SNickeau    public
45437748cd8SNickeau    function getColumns(): array
45537748cd8SNickeau    {
45637748cd8SNickeau        return $this->columns;
45737748cd8SNickeau    }
45837748cd8SNickeau
4594cadd4f8SNickeau    public function getTable(): ?string
4604cadd4f8SNickeau    {
46104fd306cSNickeau        return $this->tableName;
4624cadd4f8SNickeau    }
4634cadd4f8SNickeau
46437748cd8SNickeau    /**
46537748cd8SNickeau     * For documentation
46637748cd8SNickeau     * @param ParserRuleContext $ctx
46737748cd8SNickeau     * @return string
46837748cd8SNickeau     */
46937748cd8SNickeau    private
47037748cd8SNickeau    function getRuleName(ParserRuleContext $ctx): string
47137748cd8SNickeau    {
47237748cd8SNickeau        $ruleNames = $this->parser->getRuleNames();
47337748cd8SNickeau        return $ruleNames[$ctx->getRuleIndex()];
47437748cd8SNickeau    }
47537748cd8SNickeau
47637748cd8SNickeau    /**
47737748cd8SNickeau     * For documentation
47837748cd8SNickeau     * @param TerminalNode $node
47937748cd8SNickeau     * @return string|null
48037748cd8SNickeau     */
48137748cd8SNickeau    private
48237748cd8SNickeau    function getTokenName(TerminalNode $node)
48337748cd8SNickeau    {
48437748cd8SNickeau        $token = $node->getSymbol();
48537748cd8SNickeau        return $this->lexer->getVocabulary()->getSymbolicName($token->getType());
48637748cd8SNickeau    }
48737748cd8SNickeau
48837748cd8SNickeau    public
48937748cd8SNickeau    function getPhysicalSql(): string
49037748cd8SNickeau    {
49137748cd8SNickeau        return $this->physicalSql;
49237748cd8SNickeau    }
49337748cd8SNickeau
49437748cd8SNickeau
49537748cd8SNickeau}
496