Passed
Pull Request — master (#91)
by Jacques
11:17
created

RichEditorExtension::renderElement()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 11
c 0
b 0
f 0
dl 0
loc 18
rs 9.9
cc 3
nc 3
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
    /**
30
     * @var RegistryInterface
31
     */
32
    private $uiElementRegistry;
33
34
    /**
35
     * @var Environment
36
     */
37
    private $twig;
38
39
    /**
40
     * RichEditorExtension constructor.
41
     *
42
     * @param RegistryInterface $uiElementRegistry
43
     * @param Environment $twig
44
     */
45
    public function __construct(
46
        RegistryInterface $uiElementRegistry,
47
        Environment $twig
48
    ) {
49
        $this->uiElementRegistry = $uiElementRegistry;
50
        $this->twig = $twig;
51
    }
52
53
    /**
54
     * @return TwigFilter[]
55
     */
56
    public function getFilters()
57
    {
58
        return [
59
            new TwigFilter('monsieurbiz_richeditor_render_element', [$this, 'renderRichEditorField'], ['is_safe' => ['html']]),
60
        ];
61
    }
62
63
    /**
64
     * @return array|TwigFunction[]
65
     */
66
    public function getFunctions()
67
    {
68
        return [
69
            new TwigFunction('monsieurbiz_richeditor_list_elements', [$this, 'listUiElements'], ['is_safe' => ['html', 'js']]),
70
            new TwigFunction('monsieurbiz_richeditor_youtube_link', [$this, 'convertYoutubeEmbeddedLink'], ['is_safe' => ['html', 'js']]),
71
        ];
72
    }
73
74
    /**
75
     * @param string $content
76
     *
77
     * @throws LoaderError
78
     * @throws RuntimeError
79
     * @throws SyntaxError
80
     *
81
     * @return string
82
     */
83
    public function renderRichEditorField(string $content)
84
    {
85
        $elements = json_decode($content, true);
86
        if (!\is_array($elements)) {
87
            return $content;
88
        }
89
90
        return $this->renderElements($elements);
91
    }
92
93
    /**
94
     * @param array $elements
95
     *
96
     * @return string
97
     * @throws LoaderError
98
     * @throws RuntimeError
99
     * @throws SyntaxError
100
     */
101
    private function renderElements(array $elements): string
102
    {
103
        $html = '';
104
        foreach ($elements as $element) {
105
            try {
106
                $html .= $this->renderElement($element);
107
            } catch (UiElementNotFoundException $e) {
108
                continue;
109
            }
110
        }
111
        return $html;
112
    }
113
114
    /**
115
     * @param array $element
116
     *
117
     * @return string
118
     * @throws UiElementNotFoundException
119
     * @throws LoaderError  [twig.render] When the template cannot be found
120
     * @throws SyntaxError  [twig.render] When an error occurred during compilation
121
     * @throws RuntimeError [twig.render] When an error occurred during rendering
122
     */
123
    private function renderElement(array $element): string
124
    {
125
        if (!isset($element['code'])) {
126
            if (!isset($element['type'], $element['fields'])) {
127
                throw new UiElementNotFoundException('unknown');
128
            }
129
            $element = [
130
                'code' => $element['type'],
131
                'data' => $element['fields'],
132
            ];
133
        }
134
135
        $uiElement = $this->uiElementRegistry->getUiElement($element['code']);
136
        $template = $uiElement->getFrontRenderTemplate();
137
138
        return $this->twig->render($template, [
139
            'ui_element' => $uiElement,
140
            'element' => $element['data'],
141
        ]);
142
    }
143
144
    /**
145
     * List available Ui Elements in JSON.
146
     *
147
     * @return string
148
     */
149
    public function listUiElements(): string
150
    {
151
        return (string) json_encode($this->uiElementRegistry);
152
    }
153
154
    /**
155
     * Convert Youtube link to embed URL.
156
     *
157
     * @param string $url
158
     *
159
     * @return string|null
160
     */
161
    public function convertYoutubeEmbeddedLink(string $url): ?string
162
    {
163
        $isValid = (bool) preg_match(YoutubeUrlValidator::YOUTUBE_REGEX_VALIDATOR, $url, $matches);
164
165
        if (!$isValid || !isset($matches[1])) {
166
            return null;
167
        }
168
169
        return sprintf('https://www.youtube.com/embed/%s', $matches[1]);
170
    }
171
}
172