Completed
Push — master ( 387d55...d6cbad )
by Jacques
19s queued 11s
created

RichEditorExtension::renderRichEditorField()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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