Completed
Pull Request — master (#340)
by Maximilian
70:44
created

CKEditorRenderer::getAssets()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
/*
4
 * This file is part of the Ivory CKEditor package.
5
 *
6
 * (c) Eric GELOEN <[email protected]>
7
 *
8
 * For the full copyright and license information, please read the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Ivory\CKEditorBundle\Renderer;
13
14
use Ivory\JsonBuilder\JsonBuilder;
15
use Symfony\Component\Asset\Packages;
16
use Symfony\Component\DependencyInjection\ContainerInterface;
17
use Symfony\Component\HttpFoundation\RequestStack;
18
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
19
use Symfony\Component\Routing\RouterInterface;
20
use Symfony\Component\Templating\EngineInterface;
21
22
/**
23
 * @author GeLo <[email protected]>
24
 */
25
class CKEditorRenderer implements CKEditorRendererInterface
26
{
27
    /**
28
     * @var JsonBuilder
29
     */
30
    private $jsonBuilder;
31
32
    /**
33
     * @var RouterInterface
34
     */
35 790
    private $router;
36
37 790
    /**
38 790
     * @var Packages
39
     */
40
    private $assetsPackages;
41
42
    /**
43 100
     * @var EngineInterface
44
     */
45 100
    private $templating;
46
47
    /**
48
     * @var RequestStack
49
     */
50
    private $requestStack;
51 90
52
    /**
53 90
     * @var null|string
54
     */
55
    private $locale;
56
57
    /**
58
     * @param JsonBuilder|ContainerInterface $containerOrJsonBuilder
59 610
     * @param RouterInterface $router
60
     * @param Packages $packages
61 610
     * @param RequestStack $requestStack
62 610
     * @param EngineInterface $templating
63 610
     * @param null|string $locale
64 610
     */
65 610
    public function __construct($containerOrJsonBuilder, RouterInterface $router = null, Packages $packages = null, RequestStack $requestStack = null, EngineInterface
66 488
    $templating = null, $locale = null)
67
    {
68 610
        if ($containerOrJsonBuilder instanceof ContainerInterface) {
69 494
            @trigger_error(sprintf('Passing a %s as %s first argument is deprecated since IvoryCKEditor 6.1, and will be removed in 7.0. Use %s instead.', ContainerInterface::class, __METHOD__, JsonBuilder::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
70 610
            $jsonBuilder = $containerOrJsonBuilder->get('ivory_ck_editor.renderer.json_builder');
71
            $router = $containerOrJsonBuilder->get('router');
72 610
            $packages = $containerOrJsonBuilder->get('assets.packages');
73 610
            $requestStack = $containerOrJsonBuilder->get('request_stack');
74
            $templating = $containerOrJsonBuilder->get('templating');
75 610
        } elseif ($containerOrJsonBuilder instanceof JsonBuilder) {
76 610
            $jsonBuilder = $containerOrJsonBuilder;
77 610
            if ($router === null) {
78 610
                throw new \InvalidArgumentException(sprintf('%s 2nd argument must not be null when using %s as first argument', __METHOD__, JsonBuilder::class));
79 610
            } elseif ($packages === null) {
80 488
                throw new \InvalidArgumentException(sprintf('%s 3rd argument must not be null when using %s as first argument', __METHOD__, JsonBuilder::class));
81
            } elseif ($requestStack === null) {
82 610
                throw new \InvalidArgumentException(sprintf('%s 4th argument must not be null when using %s as first argument', __METHOD__, JsonBuilder::class));
83 30
            } elseif ($templating === null) {
84 30
                throw new \InvalidArgumentException(sprintf('%s 5th argument must not be null when using %s as first argument', __METHOD__, JsonBuilder::class));
85
            }
86 30
        } else {
87
            throw new \InvalidArgumentException(sprintf('%s first argument must be an instance of %s or %s (%s given).', __METHOD__, ContainerInterface::class, JsonBuilder::class, is_object($containerOrJsonBuilder) ? get_class($containerOrJsonBuilder) : gettype($containerOrJsonBuilder)));
88
        }
89 580
90
        $this->jsonBuilder = $jsonBuilder;
91
        $this->router = $router;
92
        $this->assetsPackages = $packages;
93
        $this->templating = $templating;
94
        $this->requestStack = $requestStack;
95 110
        $this->locale = $locale;
96
    }
97 110
98
    /**
99 88
     * {@inheritdoc}
100 88
     */
101 110
    public function renderBasePath($basePath)
102 22
    {
103 88
        return $this->fixPath($basePath);
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109 40
    public function renderJsPath($jsPath)
110
    {
111 40
        return $this->fixPath($jsPath);
112 40
    }
113 40
114 40
    /**
115 40
     * {@inheritdoc}
116 32
     */
117
    public function renderWidget($id, array $config, array $options = [])
118
    {
119
        $config = $this->fixConfigLanguage($config);
120
        $config = $this->fixConfigContentsCss($config);
121
        $config = $this->fixConfigFilebrowsers(
122 30
            $config,
123
            isset($options['filebrowsers']) ? $options['filebrowsers'] : []
124 30
        );
125
126 24
        $autoInline = isset($options['auto_inline']) && !$options['auto_inline']
127 30
            ? 'CKEDITOR.disableAutoInline = true;'."\n"
128 30
            : null;
129 30
130 24
        $builder = $this->jsonBuilder->reset()->setValues($config);
131
        $this->fixConfigEscapedValues($builder, $config);
132
133
        $widget = sprintf(
134
            'CKEDITOR.%s("%s", %s);',
135
            isset($options['inline']) && $options['inline'] ? 'inline' : 'replace',
136 80
            $id,
137
            $this->fixConfigConstants($builder->build())
138 80
        );
139 80
140 64
        if (isset($options['input_sync']) && $options['input_sync']) {
141
            $variable = 'ivory_ckeditor_'.$id;
142 80
            $widget = 'var '.$variable.' = '.$widget."\n";
143 80
144 80
            return $autoInline.$widget.$variable.'.on(\'change\', function() { '.$variable.'.updateElement(); });';
145 40
        }
146 40
147 40
        return $autoInline.$widget;
148 32
    }
149 32
150
    /**
151 80
     * {@inheritdoc}
152 80
     */
153 64
    public function renderDestroy($id)
154 64
    {
155
        return sprintf(
156 80
            'if (CKEDITOR.instances["%1$s"]) { '.
157 80
            'CKEDITOR.instances["%1$s"].destroy(true); '.
158 80
            'delete CKEDITOR.instances["%1$s"]; '.
159 80
            '}',
160 64
            $id
161
        );
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167
    public function renderPlugin($name, array $plugin)
168 610
    {
169
        return sprintf(
170 610
            'CKEDITOR.plugins.addExternal("%s", "%s", "%s");',
171 40
            $name,
172 32
            $this->fixPath($plugin['path']),
173
            $plugin['filename']
174 610
        );
175 60
    }
176 48
177
    /**
178 610
     * {@inheritdoc}
179
     */
180
    public function renderStylesSet($name, array $stylesSet)
181
    {
182
        return sprintf(
183
            'if (CKEDITOR.stylesSet.get("%1$s") === null) { '.
184
            'CKEDITOR.stylesSet.add("%1$s", %2$s); '.
185
            '}',
186 610
            $name,
187
            $this->jsonBuilder->reset()->setValues($stylesSet)->build()
188 610
        );
189 80
    }
190
191 80
    /**
192 80
     * {@inheritdoc}
193 80
     */
194 64
    public function renderTemplate($name, array $template)
195 64
    {
196
        if (isset($template['imagesPath'])) {
197 610
            $template['imagesPath'] = $this->fixPath($template['imagesPath']);
198
        }
199
200
        if (isset($template['templates'])) {
201
            foreach ($template['templates'] as &$rawTemplate) {
0 ignored issues
show
Bug introduced by
The expression $template['templates'] of type string is not traversable.
Loading history...
202
                if (isset($rawTemplate['template'])) {
203
                    $rawTemplate['html'] = $this->templating->render(
204
                        $rawTemplate['template'],
205
                        isset($rawTemplate['template_parameters']) ? $rawTemplate['template_parameters'] : []
206 610
                    );
207
                }
208 610
209 610
                unset($rawTemplate['template']);
210 488
                unset($rawTemplate['template_parameters']);
211 488
            }
212 488
        }
213 488
214 488
        return sprintf(
215 488
            'CKEDITOR.addTemplates("%s", %s);',
216 610
            $name,
217
            $this->jsonBuilder->reset()->setValues($template)->build()
218 610
        );
219 610
    }
220 610
221 610
    /**
222 610
     * @param array $config
223 610
     *
224 610
     * @return array
225
     */
226 610
    private function fixConfigLanguage(array $config)
227 70
    {
228 610
        if (!isset($config['language']) && ($language = $this->getLanguage()) !== null) {
229 140
            $config['language'] = $language;
230 140
        }
231 140
232 140
        if (isset($config['language'])) {
233 112
            $config['language'] = strtolower(str_replace('_', '-', $config['language']));
234 112
        }
235
236 610
        return $config;
237 610
    }
238 610
239 610
    /**
240 488
     * @param array $config
241
     *
242 610
     * @return array
243
     */
244
    private function fixConfigContentsCss(array $config)
245
    {
246
        if (isset($config['contentsCss'])) {
247
            $cssContents = (array) $config['contentsCss'];
248
249 610
            $config['contentsCss'] = [];
250
            foreach ($cssContents as $cssContent) {
251 610
                $config['contentsCss'][] = $this->fixPath($cssContent);
252 10
            }
253 10
        }
254 8
255 8
        return $config;
256
    }
257
258 610
    /**
259 488
     * @param array $config
260 488
     * @param array $filebrowsers
261
     *
262 610
     * @return array
263 610
     */
264 138
    private function fixConfigFilebrowsers(array $config, array $filebrowsers)
265 16
    {
266 488
        $filebrowsers = array_unique(array_merge([
267 610
            'Browse',
268
            'FlashBrowse',
269
            'ImageBrowse',
270
            'ImageBrowseLink',
271
            'Upload',
272
            'FlashUpload',
273
            'ImageUpload',
274 610
        ], $filebrowsers));
275
276 610
        foreach ($filebrowsers as $filebrowser) {
277
            $fileBrowserKey = 'filebrowser'.$filebrowser;
278
            $handler = $fileBrowserKey.'Handler';
279
            $url = $fileBrowserKey.'Url';
280
            $route = $fileBrowserKey.'Route';
281
            $routeParameters = $fileBrowserKey.'RouteParameters';
282
            $routeType = $fileBrowserKey.'RouteType';
283
284 270
            if (isset($config[$handler])) {
285
                $config[$url] = $config[$handler]($this->router);
286 270
            } elseif (isset($config[$route])) {
287
                $config[$url] = $this->router->generate(
288 270
                    $config[$route],
289 80
                    isset($config[$routeParameters]) ? $config[$routeParameters] : [],
290
                    isset($config[$routeType]) ? $config[$routeType] : UrlGeneratorInterface::ABSOLUTE_PATH
291
                );
292 190
            }
293
294 190
            unset($config[$handler]);
295 50
            unset($config[$route]);
296 40
            unset($config[$routeParameters]);
297
            unset($config[$routeType]);
298 190
        }
299
300
        return $config;
301
    }
302
303
    /**
304 680
     * @param JsonBuilder $builder
305
     * @param array       $config
306 680
     */
307
    private function fixConfigEscapedValues(JsonBuilder $builder, array $config)
308
    {
309
        if (isset($config['protectedSource'])) {
310
            foreach ($config['protectedSource'] as $key => $value) {
311
                $builder->setValue(sprintf('[protectedSource][%s]', $key), $value, false);
312 590
            }
313
        }
314 590
315 20
        $escapedValueKeys = [
316
            'stylesheetParser_skipSelectors',
317
            'stylesheetParser_validSelectors',
318 570
        ];
319 20
320
        foreach ($escapedValueKeys as $escapedValueKey) {
321 550
            if (isset($config[$escapedValueKey])) {
322
                $builder->setValue(sprintf('[%s]', $escapedValueKey), $config[$escapedValueKey], false);
323
            }
324
        }
325
    }
326 590
327
    /**
328 590
     * @param string $json
329
     *
330
     * @return string
331
     */
332
    private function fixConfigConstants($json)
333
    {
334 40
        return preg_replace('/"(CKEDITOR\.[A-Z_]+)"/', '$1', $json);
335
    }
336 40
337 36
    /**
338 40
     * @param string $path
339
     *
340
     * @return string
341
     */
342
    private function fixPath($path)
343
    {
344 270
        if ($this->assetsPackages === null) {
345
            return $path;
346 270
        }
347
348
        $url = $this->assetsPackages->getUrl($path);
349
350
        if (substr($path, -1) === '/' && ($position = strpos($url, '?')) !== false) {
351
            $url = substr($url, 0, $position);
352 210
        }
353
354 210
        return $url;
355
    }
356
357
    /**
358
     * @return null|string
359
     */
360
    private function getLanguage()
361
    {
362
        $request = $this->requestStack->getCurrentRequest();
363
        if ($request !== null) {
364
            return $request->getLocale();
365
        }
366
367
        return $this->locale;
368
    }
369
}
370