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