Completed
Push — master ( ccb048...2c2af4 )
by Iurii
01:02
created

Editor::setMessageEditEditor()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 9
nc 4
nop 0
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
     * The current file extension
48
     * @var string
49
     */
50
    protected $data_extension;
51
52
    /**
53
     * @param EditorModuleModel $editor
54
     * @param ModuleModel $module
55
     */
56
    public function __construct(EditorModuleModel $editor, ModuleModel $module)
57
    {
58
        parent::__construct();
59
60
        $this->editor = $editor;
61
        $this->module = $module;
62
    }
63
64
    /**
65
     * Route callback to display the select theme page
66
     */
67
    public function themeEditor()
68
    {
69
        $this->setTitleThemeEditor();
70
        $this->setBreadcrumbThemeEditor();
71
72
        $this->setData('themes', $this->module->getByType('theme'));
73
74
        $this->outputThemeEditor();
75
    }
76
77
    /**
78
     * Set title on the select theme page
79
     */
80
    protected function setTitleThemeEditor()
81
    {
82
        $this->setTitle($this->text('Themes'));
83
    }
84
85
    /**
86
     * Set breadcrumbs on the select theme page
87
     */
88
    protected function setBreadcrumbThemeEditor()
89
    {
90
        $breadcrumbs = array();
91
92
        $breadcrumbs[] = array(
93
            'url' => $this->url('admin'),
94
            'text' => $this->text('Dashboard')
95
        );
96
97
        $breadcrumbs[] = array(
98
            'url' => $this->url('admin/module/list'),
99
            'text' => $this->text('Modules')
100
        );
101
102
        $this->setBreadcrumbs($breadcrumbs);
103
    }
104
105
    /**
106
     * Output rendered templates on the select theme page
107
     */
108
    protected function outputThemeEditor()
109
    {
110
        $this->output('editor|themes');
111
    }
112
113
    /**
114
     * Displays the module file overview page
115
     * @param integer $module_id
116
     */
117
    public function listEditor($module_id)
118
    {
119
        $this->setModuleEditor($module_id);
120
121
        $this->setTitleListEditor();
122
        $this->setBreadcrumbListEditor();
123
124
        $this->setData('module', $this->data_module);
125
        $this->setData('files', $this->getFilesEditor());
126
127
        $this->outputListEditor();
128
    }
129
130
    /**
131
     * Returns an array of module data
132
     * @param string $module_id
133
     */
134
    protected function setModuleEditor($module_id)
135
    {
136
        $this->data_module = $this->module->get($module_id);
137
138
        if (empty($this->data_module)) {
139
            $this->outputHttpStatus(404);
140
        }
141
142
        if ($this->data_module['type'] !== 'theme') {
143
            $this->outputHttpStatus(403);
144
        }
145
    }
146
147
    /**
148
     * Returns an array of files to edit
149
     * @return array
150
     */
151
    protected function getFilesEditor()
152
    {
153
        $data = $this->editor->getList($this->data_module);
154
        return $this->prepareFilesEditor($data);
155
    }
156
157
    /**
158
     * Prepares an array of files to be edited
159
     * @param array $data
160
     * @return array
161
     */
162
    protected function prepareFilesEditor(array $data)
163
    {
164
        $prepared = array();
165
        foreach ($data as $folder => $files) {
166
            foreach ($files as $file) {
167
168
                $path = trim(str_replace($this->data_module['directory'], '', $file), '/');
169
                $depth = substr_count(str_replace('\\', '/', $path), '/'); // WIN compatibility
170
171
                $pathinfo = pathinfo($path);
172
                $directory = is_dir($file);
173
                $parent = $directory ? $path : $pathinfo['dirname'];
174
175
                $prepared[$folder][$parent][] = array(
176
                    'file' => $file,
177
                    'path' => $path,
178
                    'depth' => $depth,
179
                    'directory' => $directory,
180
                    'name' => $pathinfo['basename'],
181
                    'id' => gplcart_string_encode($path),
182
                    'indentation' => str_repeat('<span class="indentation"></span>', $depth)
183
                );
184
            }
185
186
            ksort($prepared[$folder]);
187
        }
188
        return $prepared;
189
    }
