xref: /plugin/combo/ComboStrap/MarkupRenderer.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1*04fd306cSNickeau<?php
2*04fd306cSNickeau
3*04fd306cSNickeaunamespace ComboStrap;
4*04fd306cSNickeau
5*04fd306cSNickeau
6*04fd306cSNickeauclass MarkupRenderer
7*04fd306cSNickeau{
8*04fd306cSNickeau
9*04fd306cSNickeau    /**
10*04fd306cSNickeau     * Setting the mime to instructions will just not do any render processing.
11*04fd306cSNickeau     * Just parse tree/instructions processing if needed
12*04fd306cSNickeau     */
13*04fd306cSNickeau    public const INSTRUCTION_EXTENSION = "i";
14*04fd306cSNickeau
15*04fd306cSNickeau    const CANONICAL = "markup:renderer";
16*04fd306cSNickeau    const XHTML_RENDERER = "xhtml";
17*04fd306cSNickeau    const DEFAULT_RENDERER = self::XHTML_RENDERER;
18*04fd306cSNickeau    const METADATA_EXTENSION = "meta";
19*04fd306cSNickeau    /**
20*04fd306cSNickeau     * @var string source of the renderer is a markup (and not instructions)
21*04fd306cSNickeau     */
22*04fd306cSNickeau    private string $markupSource;
23*04fd306cSNickeau    /**
24*04fd306cSNickeau     * @var array source of the rendere is instructions
25*04fd306cSNickeau     */
26*04fd306cSNickeau    private array $instructionsSource;
27*04fd306cSNickeau
28*04fd306cSNickeau    private Mime $requestedMime;
29*04fd306cSNickeau
30*04fd306cSNickeau    /**
31*04fd306cSNickeau     * @var mixed
32*04fd306cSNickeau     */
33*04fd306cSNickeau    private $cacheAfterRendering = true;
34*04fd306cSNickeau    private string $renderer;
35*04fd306cSNickeau
36*04fd306cSNickeau    /**
37*04fd306cSNickeau     * @var WikiPath the context path
38*04fd306cSNickeau     * May be null (ie markup rendering without any context such as webcode)
39*04fd306cSNickeau     */
40*04fd306cSNickeau    private WikiPath $requestedContextPath;
41*04fd306cSNickeau
42*04fd306cSNickeau    /**
43*04fd306cSNickeau     * @var ?Path the path from where the instructions/markup where created
44*04fd306cSNickeau     * This is mandatory to add cache dependency informations
45*04fd306cSNickeau     * and set the path that is executing
46*04fd306cSNickeau     */
47*04fd306cSNickeau    private ?Path $executingPath;
48*04fd306cSNickeau
49*04fd306cSNickeau
50*04fd306cSNickeau    /**
51*04fd306cSNickeau     * @param string $markup
52*04fd306cSNickeau     * @param Path|null $executingPath - the source of the markup - may be null (case of webcode)
53*04fd306cSNickeau     * @param WikiPath|null $contextPath - the requested markup path - may be null (case of webcode)
54*04fd306cSNickeau     * @return MarkupRenderer
55*04fd306cSNickeau     */
56*04fd306cSNickeau    public static function createFromMarkup(string $markup, ?Path $executingPath, ?WikiPath $contextPath): MarkupRenderer
57*04fd306cSNickeau    {
58*04fd306cSNickeau        $markupRenderer = (new MarkupRenderer())
59*04fd306cSNickeau            ->setMarkup($markup);
60*04fd306cSNickeau        if ($executingPath != null) {
61*04fd306cSNickeau            $markupRenderer->setRequestedExecutingPath($executingPath);
62*04fd306cSNickeau        }
63*04fd306cSNickeau        if ($contextPath != null) {
64*04fd306cSNickeau            $markupRenderer->setRequestedContextPath($contextPath);
65*04fd306cSNickeau        }
66*04fd306cSNickeau        return $markupRenderer;
67*04fd306cSNickeau
68*04fd306cSNickeau    }
69*04fd306cSNickeau
70*04fd306cSNickeau    private function setMarkup(string $markup): MarkupRenderer
71*04fd306cSNickeau    {
72*04fd306cSNickeau        $this->markupSource = $markup;
73*04fd306cSNickeau        return $this;
74*04fd306cSNickeau    }
75*04fd306cSNickeau
76*04fd306cSNickeau    public static function createFromMarkupInstructions($instructions, FetcherMarkup $fetcherMarkup): MarkupRenderer
77*04fd306cSNickeau    {
78*04fd306cSNickeau        return (new MarkupRenderer())
79*04fd306cSNickeau            ->setInstructions($instructions)
80*04fd306cSNickeau            ->setRequestedContextPath($fetcherMarkup->getRequestedContextPath())
81*04fd306cSNickeau            ->setRequestedExecutingPath($fetcherMarkup->getExecutingPathOrNull());
82*04fd306cSNickeau    }
83*04fd306cSNickeau
84*04fd306cSNickeau    public static function createFromInstructions($instructions): MarkupRenderer
85*04fd306cSNickeau    {
86*04fd306cSNickeau        return (new MarkupRenderer())->setInstructions($instructions);
87*04fd306cSNickeau    }
88*04fd306cSNickeau
89*04fd306cSNickeau
90*04fd306cSNickeau    public function setRequestedMimeToInstruction(): MarkupRenderer
91*04fd306cSNickeau    {
92*04fd306cSNickeau        try {
93*04fd306cSNickeau            $this->setRequestedMime(Mime::createFromExtension(self::INSTRUCTION_EXTENSION));
94*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
95*04fd306cSNickeau            throw new ExceptionRuntime("Internal error: the mime is internal and should be good");
96*04fd306cSNickeau        }
97*04fd306cSNickeau        return $this;
98*04fd306cSNickeau
99*04fd306cSNickeau    }
100*04fd306cSNickeau
101*04fd306cSNickeau    public function setRequestedMime(Mime $requestedMime): MarkupRenderer
102*04fd306cSNickeau    {
103*04fd306cSNickeau        $this->requestedMime = $requestedMime;
104*04fd306cSNickeau        return $this;
105*04fd306cSNickeau    }
106*04fd306cSNickeau
107*04fd306cSNickeau    public function getOutput()
108*04fd306cSNickeau    {
109*04fd306cSNickeau
110*04fd306cSNickeau        $extension = $this->requestedMime->getExtension();
111*04fd306cSNickeau        switch ($extension) {
112*04fd306cSNickeau            case self::INSTRUCTION_EXTENSION:
113*04fd306cSNickeau                /**
114*04fd306cSNickeau                 * Get the instructions adapted from {@link p_cached_instructions()}
115*04fd306cSNickeau                 *
116*04fd306cSNickeau                 * Note that this code may not run at first rendering
117*04fd306cSNickeau                 *
118*04fd306cSNickeau                 * Why ?
119*04fd306cSNickeau                 * Because dokuwiki asks first page information
120*04fd306cSNickeau                 * via the {@link pageinfo()} method.
121*04fd306cSNickeau                 * This function then render the metadata (ie {@link p_render_metadata()} and therefore will trigger
122*04fd306cSNickeau                 * the rendering with this function
123*04fd306cSNickeau                 * ```p_cached_instructions(wikiFN($id),false,$id)```
124*04fd306cSNickeau                 *
125*04fd306cSNickeau                 * The best way to manipulate the instructions is not before but after
126*04fd306cSNickeau                 * the parsing. See {@link \action_plugin_combo_instructionspostprocessing}
127*04fd306cSNickeau                 *
128*04fd306cSNickeau                 */
129*04fd306cSNickeau                return p_get_instructions($this->markupSource);
130*04fd306cSNickeau
131*04fd306cSNickeau            default:
132*04fd306cSNickeau                /**
133*04fd306cSNickeau                 * The code below is adapted from {@link p_cached_output()}
134*04fd306cSNickeau                 * $ret = p_cached_output($file, 'xhtml', $pageid);
135*04fd306cSNickeau                 */
136*04fd306cSNickeau                if (!isset($this->instructionsSource)) {
137*04fd306cSNickeau                    $executingPath = null;
138*04fd306cSNickeau                    if (isset($this->executingPath)) {
139*04fd306cSNickeau                        $executingPath = $this->executingPath;
140*04fd306cSNickeau                    }
141*04fd306cSNickeau
142*04fd306cSNickeau                    $contextPath = null;
143*04fd306cSNickeau                    if (isset($this->requestedContextPath)) {
144*04fd306cSNickeau                        $contextPath = $this->requestedContextPath;
145*04fd306cSNickeau                    }
146*04fd306cSNickeau
147*04fd306cSNickeau                    $this->instructionsSource = MarkupRenderer::createFromMarkup($this->markupSource, $executingPath, $contextPath)
148*04fd306cSNickeau                        ->setRequestedMimeToInstruction()
149*04fd306cSNickeau                        ->getOutput();
150*04fd306cSNickeau                }
151*04fd306cSNickeau
152*04fd306cSNickeau                /**
153*04fd306cSNickeau                 * Render
154*04fd306cSNickeau                 */
155*04fd306cSNickeau                $result = p_render($this->getRendererNameOrDefault(), $this->instructionsSource, $info);
156*04fd306cSNickeau                $this->cacheAfterRendering = $info['cache'] !== null ? $info['cache'] : false;
157*04fd306cSNickeau                return $result;
158*04fd306cSNickeau
159*04fd306cSNickeau        }
160*04fd306cSNickeau
161*04fd306cSNickeau
162*04fd306cSNickeau    }
163*04fd306cSNickeau
164*04fd306cSNickeau    private function setInstructions(array $instructions): MarkupRenderer
165*04fd306cSNickeau    {
166*04fd306cSNickeau        $this->instructionsSource = $instructions;
167*04fd306cSNickeau        return $this;
168*04fd306cSNickeau    }
169*04fd306cSNickeau
170*04fd306cSNickeau
171*04fd306cSNickeau    function getRendererNameOrDefault(): string
172*04fd306cSNickeau    {
173*04fd306cSNickeau        if (isset($this->renderer)) {
174*04fd306cSNickeau            return $this->renderer;
175*04fd306cSNickeau        }
176*04fd306cSNickeau        /**
177*04fd306cSNickeau         * Note: This value is passed to {@link p_get_renderer} to get the renderer class
178*04fd306cSNickeau         */
179*04fd306cSNickeau        return self::DEFAULT_RENDERER;
180*04fd306cSNickeau    }
181*04fd306cSNickeau
182*04fd306cSNickeau    public function setRendererName(string $rendererName): MarkupRenderer
183*04fd306cSNickeau    {
184*04fd306cSNickeau        $this->renderer = $rendererName;
185*04fd306cSNickeau        return $this;
186*04fd306cSNickeau    }
187*04fd306cSNickeau
188*04fd306cSNickeau    public function getCacheAfterRendering()
189*04fd306cSNickeau    {
190*04fd306cSNickeau        return $this->cacheAfterRendering;
191*04fd306cSNickeau    }
192*04fd306cSNickeau
193*04fd306cSNickeau    /**
194*04fd306cSNickeau     * The page context in which this markup was requested
195*04fd306cSNickeau     * @param WikiPath $path
196*04fd306cSNickeau     * @return $this
197*04fd306cSNickeau     */
198*04fd306cSNickeau    public function setRequestedContextPath(WikiPath $path): MarkupRenderer
199*04fd306cSNickeau    {
200*04fd306cSNickeau        $this->requestedContextPath = $path;
201*04fd306cSNickeau        return $this;
202*04fd306cSNickeau    }
203*04fd306cSNickeau
204*04fd306cSNickeau    public function setRequestedMimeToXhtml(): MarkupRenderer
205*04fd306cSNickeau    {
206*04fd306cSNickeau        try {
207*04fd306cSNickeau            return $this->setRequestedMime(Mime::createFromExtension("xhtml"));
208*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
209*04fd306cSNickeau            throw new ExceptionRuntime("Internal error", 0, $e);
210*04fd306cSNickeau        }
211*04fd306cSNickeau    }
212*04fd306cSNickeau
213*04fd306cSNickeau    /**
214*04fd306cSNickeau     * @throws ExceptionNotFound
215*04fd306cSNickeau     */
216*04fd306cSNickeau    private function getRequestedContextPath(): WikiPath
217*04fd306cSNickeau    {
218*04fd306cSNickeau
219*04fd306cSNickeau        if (!isset($this->requestedContextPath)) {
220*04fd306cSNickeau            throw new ExceptionNotFound("No requested context path");
221*04fd306cSNickeau        }
222*04fd306cSNickeau        return $this->requestedContextPath;
223*04fd306cSNickeau
224*04fd306cSNickeau    }
225*04fd306cSNickeau
226*04fd306cSNickeau    public function setRequestedExecutingPath(?Path $executingPath): MarkupRenderer
227*04fd306cSNickeau    {
228*04fd306cSNickeau        $this->executingPath = $executingPath;
229*04fd306cSNickeau        return $this;
230*04fd306cSNickeau    }
231*04fd306cSNickeau
232*04fd306cSNickeau
233*04fd306cSNickeau}
234