CKEditorRenderer::renderPlugin()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 2
dl 0
loc 7
ccs 0
cts 4
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the FOSCKEditor Bundle.
5
 *
6
 * (c) 2018 - present  Friends of Symfony
7
 * (c) 2009 - 2017     Eric GELOEN <[email protected]>
8
 *
9
 * For the full copyright and license information, please read the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace FOS\CKEditorBundle\Renderer;
14
15
use FOS\CKEditorBundle\Builder\JsonBuilder;
16
use Symfony\Component\Asset\Packages;
17
use Symfony\Component\HttpFoundation\RequestStack;
18
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
19
use Symfony\Component\Routing\RouterInterface;
20
use Twig\Environment;
21
22
/**
23
 * @author GeLo <[email protected]>
24
 */
25
final class CKEditorRenderer implements CKEditorRendererInterface
26
{
27
    /**
28
     * @var JsonBuilder
29
     */
30
    private $jsonBuilder;
31
32
    /**
33
     * @var RouterInterface
34
     */
35
    private $router;
36
37
    /**
38
     * @var Packages
39
     */
40
    private $assetsPackages;
41
42
    /**
43
     * @var Environment
44
     */
45
    private $twig;
46
47
    /**
48
     * @var RequestStack
49
     */
50
    private $requestStack;
51
52
    /**
53
     * @var null|string
54
     */
55
    private $locale;
56
57
    public function __construct(
58
        JsonBuilder $jsonBuilder,
59
        RouterInterface $router,
60
        Packages $packages,
61
        RequestStack $requestStack,
62
        Environment $twig,
63
        $locale = null
64
    ) {
65
        $this->jsonBuilder = $jsonBuilder;
66
        $this->router = $router;
67
        $this->assetsPackages = $packages;
68
        $this->twig = $twig;
69
        $this->requestStack = $requestStack;
70
        $this->locale = $locale;
71
    }
72
73
    public function renderBasePath(string $basePath): string
74
    {
75
        return $this->fixPath($basePath);
76
    }
77
78
    public function renderJsPath(string $jsPath): string
79
    {
80
        return $this->fixPath($jsPath);
81
    }
82
83
    public function renderWidget(string $id, array $config, array $options = []): string
84
    {
85
        $config = $this->fixConfigLanguage($config);
86
        $config = $this->fixConfigContentsCss($config);
87
        $config = $this->fixConfigFilebrowsers(
88
            $config,
89
            isset($options['filebrowsers']) ? $options['filebrowsers'] : []
90
        );
91
92
        $autoInline = isset($options['auto_inline']) && !$options['auto_inline']
93
            ? 'CKEDITOR.disableAutoInline = true;'."\n"
94
            : null;
95
96
        $builder = $this->jsonBuilder->reset()->setValues($config);
97
        $this->fixConfigEscapedValues($builder, $config);
98
99
        $widget = sprintf(
100
            'CKEDITOR.%s("%s", %s);',
101
            isset($options['inline']) && $options['inline'] ? 'inline' : 'replace',
102
            $id,
103
            $this->fixConfigConstants($builder->build())
104
        );
105
106
        if (isset($options['input_sync']) && $options['input_sync']) {
107
            $variable = 'fos_ckeditor_'.$id;
108
            $widget = 'var '.$variable.' = '.$widget."\n";
109
110
            return $autoInline.$widget.$variable.'.on(\'change\', function() { '.$variable.'.updateElement(); });';
111
        }
112
113
        return $autoInline.$widget;
114
    }
115
116
    public function renderDestroy(string $id): string
117
    {
118
        return sprintf(
119
            'if (CKEDITOR.instances["%1$s"]) { '.
120
            'CKEDITOR.instances["%1$s"].destroy(true); '.
121
            'delete CKEDITOR.instances["%1$s"]; '.
122
            '}',
123
            $id
124
        );
125
    }
126
127
    public function renderPlugin(string $name, array $plugin): string
128
    {
129
        return sprintf(
130
            'CKEDITOR.plugins.addExternal("%s", "%s", "%s");',
131
            $name,
132
            $this->fixPath($plugin['path']),
133
            $plugin['filename']
134
        );
135
    }
136
137
    public function renderStylesSet(string $name, array $stylesSet): string
138
    {
139
        return sprintf(
140
            'if (CKEDITOR.stylesSet.get("%1$s") === null) { '.
141
            'CKEDITOR.stylesSet.add("%1$s", %2$s); '.
142
            '}',
143
            $name,
144
            $this->jsonBuilder->reset()->setValues($stylesSet)->build()
145
        );
146
    }
147
148
    public function renderTemplate(string $name, array $template): string
149
    {
150
        if (isset($template['imagesPath'])) {
151
            $template['imagesPath'] = $this->fixPath($template['imagesPath']);
152
        }
153
154
        if (isset($template['templates'])) {
155
            foreach ($template['templates'] as &$rawTemplate) {
156
                if (isset($rawTemplate['template'])) {
157
                    $rawTemplate['html'] = $this->twig->render(
158
                        $rawTemplate['template'],
159
                        isset($rawTemplate['template_parameters']) ? $rawTemplate['template_parameters'] : []
160
                    );
161
                }
162
163
                unset($rawTemplate['template'], $rawTemplate['template_parameters']);
164
            }
165
        }
166
167
        return sprintf(
168
            'CKEDITOR.addTemplates("%s", %s);',
169
            $name,
170
            $this->jsonBuilder->reset()->setValues($template)->build()
171
        );
172
    }
173
174
    private function fixConfigLanguage(array $config): array
175
    {
176
        if (!isset($config['language']) && null !== ($language = $this->getLanguage())) {
177
            $config['language'] = $language;
178
        }
179
180
        if (isset($config['language'])) {
181
            $config['language'] = strtolower(str_replace('_', '-', $config['language']));
182
        }
183
184
        return $config;
185
    }
186
187
    private function fixConfigContentsCss(array $config): array
188
    {
189
        if (isset($config['contentsCss'])) {
190
            $cssContents = (array) $config['contentsCss'];
191
192
            $config['contentsCss'] = [];
193
            foreach ($cssContents as $cssContent) {
194
                $config['contentsCss'][] = $this->fixPath($cssContent);
195
            }
196
        }
197
198
        return $config;
199
    }
200
201
    private function fixConfigFilebrowsers(array $config, array $filebrowsers): array
202
    {
203
        $filebrowsers = array_unique(array_merge([
204
            'Browse',
205
            'FlashBrowse',
206
            'ImageBrowse',
207
            'ImageBrowseLink',
208
            'Upload',
209
            'FlashUpload',
210
            'ImageUpload',
211
        ], $filebrowsers));
212
213
        foreach ($filebrowsers as $filebrowser) {
214
            $fileBrowserKey = 'filebrowser'.$filebrowser;
215
            $handler = $fileBrowserKey.'Handler';
216
            $url = $fileBrowserKey.'Url';
217
            $route = $fileBrowserKey.'Route';
218
            $routeParameters = $fileBrowserKey.'RouteParameters';
219
            $routeType = $fileBrowserKey.'RouteType';
220
221
            if (isset($config[$handler])) {
222
                $config[$url] = $config[$handler]($this->router);
223
            } elseif (isset($config[$route])) {
224
                $config[$url] = $this->router->generate(
225
                    $config[$route],
226
                    isset($config[$routeParameters]) ? $config[$routeParameters] : [],
227
                    isset($config[$routeType]) ? $config[$routeType] : UrlGeneratorInterface::ABSOLUTE_PATH
228
                );
229
            }
230
231
            unset($config[$handler], $config[$route], $config[$routeParameters], $config[$routeType]);
232
        }
233
234
        return $config;
235
    }
236
237
    private function fixConfigEscapedValues(JsonBuilder $builder, array $config): void
238
    {
239
        if (isset($config['protectedSource'])) {
240
            foreach ($config['protectedSource'] as $key => $value) {
241
                $builder->setValue(sprintf('[protectedSource][%s]', $key), $value, false);
242
            }
243
        }
244
245
        $escapedValueKeys = [
246
            'stylesheetParser_skipSelectors',
247
            'stylesheetParser_validSelectors',
248
        ];
249
250
        foreach ($escapedValueKeys as $escapedValueKey) {
251
            if (isset($config[$escapedValueKey])) {
252
                $builder->setValue(sprintf('[%s]', $escapedValueKey), $config[$escapedValueKey], false);
253
            }
254
        }
255
    }
256
257
    private function fixConfigConstants(string $json): string
258
    {
259
        return preg_replace('/"(CKEDITOR\.[A-Z_]+)"/', '$1', $json);
260
    }
261
262
    private function fixPath(string $path): string
263
    {
264
        if (null === $this->assetsPackages) {
265
            return $path;
266
        }
267
268
        $url = $this->assetsPackages->getUrl($path);
269
270
        if ('/' === substr($path, -1) && false !== ($position = strpos($url, '?'))) {
271
            $url = substr($url, 0, (int) $position);
272
        }
273
274
        return $url;
275
    }
276
277
    private function getLanguage(): ?string
278
    {
279
        $request = $this->requestStack->getCurrentRequest();
280
281
        if (null !== $request) {
282
            return $request->getLocale();
283
        }
284
285
        return $this->locale;
286
    }
287
}
288