190
191
    /**
192
     * Sets title on theme files overview page
193
     */
194
    protected function setTitleListEditor()
195
    {
196
        $text = $this->text('Edit theme %name', array('%name' => $this->data_module['name']));
197
        $this->setTitle($text);
198
    }
199
200
    /**
201
     * Sets breadcrumbs on theme files overview page
202
     */
203
    protected function setBreadcrumbListEditor()
204
    {
205
        $breadcrumbs = array();
206
207
        $breadcrumbs[] = array(
208
            'url' => $this->url('admin'),
209
            'text' => $this->text('Dashboard')
210
        );
211
212
        $breadcrumbs[] = array(
213
            'url' => $this->url('admin/module/list'),
214
            'text' => $this->text('Modules')
215
        );
216
217
        $this->setBreadcrumbs($breadcrumbs);
218
    }
219
220
    /**
221
     * Renders templates of theme files overview page
222
     */
223
    protected function outputListEditor()
224
    {
225
        $this->output('editor|list');
226
    }
227
228
    /**
229
     * Displays the file edit page
230
     * @param string $module_id
231
     * @param string $file_id
232
     */
233
    public function editEditor($module_id, $file_id)
234
    {
235
        $this->setModuleEditor($module_id);
236
        $this->setFilePathEditor($file_id);
237
238
        $this->setTitleEditEditor();
239
        $this->setBreadcrumbEditEditor();
240
        $this->setMessageEditEditor();
241
242
        $this->setData('module', $this->data_module);
243
        $this->setData('can_save', $this->canSaveEditor());
244
        $this->setData('lines', $this->getFileTotalLinesEditor());
245
        $this->setData('editor.content', $this->getFileContentEditor());
246
247
        $this->submitEditor();
248
249
        $this->setJsSettingsEditor();
250
        $this->outputEditEditor();
251
    }
252
253
    /**
254
     * Sets messages on the file edit page
255
     */
256
    protected function setMessageEditEditor()
257
    {
258
        if ($this->current_theme['id'] == $this->data_module['id']) {
259
            $message = $this->text('You cannot edit the current theme');
260
            $this->setMessage($message, 'warning');
261
        } else if ($this->canSaveEditor() && $this->data_extension === 'php') {
262
            $this->setMessage($this->text('Be careful! Invalid PHP code can break down all your site!'), 'danger');
263
            if (!$this->editor->canValidatePhpCode()) {
264
                $message = $this->text('PHP syntax validation is disabled due to your environment settings');
265
                $this->setMessage($message, 'warning');
266
            }
267
        }
268
    }
269
270
    /**
271
     * Sets JavaScript settings on the file edit page
272
     */
273
    protected function setJsSettingsEditor()
274
    {
275
        $settings = array(
276
            'readonly' => !$this->canSaveEditor(),
277
            'file_extension' => $this->data_extension
278
        );
279
280
        $this->setJsSettings('editor', $settings);
281
    }
282
283
    /**
284
     * Saves an array of submitted data
285
     */
286
    protected function submitEditor()
287
    {
288
        if ($this->isPosted('save') && $this->validateEditor()) {
289
            $this->saveEditor();
290
        }
291
    }
292
293
    /**
294
     * Validates a submitted data when editing a theme file
295
     * @return bool
296
     */
297
    protected function validateEditor()
298
    {
299
        $this->setSubmitted('editor', null, false);
300
301
        $this->setSubmitted('user_id', $this->uid);
302
        $this->setSubmitted('path', $this->data_file);
303
        $this->setSubmitted('module', $this->data_module);
304
305
        $this->validateSyntaxEditor();
306
307
        return !$this->hasErrors();
308
    }
309
310
    /**
311
     * Validate syntax of a submitted file
312
     */
313
    protected function validateSyntaxEditor()
