1<?php
2
3use ComboStrap\ExceptionBadSyntax;
4use ComboStrap\ExecutionContext;
5use ComboStrap\MarkupPath;
6use ComboStrap\PipelineUtility;
7use ComboStrap\PluginUtility;
8use ComboStrap\SlotSystem;
9use ComboStrap\Template;
10
11
12/**
13 *
14 * Variable
15 */
16class syntax_plugin_combo_variable extends DokuWiki_Syntax_Plugin
17{
18
19
20    const TAG = "variable";
21
22
23    const CANONICAL = self::TAG;
24    const EXPRESSION_ATTRIBUTE = "expression";
25
26    public static function isVariable($ref): bool
27    {
28        return substr($ref, 0, 1) === Template::DOLLAR_VARIABLE_PREFIX;
29    }
30
31    /**
32     * Template rendering will be context based
33     * (first step to delete the template tag)
34     * @param string $string
35     * @param array|null $contextData
36     * @return string
37     */
38    public static function replaceVariablesWithValuesFromContext(string $string, array $contextData = null): string
39    {
40        if ($contextData === null) {
41            $executionContext = ExecutionContext::getActualOrCreateFromEnv();
42            $contextData = $executionContext->getContextData();
43        }
44        return Template::create($string)->setProperties($contextData)->render();
45    }
46
47
48    public function getSort(): int
49    {
50        return 200;
51    }
52
53    public function getType(): string
54    {
55        return 'substition';
56    }
57
58
59    /**
60     *
61     * How Dokuwiki will add P element
62     *
63     *  * 'normal' - The plugin can be used inside paragraphs (inline)
64     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
65     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
66     *
67     * @see DokuWiki_Syntax_Plugin::getPType()
68     *
69     * This is the equivalent of inline or block for css
70     */
71    public function getPType(): string
72    {
73        return 'normal';
74    }
75
76    /**
77     * @return array
78     * Allow which kind of plugin inside
79     *
80     * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
81     * because we manage self the content and we call self the parser
82     *
83     * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php
84     */
85    function getAllowedTypes(): array
86    {
87        return array();
88    }
89
90
91    public function connectTo($mode)
92    {
93
94        $this->Lexer->addSpecialPattern(Template::CAPTURE_PATTERN_SHORT, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
95        $this->Lexer->addSpecialPattern(Template::CAPTURE_PATTERN_LONG, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
96
97    }
98
99
100    /**
101     * Handle the syntax
102     *
103     * At the end of the parser, the `section_open` and `section_close` calls
104     * are created in {@link action_plugin_combo_instructionspostprocessing}
105     * and the text inside for the toc is captured
106     *
107     * @param string $match
108     * @param int $state
109     * @param int $pos
110     * @param Doku_Handler $handler
111     * @return array
112     */
113    public function handle($match, $state, $pos, Doku_Handler $handler): array
114    {
115        if ($state == DOKU_LEXER_SPECIAL) {
116            $lengthLongPrefix = strlen(Template::LONG_PREFIX);
117            /**
118             * Recreating a pipeline expression
119             */
120            if (substr($match, 0, $lengthLongPrefix) === Template::LONG_PREFIX) {
121                $expression = trim(substr($match, $lengthLongPrefix, -1));
122                if (!in_array($expression[0], PipelineUtility::QUOTES_CHARACTERS)) {
123                    $expression = "\${$expression}";
124                }
125            } else {
126                $expression = "\"$match\"";
127            }
128            return [
129                self::EXPRESSION_ATTRIBUTE => $expression,
130                PluginUtility::STATE => $state
131            ];
132        }
133        return array();
134    }
135
136    public function render($format, $renderer, $data): bool
137    {
138
139        switch ($format) {
140            case "xhtml":
141            {
142                /**
143                 * @var Doku_Renderer_xhtml $renderer
144                 */
145                $state = $data[PluginUtility::STATE];
146                if ($state === DOKU_LEXER_SPECIAL) {
147                    $expression = $data[self::EXPRESSION_ATTRIBUTE];
148                    try {
149                        $execute = PipelineUtility::execute($expression);
150                    } catch (ExceptionBadSyntax $e) {
151                        $renderer->doc .= $e->getMessage();
152                        return false;
153                    }
154                    $renderer->doc .= $execute;
155                    return true;
156                }
157                break;
158            }
159        }
160        return false;
161    }
162
163
164}
165