Completed
Push — master ( 84990f...39c45f )
by Iurii
01:53
created

Editor::validateTwigEditor()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 8.9197
c 0
b 0
f 0
cc 4
eloc 13
nc 3
nop 1
1
<?php
2
3
/**
4
 * @package Theme editor
5
 * @author Iurii Makukh <[email protected]>
6
 * @copyright Copyright (c) 2015, Iurii Makukh
7
 * @license https://www.gnu.org/licenses/gpl.html GNU/GPLv3
8
 */
9
10
namespace gplcart\modules\editor\controllers;
11
12
use gplcart\core\models\Module as ModuleModel,
13
    gplcart\modules\editor\models\Editor as EditorModuleModel;
14
use gplcart\core\controllers\backend\Controller as BackendController;
15
16
/**
17
 * Handles incoming requests and outputs data related to Theme editor module
18
 */
19
class Editor extends BackendController
20
{
21
22
    /**
23
     * Editor model instance
24
     * @var \gplcart\modules\editor\models\Editor $editor
25
     */
26
    protected $editor;
27
28
    /**
29
     * Module model instance
30
     * @var \gplcart\core\models\Module $module
31
     */
32
    protected $module;
33
34
    /**
35
     * The current module
36
     * @var array
37
     */
38
    protected $data_module = array();
39
40
    /**
41
     * The current module file
42
     * @var string
43
     */
44
    protected $data_file;
45
46
    /**
47
     * @param EditorModuleModel $editor
48
     * @param ModuleModel $module
49
     */
50
    public function __construct(EditorModuleModel $editor, ModuleModel $module)
51
    {
52
        parent::__construct();
53
54
        $this->editor = $editor;
55
        $this->module = $module;
56
    }
57
58
    /**
59
     * Route callback to display the select theme page
60
     */
61
    public function themeEditor()
62
    {
63
        $this->setTitleThemeEditor();
64
        $this->setBreadcrumbThemeEditor();
65
66
        $this->setData('themes', $this->module->getByType('theme'));
67
68
        $this->outputThemeEditor();
69
    }
70
71
    /**
72
     * Set title on the select theme page
73
     */
74
    protected function setTitleThemeEditor()
75
    {
76
        $this->setTitle($this->text('Themes'));
77
    }
78
79
    /**
80
     * Set breadcrumbs on the select theme page
81
     */
82
    protected function setBreadcrumbThemeEditor()
83
    {
84
        $breadcrumbs = array();
85
86
        $breadcrumbs[] = array(
87
            'url' => $this->url('admin'),
88
            'text' => $this->text('Dashboard')
89
        );
90
91
        $breadcrumbs[] = array(
92
            'url' => $this->url('admin/module/list'),
93
            'text' => $this->text('Modules')
94
        );
95
96
        $this->setBreadcrumbs($breadcrumbs);
97
    }
98
99
    /**
100
     * Output rendered templates on the select theme page
101
     */
102
    protected function outputThemeEditor()
103
    {
104
        $this->output('editor|themes');
105
    }
106
107
    /**
108
     * Displays the module file overview page
109
     * @param integer $module_id
110
     */
111
    public function listEditor($module_id)
112
    {
113
        $this->setModuleEditor($module_id);
114
115
        $this->setTitleListEditor();
116
        $this->setBreadcrumbListEditor();
117
118
        $this->setData('module', $this->data_module);
119
        $this->setData('files', $this->getFilesEditor());
120
121
        $this->outputListEditor();
122
    }
123
124
    /**
125
     * Returns an array of module data
126
     * @param string $module_id
127
     * @return array
128
     */
129
    protected function setModuleEditor($module_id)
130
    {
131
        $module = $this->module->get($module_id);
132
133
        if (empty($module)) {
134
            $this->outputHttpStatus(404);
135
        }
136
137
        if ($module['type'] !== 'theme') {
138
            $this->outputHttpStatus(403);
139
        }
140
141
        return $this->data_module = $module;
142
    }
143
144
    /**
145
     * Returns an array of files to edit
146
     * @return array
147
     */
148
    protected function getFilesEditor()
149
    {
150
        $data = $this->editor->getList($this->data_module);
151
        return $this->prepareFilesEditor($data);
152
    }
153
154
    /**
155
     * Prepares an array of files to be edited
156
     * @param array $data
157
     * @return array
158
     */
159
    protected function prepareFilesEditor(array $data)
160
    {
161
        $prepared = array();
162
        foreach ($data as $folder => $files) {
163
            foreach ($files as $file) {
164
165
                $path = trim(str_replace($this->data_module['directory'], '', $file), '/');
166
                $depth = substr_count($path, '/');
167
168
                $pathinfo = pathinfo($path);
169
170
                $directory = is_dir($file);
171
                $parent = $directory ? $path : $pathinfo['dirname'];
172
173
                $prepared[$folder][$parent][] = array(
174
                    'file' => $file,
175
                    'path' => $path,
176
                    'depth' => $depth,
177
                    'directory' => $directory,
178
                    'name' => $pathinfo['basename'],
179
                    'id' => gplcart_string_encode($path),
180
                    'indentation' => str_repeat('<span class="indentation"></span>', $depth)
181
                );
182
            }
183
184
            ksort($prepared[$folder]);
185
        }
186
        return $prepared;
187
    }
188
189
    /**
190
     * Sets title on theme files overview page
191
     */
192
    protected function setTitleListEditor()
193
    {
194
        $text = $this->text('Edit theme %name', array('%name' => $this->data_module['name']));
195
        $this->setTitle($text);
196
    }
197
198
    /**
199
     * Sets breadcrumbs on theme files overview page
200
     */
201
    protected function setBreadcrumbListEditor()
202
    {
203
        $breadcrumbs = array();
204
205
        $breadcrumbs[] = array(
206
            'url' => $this->url('admin'),
207
            'text' => $this->text('Dashboard')
208
        );
209
210
        $breadcrumbs[] = array(
211
            'url' => $this->url('admin/module/list'),
212
            'text' => $this->text('Modules')
213
        );
214
215
        $breadcrumbs[] = array(
216
            'url' => $this->url('admin/tool/editor'),
217
            'text' => $this->text('Themes')
218
        );
219
220
        $this->setBreadcrumbs($breadcrumbs);
221
    }
222
223
    /**
224
     * Renders templates of theme files overview page
225
     */
226
    protected function outputListEditor()
227
    {
228
        $this->output('editor|list');
229
    }
230
231
    /**
232
     * Displays the file edit page
233
     * @param string $module_id
234
     * @param string $file_id
235
     */
236
    public function editEditor($module_id, $file_id)
237
    {
238
        $this->setModuleEditor($module_id);
239
        $this->setFilePathEditor($file_id);
240
241
        $this->setTitleEditEditor();
242
        $this->setBreadcrumbEditEditor();
243
244
        $this->setMessageEditEditor();
245
246
        $this->setData('module', $this->data_module);
247
        $this->setData('can_save', $this->canSaveEditor());
248
        $this->setData('lines', $this->getFileTotalLinesEditor());
249
        $this->setData('editor.content', $this->getFileContentEditor());
250
251
        $this->submitEditor();
252
253
        $this->setJsSettingsEditor();
254
        $this->outputEditEditor();
255
    }
256
257
    /**
258
     * Sets messages on the file edit page
259
     */
260
    protected function setMessageEditEditor()
261
    {
262
        if ($this->canSaveEditor()) {
263
            $message = $this->text('Before saving changes make sure you have a <a href="@url">backup</a> of the current version', array('@url' => $this->url('admin/tool/backup')));
264
            $this->setMessage($message, 'warning');
265
        }
266
267
        if ($this->current_theme['id'] == $this->data_module['id']) {
268
            $message = $this->text('You cannot edit the current theme');
269
            $this->setMessage($message, 'warning');
270
        }
271
    }
272
273
    /**
274
     * Sets JavaScript settings on the file edit page
275
     */
276
    protected function setJsSettingsEditor()
277
    {
278
        $settings = array(
279
            'readonly' => !$this->canSaveEditor(),
280
            'file_extension' => pathinfo($this->data_file, PATHINFO_EXTENSION)
281
        );
282
283
        $this->setJsSettings('editor', $settings);
284
    }
285
286
    /**
287
     * Saves an array of submitted data
288
     */
289
    protected function submitEditor()
290
    {
291
        if ($this->isPosted('save') && $this->validateEditor()) {
292
            $this->saveEditor();
293
        }
294
    }
295
296
    /**
297
     * Validates a submitted data when editing a theme file
298
     * @return bool
299
     */
300
    protected function validateEditor()
301
    {
302
        $this->setSubmitted('editor', null, false);
303
304
        $this->setSubmitted('user_id', $this->uid);
305
        $this->setSubmitted('path', $this->data_file);
306
        $this->setSubmitted('module', $this->data_module);
307
308
        $content = $this->getSubmitted('content');
309
310
        if (!empty($content)) {
311
            $this->validateTwigEditor($content);
312
        }
313
        return !$this->hasErrors();
314
    }
315
316
    /**
317
     * Validates TWIG code
318
     * @param string $content
319
     * @return boolean
320
     */
321
    protected function validateTwigEditor($content)
322
    {
323
        $info = pathinfo($this->data_file);
324
325
        if ($info['extension'] !== 'twig' || !$this->config->isEnabledModule('twig')) {
326
            return null;
327
        }
328
329
        /* @var $module \gplcart\modules\twig\Twig */
330
        $module = $this->config->getModuleInstance('twig');
331
332
        $this->library->load('twig');
333
        $twig = $module->getTwigInstance($info['dirname'], $this);
334
335
        try {
336
            $twig->parse($twig->tokenize(new \Twig_Source($content, $info['basename'])));
337
            return true;
338
        } catch (\Twig_Error_Syntax $e) {
0 ignored issues
show
Bug introduced by
The class Twig_Error_Syntax does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
339
            $this->setError('content', $e->getMessage());
340
        }
341
        return false;
342
    }
343
344
    /**
345
     * Writes a submitted content to a theme file
346
     */
347
    protected function saveEditor()
348
    {
349
        $this->controlAccessSaveEditor();
350
351
        $submitted = $this->getSubmitted();
352
        $result = $this->editor->save($submitted);
353
354
        if ($result === true) {
355
            $message = $this->text('Theme file has been saved');
356
            $this->redirect("admin/tool/editor/{$submitted['module']['id']}", $message, 'success');
357
        }
358
359
        $message = $this->text('An error occurred');
360
        $this->redirect('', $message, 'warning');
361
    }
362
363
    /**
364
     * Whether the current user can save the file
365
     */
366
    protected function canSaveEditor()
367
    {
368
        return $this->access('editor_edit')//
369
                && $this->current_theme['id'] != $this->data_module['id'];
370
    }
371
372
    /**
373
     * Controls permissions to save a theme file for the current user
374
     */
375
    protected function controlAccessSaveEditor()
376
    {
377
        if (!$this->canSaveEditor()) {
378
            $this->outputHttpStatus(403);
379
        }
380
    }
381
382
    /**
383
     * Sets titles on the file edit page
384
     */
385
    protected function setTitleEditEditor()
386
    {
387
        $vars = array('%name' => substr($this->data_file, strlen(GC_MODULE_DIR . '/')));
388
        $text = $this->text('Edit file %name', $vars);
389
        $this->setTitle($text);
390
    }
391
392
    /**
393
     * Sets breadcrumbs on the file edit page
394
     */
395
    protected function setBreadcrumbEditEditor()
396
    {
397
        $breadcrumbs = array();
398
399
        $breadcrumbs[] = array(
400
            'url' => $this->url('admin'),
401
            'text' => $this->text('Dashboard')
402
        );
403
404
        $breadcrumbs[] = array(
405
            'url' => $this->url('admin/module/list'),
406
            'text' => $this->text('Modules')
407
        );
408
409
        $breadcrumbs[] = array(
410
            'url' => $this->url("admin/tool/editor/{$this->data_module['id']}"),
411
            'text' => $this->text('Edit theme %name', array('%name' => $this->data_module['name']))
412
        );
413
414
        $this->setBreadcrumbs($breadcrumbs);
415
    }
416
417
    /**
418
     * Renders the file edit page
419
     */
420
    protected function outputEditEditor()
421
    {
422
        $this->output('editor|edit');
423
    }
424
425
    /**
426
     * Returns a path to the file to be edited
427
     * @param string $encoded_filename URL encoded base64 hash
428
     * @return string
429
     */
430
    protected function setFilePathEditor($encoded_filename)
431
    {
432
        $filepath = gplcart_string_decode($encoded_filename);
433
        $file = "{$this->data_module['directory']}/$filepath";
434
435
        if (!is_file($file) || !is_readable($file)) {
436
            $this->outputHttpStatus(404);
437
        }
438
439
        return $this->data_file = $file;
440
    }
441
442
    /**
443
     * Returns a content of the file
444
     * @return string
445
     */
446
    protected function getFileContentEditor()
447
    {
448
        return file_get_contents($this->data_file);
449
    }
450
451
    /**
452
     * Returns the total number of lines in the file
453
     * @return integer
454
     */
455
    protected function getFileTotalLinesEditor()
456
    {
457
        return count(file($this->data_file));
458
    }
459
460
}
461