314
    {
315
        $code = $this->getSubmitted('content');
316
317
        if (empty($code) || $this->data_extension !== 'php') {
318
            return null;
319
        }
320
321
        $result = $this->editor->validatePhpCode($code);
322
323
        if (!isset($result) || $result === true) {
324
            return null;
325
        }
326
327
        $error = empty($result) ? $this->text('There is a syntax error in your file') : $result;
328
        $this->setError('content', $error);
329
    }
330
331
    /**
332
     * Writes a submitted content to a theme file
333
     */
334
    protected function saveEditor()
335
    {
336
        $this->controlAccessSaveEditor();
337
338
        $submitted = $this->getSubmitted();
339
        $result = $this->editor->save($submitted);
340
341
        if ($result === true) {
342
            $message = $this->text('Theme file has been saved');
343
            $this->redirect("admin/tool/editor/{$submitted['module']['id']}", $message, 'success');
344
        }
345
346
        $this->redirect('', $this->text('An error occurred'), 'warning');
347
    }
348
349
    /**
350
     * Whether the current user can save the file
351
     */
352
    protected function canSaveEditor()
353
    {
354
        return $this->access('editor_edit')//
355
                && $this->current_theme['id'] != $this->data_module['id'];
356
    }
357
358
    /**
359
     * Controls permissions to save a theme file for the current user
360
     */
361
    protected function controlAccessSaveEditor()
362
    {
363
        if (!$this->canSaveEditor()) {
364
            $this->outputHttpStatus(403);
365
        }
366
    }
367
368
    /**
369
     * Sets titles on the file edit page
370
     */
371
    protected function setTitleEditEditor()
372
    {
373
        $vars = array('%name' => str_replace('\\', '/', gplcart_relative_path($this->data_file)));
374
        $this->setTitle($this->text('Edit file %name', $vars));
375
    }
376
377
    /**
378
     * Sets breadcrumbs on the file edit page
379
     */
380
    protected function setBreadcrumbEditEditor()
381
    {
382
        $breadcrumbs = array();
383
384
        $breadcrumbs[] = array(
385
            'url' => $this->url('admin'),
386
            'text' => $this->text('Dashboard')
387
        );
388
389
        $breadcrumbs[] = array(
390
            'url' => $this->url('admin/module/list'),
391
            'text' => $this->text('Modules')
392
        );
393
394
        $breadcrumbs[] = array(
395
            'url' => $this->url('admin/tool/editor'),
396
            'text' => $this->text('Themes')
397
        );
398
399
        $breadcrumbs[] = array(
400
            'url' => $this->url("admin/tool/editor/{$this->data_module['id']}"),
401
            'text' => $this->text('Edit theme %name', array('%name' => $this->data_module['name']))
402
        );
403
404
        $this->setBreadcrumbs($breadcrumbs);
405
    }
406
407
    /**
408
     * Renders the file edit page
409
     */
410
    protected function outputEditEditor()
411
    {
412
        $this->output('editor|edit');
413
    }
414
415
    /**
416
     * Returns a path to the file to be edited
417
     * @param string $encoded_filename URL encoded base64 hash
418
     */
419
    protected function setFilePathEditor($encoded_filename)
420
    {
421
        $filepath = gplcart_string_decode($encoded_filename);
422
        $this->data_file = "{$this->data_module['directory']}/$filepath";
423
424
        if (!is_file($this->data_file) || !is_readable($this->data_file)) {
425
            $this->outputHttpStatus(404);
426
        }
427
428
        $this->data_extension = pathinfo($this->data_file, PATHINFO_EXTENSION);
429
    }
430
431
    /**
432
     * Returns a content of the file
433
     * @return string
434
     */
435
    protected function getFileContentEditor()
436
    {
437
        return file_get_contents($this->data_file);
438
    }
439
440
    /**
441
     * Returns the total number of lines in the file
442
     * @return integer
443
     */
444
    protected function getFileTotalLinesEditor()
445
    {
446
        return count(file($this->data_file));
447
    }
448
449
}
450