1<?php
2
3namespace ComboStrap;
4
5use Doku_Renderer;
6use PHPUnit\Exception;
7
8/**
9 *
10 * Adaptation of the function {@link p_render()}
11 * for dynamic rendering because the {@link \Doku_Renderer_xhtml Renderer} has also state
12 * such as the `counter_row` for the function {@link \Doku_Renderer_xhtml::table_open()}
13 *
14 * If {@link p_render()} is used multiple time, the renderer is recreated and the counter is reset to zero and the
15 * row of each table is lost.
16 *
17 */
18class MarkupDynamicRender
19{
20    /**
21     * @var MarkupDynamicRender[]
22     */
23    static array $DYNAMIC_RENDERERS_CACHE = array();
24
25
26    /**
27     * @var string the format (xhtml, ...)
28     */
29    private string $format;
30
31
32    /**
33     * @var Doku_Renderer the renderer that calls the render function
34     */
35    private Doku_Renderer $renderer;
36
37    /**
38     * @throws ExceptionNotFound
39     */
40    public function __construct($format)
41    {
42        $this->format = $format;
43        $renderer = p_get_renderer($format);
44        if (is_null($renderer)) {
45            throw new ExceptionNotFound("No renderer was found for the format $format");
46        }
47
48        $this->renderer = $renderer;
49        $this->renderer->reset();
50        $this->renderer->smileys = getSmileys();
51        $this->renderer->entities = getEntities();
52        $this->renderer->acronyms = getAcronyms();
53        $this->renderer->interwiki = getInterwiki();
54    }
55
56    /**
57     * @throws ExceptionNotFound
58     */
59    public static function create($format): MarkupDynamicRender
60    {
61        /**
62         * Don't create a static object
63         * to preserve the build because
64         * the instructions may also recursively render.
65         *
66         * Therefore, a small instructions rendering such as a tooltip
67         * would take the actual rendering and close the previous.
68         */
69        return new MarkupDynamicRender($format);
70    }
71
72    public static function createXhtml(): MarkupDynamicRender
73    {
74        try {
75            return self::create("xhtml");
76        } catch (ExceptionNotFound $e) {
77            throw new ExceptionRuntimeInternal("xhtml should be available");
78        }
79    }
80
81    public function setDateAt($date_at)
82    {
83        if ($this->renderer instanceof \Doku_Renderer_xhtml) {
84            $this->renderer->date_at = $date_at;
85        }
86
87    }
88
89    /**
90     * @throws ExceptionCompile
91     * @throws ExceptionBadState
92     */
93    public function processInstructions($callStackHeaderInstructions): string
94    {
95
96        try {
97
98            // Loop through the instructions
99            foreach ($callStackHeaderInstructions as $instruction) {
100                // Execute the callback against the Renderer
101                if (method_exists($this->renderer, $instruction[0])) {
102                    call_user_func_array(array(&$this->renderer, $instruction[0]), $instruction[1] ?: array());
103                }
104            }
105
106            // Post process
107            // $data = array($this->format, & $this->renderer->doc);
108            // \dokuwiki\Extension\Event::createAndTrigger('RENDERER_CONTENT_POSTPROCESS', $data);
109            $string = $this->renderer->doc;
110            $this->renderer->doc = '';
111            return $string;
112
113        } /** @noinspection PhpRedundantCatchClauseInspection */ catch (Exception $e) {
114            /**
115             * Example of errors;
116             * method_exists() expects parameter 2 to be string, array given
117             * inc\parserutils.php:672
118             */
119            throw new ExceptionCompile("Error while rendering instructions. Error was: {$e->getMessage()}", "dynamic renderer", 1, $e);
120        }
121    }
122
123    public function __toString()
124    {
125        return "Dynamic $this->format renderer";
126    }
127
128
129}
130