xref: /plugin/combo/syntax/fragment.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1*04fd306cSNickeau<?php
2*04fd306cSNickeau
3*04fd306cSNickeau
4*04fd306cSNickeauuse ComboStrap\ExceptionNotFound;
5*04fd306cSNickeauuse ComboStrap\ExecutionContext;
6*04fd306cSNickeauuse ComboStrap\FragmentTag;
7*04fd306cSNickeauuse ComboStrap\MarkupCacheDependencies;
8*04fd306cSNickeauuse ComboStrap\CacheManager;
9*04fd306cSNickeauuse ComboStrap\CallStack;
10*04fd306cSNickeauuse ComboStrap\Canonical;
11*04fd306cSNickeauuse ComboStrap\ExceptionCompile;
12*04fd306cSNickeauuse ComboStrap\LogUtility;
13*04fd306cSNickeauuse ComboStrap\MarkupPath;
14*04fd306cSNickeauuse ComboStrap\CreationDate;
15*04fd306cSNickeauuse ComboStrap\PagePath;
16*04fd306cSNickeauuse ComboStrap\PagePublicationDate;
17*04fd306cSNickeauuse ComboStrap\PluginUtility;
18*04fd306cSNickeauuse ComboStrap\MarkupRenderUtility;
19*04fd306cSNickeauuse ComboStrap\ResourceName;
20*04fd306cSNickeauuse ComboStrap\TagAttributes;
21*04fd306cSNickeauuse ComboStrap\XmlTagProcessing;
22*04fd306cSNickeau
23*04fd306cSNickeau
24*04fd306cSNickeaurequire_once(__DIR__ . "/../ComboStrap/PluginUtility.php");
25*04fd306cSNickeau
26*04fd306cSNickeau/**
27*04fd306cSNickeau *
28*04fd306cSNickeau * Fragment
29*04fd306cSNickeau *
30*04fd306cSNickeau * A fragment is a part of a markup file
31*04fd306cSNickeau * that captures the instructions
32*04fd306cSNickeau * and then render them with {@link \ComboStrap\FetcherMarkup}
33*04fd306cSNickeau * with different {@link \ComboStrap\FetcherMarkupBuilder::setContextData() context data}
34*04fd306cSNickeau * for each page.
35*04fd306cSNickeau *
36*04fd306cSNickeau * It should be used inside an iterator.
37*04fd306cSNickeau *
38*04fd306cSNickeau *
39*04fd306cSNickeau *
40*04fd306cSNickeau */
41*04fd306cSNickeauclass syntax_plugin_combo_fragment extends DokuWiki_Syntax_Plugin
42*04fd306cSNickeau{
43*04fd306cSNickeau
44*04fd306cSNickeau
45*04fd306cSNickeau    /**
46*04fd306cSNickeau     * Syntax Type.
47*04fd306cSNickeau     *
48*04fd306cSNickeau     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
49*04fd306cSNickeau     * @see https://www.dokuwiki.org/devel:syntax_plugins#syntax_types
50*04fd306cSNickeau     * @see DokuWiki_Syntax_Plugin::getType()
51*04fd306cSNickeau     */
52*04fd306cSNickeau    function getType(): string
53*04fd306cSNickeau    {
54*04fd306cSNickeau        return 'formatting';
55*04fd306cSNickeau    }
56*04fd306cSNickeau
57*04fd306cSNickeau    /**
58*04fd306cSNickeau     * How Dokuwiki will add P element
59*04fd306cSNickeau     *
60*04fd306cSNickeau     * * 'normal' - Inline
61*04fd306cSNickeau     *  * 'block' - Block (p are not created inside)
62*04fd306cSNickeau     *  * 'stack' - Block (p can be created inside)
63*04fd306cSNickeau     *
64*04fd306cSNickeau     * @see DokuWiki_Syntax_Plugin::getPType()
65*04fd306cSNickeau     * @see https://www.dokuwiki.org/devel:syntax_plugins#ptype
66*04fd306cSNickeau     */
67*04fd306cSNickeau    function getPType(): string
68*04fd306cSNickeau    {
69*04fd306cSNickeau        /**
70*04fd306cSNickeau         * No P please
71*04fd306cSNickeau         */
72*04fd306cSNickeau        return 'normal';
73*04fd306cSNickeau    }
74*04fd306cSNickeau
75*04fd306cSNickeau    /**
76*04fd306cSNickeau     * @return array
77*04fd306cSNickeau     * Allow which kind of plugin inside
78*04fd306cSNickeau     *
79*04fd306cSNickeau     * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
80*04fd306cSNickeau     * because we manage self the content and we call self the parser
81*04fd306cSNickeau     *
82*04fd306cSNickeau     * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php
83*04fd306cSNickeau     */
84*04fd306cSNickeau    function getAllowedTypes(): array
85*04fd306cSNickeau    {
86*04fd306cSNickeau
87*04fd306cSNickeau        return array('baseonly', 'container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs');
88*04fd306cSNickeau    }
89*04fd306cSNickeau
90*04fd306cSNickeau    function getSort(): int
91*04fd306cSNickeau    {
92*04fd306cSNickeau        return 201;
93*04fd306cSNickeau    }
94*04fd306cSNickeau
95*04fd306cSNickeau    public function accepts($mode)
96*04fd306cSNickeau    {
97*04fd306cSNickeau        return syntax_plugin_combo_preformatted::disablePreformatted($mode);
98*04fd306cSNickeau    }
99*04fd306cSNickeau
100*04fd306cSNickeau
101*04fd306cSNickeau    function connectTo($mode)
102*04fd306cSNickeau    {
103*04fd306cSNickeau
104*04fd306cSNickeau        foreach (FragmentTag::TAGS as $tag) {
105*04fd306cSNickeau            $pattern = XmlTagProcessing::getContainerTagPattern($tag);
106*04fd306cSNickeau            $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
107*04fd306cSNickeau        }
108*04fd306cSNickeau
109*04fd306cSNickeau
110*04fd306cSNickeau    }
111*04fd306cSNickeau
112*04fd306cSNickeau
113*04fd306cSNickeau    public function postConnect()
114*04fd306cSNickeau    {
115*04fd306cSNickeau        foreach (FragmentTag::TAGS as $tag) {
116*04fd306cSNickeau            $this->Lexer->addExitPattern('</' . $tag . '>', PluginUtility::getModeFromTag($this->getPluginComponent()));
117*04fd306cSNickeau        }
118*04fd306cSNickeau
119*04fd306cSNickeau
120*04fd306cSNickeau    }
121*04fd306cSNickeau
122*04fd306cSNickeau
123*04fd306cSNickeau    /**
124*04fd306cSNickeau     *
125*04fd306cSNickeau     * The handle function goal is to parse the matched syntax through the pattern function
126*04fd306cSNickeau     * and to return the result for use in the renderer
127*04fd306cSNickeau     * This result is always cached until the page is modified.
128*04fd306cSNickeau     * @param string $match
129*04fd306cSNickeau     * @param int $state
130*04fd306cSNickeau     * @param int $pos - byte position in the original source file
131*04fd306cSNickeau     * @param Doku_Handler $handler
132*04fd306cSNickeau     * @return array
133*04fd306cSNickeau     * @throws Exception
134*04fd306cSNickeau     * @see DokuWiki_Syntax_Plugin::handle()
135*04fd306cSNickeau     *
136*04fd306cSNickeau     */
137*04fd306cSNickeau    function handle($match, $state, $pos, Doku_Handler $handler): array
138*04fd306cSNickeau    {
139*04fd306cSNickeau
140*04fd306cSNickeau        switch ($state) {
141*04fd306cSNickeau
142*04fd306cSNickeau            case DOKU_LEXER_ENTER :
143*04fd306cSNickeau
144*04fd306cSNickeau                if (substr($match, 1, strlen(FragmentTag::TEMPLATE_TAG)) === FragmentTag::TEMPLATE_TAG) {
145*04fd306cSNickeau                    LogUtility::warning("The template component has been deprecated and replaced by the fragment component. Why ? Because a whole page is now a template. ", syntax_plugin_combo_iterator::CANONICAL);
146*04fd306cSNickeau                }
147*04fd306cSNickeau                $tagAttributes = TagAttributes::createFromTagMatch($match);
148*04fd306cSNickeau                return array(
149*04fd306cSNickeau                    PluginUtility::STATE => $state,
150*04fd306cSNickeau                    PluginUtility::ATTRIBUTES => $tagAttributes->toCallStackArray()
151*04fd306cSNickeau                );
152*04fd306cSNickeau
153*04fd306cSNickeau            case DOKU_LEXER_UNMATCHED :
154*04fd306cSNickeau
155*04fd306cSNickeau                // We should not ever come here but a user does not not known that
156*04fd306cSNickeau                return PluginUtility::handleAndReturnUnmatchedData(FragmentTag::FRAGMENT_TAG, $match, $handler);
157*04fd306cSNickeau
158*04fd306cSNickeau
159*04fd306cSNickeau            case DOKU_LEXER_EXIT :
160*04fd306cSNickeau
161*04fd306cSNickeau                /**
162*04fd306cSNickeau                 * Gather template stack
163*04fd306cSNickeau                 */
164*04fd306cSNickeau                $callStack = CallStack::createFromHandler($handler);
165*04fd306cSNickeau                $templateEnterCall = $callStack->moveToPreviousCorrespondingOpeningCall();
166*04fd306cSNickeau                $templateStack = [];
167*04fd306cSNickeau                while ($actualCall = $callStack->next()) {
168*04fd306cSNickeau                    $templateStack[] = $actualCall->toCallArray();
169*04fd306cSNickeau                }
170*04fd306cSNickeau                $callStack->deleteAllCallsAfter($templateEnterCall);
171*04fd306cSNickeau
172*04fd306cSNickeau                /**
173*04fd306cSNickeau                 * Cache dependent on the requested page
174*04fd306cSNickeau                 */
175*04fd306cSNickeau                try {
176*04fd306cSNickeau                    ExecutionContext::getActualOrCreateFromEnv()
177*04fd306cSNickeau                        ->getExecutingMarkupHandler()
178*04fd306cSNickeau                        ->getOutputCacheDependencies()
179*04fd306cSNickeau                        ->addDependency(MarkupCacheDependencies::REQUESTED_PAGE_DEPENDENCY);
180*04fd306cSNickeau                } catch (ExceptionNotFound $e) {
181*04fd306cSNickeau                    // not a fetcher markup run
182*04fd306cSNickeau                }
183*04fd306cSNickeau
184*04fd306cSNickeau
185*04fd306cSNickeau                return array(
186*04fd306cSNickeau                    PluginUtility::STATE => $state,
187*04fd306cSNickeau                    FragmentTag::CALLSTACK => $templateStack
188*04fd306cSNickeau                );
189*04fd306cSNickeau
190*04fd306cSNickeau
191*04fd306cSNickeau        }
192*04fd306cSNickeau        return array();
193*04fd306cSNickeau
194*04fd306cSNickeau    }
195*04fd306cSNickeau
196*04fd306cSNickeau    /**
197*04fd306cSNickeau     * Render the output
198*04fd306cSNickeau     * @param string $format
199*04fd306cSNickeau     * @param Doku_Renderer $renderer
200*04fd306cSNickeau     * @param array $data - what the function handle() return'ed
201*04fd306cSNickeau     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
202*04fd306cSNickeau     * @throws ExceptionNotFound
203*04fd306cSNickeau     * @see DokuWiki_Syntax_Plugin::render()
204*04fd306cSNickeau     *
205*04fd306cSNickeau     *
206*04fd306cSNickeau     */
207*04fd306cSNickeau    function render($format, Doku_Renderer $renderer, $data): bool
208*04fd306cSNickeau    {
209*04fd306cSNickeau
210*04fd306cSNickeau        if ($format === "xhtml") {
211*04fd306cSNickeau            $state = $data[PluginUtility::STATE];
212*04fd306cSNickeau            switch ($state) {
213*04fd306cSNickeau                case DOKU_LEXER_UNMATCHED:
214*04fd306cSNickeau                    $renderer->doc .= PluginUtility::renderUnmatched($data);
215*04fd306cSNickeau                    return true;
216*04fd306cSNickeau                case DOKU_LEXER_EXIT:
217*04fd306cSNickeau                    $templateStack = $data[FragmentTag::CALLSTACK];
218*04fd306cSNickeau                    if ($templateStack === null) {
219*04fd306cSNickeau                        $renderer->doc .= LogUtility::wrapInRedForHtml("Template instructions should not be null");
220*04fd306cSNickeau                        return false;
221*04fd306cSNickeau                    }
222*04fd306cSNickeau                    $page = MarkupPath::createFromRequestedPage();
223*04fd306cSNickeau                    $metadata = $page->getMetadataForRendering();
224*04fd306cSNickeau                    try {
225*04fd306cSNickeau                        $renderer->doc .= MarkupRenderUtility::renderInstructionsToXhtml($templateStack, $metadata);
226*04fd306cSNickeau                    } catch (ExceptionCompile $e) {
227*04fd306cSNickeau                        $renderer->doc .= LogUtility::wrapInRedForHtml("Error while rendering the instruction. Error: {$e->getMessage()}");
228*04fd306cSNickeau                    }
229*04fd306cSNickeau                    LogUtility::warning("There is no need anymore to use a template to render variable", FragmentTag::CANONICAL);
230*04fd306cSNickeau                    return true;
231*04fd306cSNickeau            }
232*04fd306cSNickeau        }
233*04fd306cSNickeau        return false;
234*04fd306cSNickeau
235*04fd306cSNickeau    }
236*04fd306cSNickeau
237*04fd306cSNickeau
238*04fd306cSNickeau}
239*04fd306cSNickeau
240