Passed
Pull Request — master (#120)
by
unknown
07:16
created

RichEditorExtension::renderField()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 8
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
/*
4
 * This file is part of Monsieur Biz' Rich Editor plugin for Sylius.
5
 *
6
 * (c) Monsieur Biz <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace MonsieurBiz\SyliusRichEditorPlugin\Twig;
15
16
use MonsieurBiz\SyliusRichEditorPlugin\Exception\UiElementNotFoundException;
17
use MonsieurBiz\SyliusRichEditorPlugin\UiElement\RegistryInterface;
18
use MonsieurBiz\SyliusRichEditorPlugin\Validator\Constraints\YoutubeUrlValidator;
19
use Twig\Environment;
20
use Twig\Error\LoaderError;
21
use Twig\Error\RuntimeError;
22
use Twig\Error\SyntaxError;
23
use Twig\Extension\AbstractExtension;
24
use Twig\TwigFilter;
25
use Twig\TwigFunction;
26
27
final class RichEditorExtension extends AbstractExtension
28
{
29
    private RegistryInterface $uiElementRegistry;
30
31
    private Environment $twig;
32
33
    private string $defaultElement;
34
35
    private string $defaultElementDataField;
36
37
    /**
38
     * RichEditorExtension constructor.
39
     *
40
     * @param RegistryInterface $uiElementRegistry
41
     * @param Environment $twig
42
     * @param string $monsieurbizRicheditorDefaultElement
43
     * @param string $monsieurbizRicheditorDefaultElementDataField
44
     */
45
    public function __construct(
46
        RegistryInterface $uiElementRegistry,
47
        Environment $twig,
48
        string $monsieurbizRicheditorDefaultElement,
49
        string $monsieurbizRicheditorDefaultElementDataField
50
    ) {
51
        $this->uiElementRegistry = $uiElementRegistry;
52
        $this->twig = $twig;
53
        $this->defaultElement = $monsieurbizRicheditorDefaultElement;
54
        $this->defaultElementDataField = $monsieurbizRicheditorDefaultElementDataField;
55
    }
56
57
    /**
58
     * @return TwigFilter[]
59
     */
60
    public function getFilters(): array
61
    {
62
        return [
63
            new TwigFilter('monsieurbiz_richeditor_render_field', [$this, 'renderField'], ['is_safe' => ['html']]),
64
            new TwigFilter('monsieurbiz_richeditor_render_elements', [$this, 'renderElements'], ['is_safe' => ['html']]),
65
            new TwigFilter('monsieurbiz_richeditor_render_element', [$this, 'renderElement'], ['is_safe' => ['html']]),
66
        ];
67
    }
68
69
    /**
70
     * @return array|TwigFunction[]
71
     */
72
    public function getFunctions(): array
73
    {
74
        return [
75
            new TwigFunction('monsieurbiz_richeditor_list_elements', [$this, 'listUiElements'], ['is_safe' => ['html', 'js']]),
76
            new TwigFunction('monsieurbiz_richeditor_youtube_link', [$this, 'convertYoutubeEmbeddedLink'], ['is_safe' => ['html', 'js']]),
77
            new TwigFunction('monsieurbiz_richeditor_get_elements', [$this, 'getElements'], ['is_safe' => ['html']]),
78
            new TwigFunction('monsieurbiz_richeditor_get_default_element', [$this, 'getDefaultElement'], ['is_safe' => ['html']]),
79
            new TwigFunction('monsieurbiz_richeditor_get_default_element_data_field', [$this, 'getDefaultElementDataField'], ['is_safe' => ['html']]),
80
        ];
81
    }
82
83
    /**
84
     * @param string $content
85
     *
86
     * @throws LoaderError
87
     * @throws RuntimeError
88
     * @throws SyntaxError
89
     *
90
     * @return string
91
     */
92
    public function renderField(string $content): string
93
    {
94
        $elements = json_decode($content, true);
95
        if (!\is_array($elements)) {
96
            return $content;
97
        }
98
99
        return $this->renderElements($elements);
100
    }
101
102
    /**
103
     * @param string $content
104
     *
105
     * @throws LoaderError
106
     * @throws RuntimeError
107
     * @throws SyntaxError
108
     *
109
     * @return array
110
     */
111
    public function getElements(string $content): array
112
    {
113
        $elements = json_decode($content, true);
114
        if (!\is_array($elements)) {
115
            // If the JSON decode failed, return a new UIElement with default configuration
116
            return [
117
                'type' => $this->getDefaultElement(),
118
                'data' => [$this->getDefaultElementDataField()  => $content],
119
            ];
120
        }
121
122
        return $elements;
123
    }
124
125
    /**
126
     * @param array $elements
127
     *
128
     * @throws LoaderError
129
     * @throws RuntimeError
130
     * @throws SyntaxError
131
     *
132
     * @return string
133
     */
134
    public function renderElements(array $elements): string
135
    {
136
        $html = '';
137
        foreach ($elements as $element) {
138
            try {
139
                $html .= $this->renderElement($element);
140
            } catch (UiElementNotFoundException $e) {
141
                continue;
142
            }
143
        }
144
145
        return $html;
146
    }
147
148
    /**
149
     * @param array $element
150
     *
151
     * @throws UiElementNotFoundException
152
     * @throws LoaderError [twig.render] When the template cannot be found
153
     * @throws SyntaxError [twig.render] When an error occurred during compilation
154
     * @throws RuntimeError [twig.render] When an error occurred during rendering
155
     *
156
     * @return string
157
     */
158
    public function renderElement(array $element): string
159
    {
160
        if (!isset($element['code'])) {
161
            if (!isset($element['type'], $element['fields'])) {
162
                throw new UiElementNotFoundException('unknown');
163
            }
164
            $element = [
165
                'code' => $element['type'],
166
                'data' => $element['fields'],
167
            ];
168
        }
169
170
        $uiElement = $this->uiElementRegistry->getUiElement($element['code']);
171
        $template = $uiElement->getFrontRenderTemplate();
172
173
        return $this->twig->render($template, [
174
            'ui_element' => $uiElement,
175
            'element' => $element['data'],
176
        ]);
177
    }
178
179
    /**
180
     * List available Ui Elements in JSON.
181
     *
182
     * @return string
183
     */
184
    public function listUiElements(): string
185
    {
186
        return (string) json_encode($this->uiElementRegistry);
187
    }
188
189
    /**
190
     * Convert Youtube link to embed URL.
191
     *
192
     * @param string $url
193
     *
194
     * @return string|null
195
     */
196
    public function convertYoutubeEmbeddedLink(string $url): ?string
197
    {
198
        $isValid = (bool) preg_match(YoutubeUrlValidator::YOUTUBE_REGEX_VALIDATOR, $url, $matches);
199
200
        if (!$isValid || !isset($matches[1])) {
201
            return null;
202
        }
203
204
        return sprintf('https://www.youtube.com/embed/%s', $matches[1]);
205
    }
206
207
    public function getDefaultElement(): string
208
    {
209
        return $this->defaultElement;
210
    }
211
212
    public function getDefaultElementDataField(): string
213
    {
214
        return $this->defaultElementDataField;
215
    }
216
}
217