1<?php
2
3namespace ComboStrap;
4
5
6use action_plugin_combo_css;
7use ComboStrap\Api\ApiRouter;
8use ComboStrap\Meta\Field\PageTemplateName;
9use ComboStrap\Web\Url;
10use ComboStrap\Web\UrlEndpoint;
11
12/**
13 *
14 * This code permits to render a markup from a string passed as argument
15 *
16 * Technically, it's the same than {@link FetcherMarkup}
17 * but:
18 *   * it outputs the HTML within a minimal HTML page (no layout as in {@link FetcherPage})
19 *   * it gets the input from the url query properties
20 *
21 * It's used primarily by {@link \syntax_plugin_combo_webcode}
22 * that's why it's called webcode.
23 *
24 */
25class FetcherMarkupWebcode extends IFetcherAbs implements IFetcherString
26{
27
28    const CANONICAL = "webcode";
29    const NAME = "markup";
30
31    public const MARKUP_PROPERTY = "markup";
32    const TITLE_PROPERTY = "title";
33
34    private string $requestedMarkup;
35    private string $requestedTitle = "ComboStrap WebCode - Markup Renderer";
36
37    public static function createFetcherMarkup(string $markup): FetcherMarkupWebcode
38    {
39        return (new FetcherMarkupWebcode())
40            ->setRequestedMarkup($markup);
41    }
42
43    /**
44     * @throws ExceptionBadState - the markup is mandatory
45     */
46    function getFetchUrl(Url $url = null): Url
47    {
48        $url = UrlEndpoint::createAjaxUrl()
49            ->addQueryParameter(ApiRouter::AJAX_CALL_ATTRIBUTE, ApiRouter::AJAX_CALL_VALUE)
50            ->addQueryParameter(self::MARKUP_PROPERTY, $this->getRequestedMarkup())
51            ->addQueryParameter(self::TITLE_PROPERTY, $this->getRequestedTitle());
52        return parent::getFetchUrl($url);
53    }
54
55
56    function getBuster(): string
57    {
58        try {
59            return FileSystems::getCacheBuster(ClassUtility::getClassPath(FetcherMarkupWebcode::class));
60        } catch (ExceptionNotFound|\ReflectionException $e) {
61            LogUtility::internalError("The cache buster should be good. Error:{$e->getMessage()}", self::NAME);
62            return "";
63        }
64    }
65
66    public function buildFromTagAttributes(TagAttributes $tagAttributes): IFetcher
67    {
68
69        $markupProperty = self::MARKUP_PROPERTY;
70        $markup = $tagAttributes->getValueAndRemove($markupProperty);
71        if ($markup === null) {
72            throw new ExceptionBadArgument("The markup property ($markupProperty) is mandatory");
73        }
74        $this->setRequestedMarkup($markup);
75        $title = $tagAttributes->getValueAndRemove(self::TITLE_PROPERTY);
76        if ($title !== null) {
77            $this->setRequestedTitle($title);
78        }
79        return parent::buildFromTagAttributes($tagAttributes);
80    }
81
82
83    public function getMime(): Mime
84    {
85        return Mime::getHtml();
86    }
87
88    public function getFetcherName(): string
89    {
90        return self::NAME;
91    }
92
93    /**
94     * @return string
95     * @throws ExceptionBadState - if the markup was not defined
96     * @throws ExceptionCompile - if any error
97     */
98    public function getFetchString(): string
99    {
100
101        /**
102         * Conf
103         */
104        ExecutionContext::getActualOrCreateFromEnv()
105            ->getConfig()
106            ->setConf(action_plugin_combo_css::CONF_DISABLE_DOKUWIKI_STYLESHEET, true);
107
108        $fetcherCache = FetcherCache::createFrom($this);
109        if ($fetcherCache->isCacheUsable()) {
110            try {
111                return FileSystems::getContent($fetcherCache->getFile());
112            } catch (ExceptionNotFound $e) {
113                $message = "The cache file should exists";
114                if (PluginUtility::isDevOrTest()) {
115                    throw new ExceptionRuntimeInternal($message);
116                }
117                LogUtility::internalError($message);
118            }
119        }
120
121        $requestedMarkup = $this->getRequestedMarkup();
122
123        try {
124            $mainContent = FetcherMarkup::confRoot()
125                ->setRequestedMarkupString($requestedMarkup)
126                ->setDeleteRootBlockElement(true)
127                ->setRequestedMimeToXhtml()
128                ->setRequestedContextPathWithDefault()
129                ->setIsStandAloneCodeExecution(true)
130                ->build()
131                ->getFetchString();
132        } catch (ExceptionNotExists|ExceptionCompile $e) {
133            throw new ExceptionRuntimeInternal("An error has occurred while transforming the markup fragment to HTML. Error: {$e->getMessage()}", self::CANONICAL, 1, $e);
134        }
135
136        $title = $this->getRequestedTitle();
137
138        $html = TemplateForWebPage::create()
139            ->setRequestedTitle($title)
140            ->setRequestedTemplateName(PageTemplateName::BLANK_TEMPLATE_VALUE)
141            ->setRequestedEnableTaskRunner(false)
142            ->setIsIframe(true)
143            ->setMainContent($mainContent)
144            ->render();
145
146        $fetcherCache->storeCache($html);
147        return $html;
148
149    }
150
151    public function setRequestedMarkup(string $markup): FetcherMarkupWebcode
152    {
153        $this->requestedMarkup = $markup;
154        return $this;
155
156    }
157
158    public function setRequestedTitle(string $title): FetcherMarkupWebcode
159    {
160        $this->requestedTitle = $title;
161        return $this;
162    }
163
164    /**
165     * @throws ExceptionBadState
166     */
167    private function getRequestedMarkup(): string
168    {
169        if (!isset($this->requestedMarkup)) {
170            throw new ExceptionBadState("The markup was not defined.", self::CANONICAL);
171        }
172        return $this->requestedMarkup;
173    }
174
175    private function getRequestedTitle(): string
176    {
177        return $this->requestedTitle;
178    }
179
180
181    public function getLabel(): string
182    {
183        return self::CANONICAL;
184    }
185
186}
187