Completed
Push — master ( 6470f1...618439 )
by Iurii
01:11
created

Editor::setTitleEditEditor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
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
        $module = $this->module->get($module_id);
137
138
        if (empty($module)) {
139
            $this->outputHttpStatus(404);
140
        }
141
142
        if ($module['type'] !== 'theme') {
143
            $this->outputHttpStatus(403);
144
        }
145
146
        $this->data_module = $module;
147
    }
148
149
    /**
150
     * Returns an array of files to edit
151
     * @return array
152
     */
153
    protected function getFilesEditor()
154
    {
155
        $data = $this->editor->getList($this->data_module);
156
        return $this->prepareFilesEditor($data);
157
    }
158
159
    /**
160
     * Prepares an array of files to be edited
161
     * @param array $data
162
     * @return array
163
     */
164
    protected function prepareFilesEditor(array $data)
165
    {
166
        $prepared = array();
167
        foreach ($data as $folder => $files) {
168
            foreach ($files as $file) {
169
170
                $path = trim(str_replace($this->data_module['directory'], '', $file), '/');
171
                $depth = substr_count(str_replace('\\', '/', $path), '/'); // WIN compatibility
172
173
                $pathinfo = pathinfo($path);
174
                $directory = is_dir($file);
175
                $parent = $directory ? $path : $pathinfo['dirname'];
176
177
                $prepared[$folder][$parent][] = array(
178
                    'file' => $file,
179
                    'path' => $path,
180
                    'depth' => $depth,
181
                    'directory' => $directory,
182
                    'name' => $pathinfo['basename'],
183
                    'id' => gplcart_string_encode($path),
184
                    'indentation' => str_repeat('<span class="indentation"></span>', $depth)
185
                );
186
            }
187
188
            ksort($prepared[$folder]);
189
        }
190
        return $prepared;
191
    }
192
193
    /**
194
     * Sets title on theme files overview page
195
     */
196
    protected function setTitleListEditor()
197
    {
198
        $text = $this->text('Edit theme %name', array('%name' => $this->data_module['name']));
199
        $this->setTitle($text);
200
    }
201
202
    /**
203
     * Sets breadcrumbs on theme files overview page
204
     */
205
    protected function setBreadcrumbListEditor()
206
    {
207
        $breadcrumbs = array();
208
209
        $breadcrumbs[] = array(
210
            'url' => $this->url('admin'),
211
            'text' => $this->text('Dashboard')
212
        );
213
214
        $breadcrumbs[] = array(
215
            'url' => $this->url('admin/module/list'),
216
            'text' => $this->text('Modules')
217
        );
218
219
        $this->setBreadcrumbs($breadcrumbs);
220
    }
221
222
    /**
223
     * Renders templates of theme files overview page
224
     */
225
    protected function outputListEditor()
226
    {
227
        $this->output('editor|list');
228
    }
229
230
    /**
231
     * Displays the file edit page
232
     * @param string $module_id
233
     * @param string $file_id
234
     */
235
    public function editEditor($module_id, $file_id)
236
    {
237
        $this->setModuleEditor($module_id);
238
        $this->setFilePathEditor($file_id);
239
240
        $this->setTitleEditEditor();
241
        $this->setBreadcrumbEditEditor();
242
        $this->setMessageEditEditor();
243
244
        $this->setData('module', $this->data_module);
245
        $this->setData('can_save', $this->canSaveEditor());
246
        $this->setData('lines', $this->getFileTotalLinesEditor());
247
        $this->setData('editor.content', $this->getFileContentEditor());
248
249
        $this->submitEditor();
250
251
        $this->setJsSettingsEditor();
252
        $this->outputEditEditor();
253
    }
254
255
    /**
256
     * Sets messages on the file edit page
257
     */
258
    protected function setMessageEditEditor()
259
    {
260
        if ($this->canSaveEditor() && $this->data_extension === 'php') {
261
            $this->setMessage($this->text('Be careful! Invalid PHP code can break down all your site!'), 'danger');
262
            if (!$this->editor->canValidatePhpCode()) {
263
                $message = $this->text('PHP syntax validation is disabled due to your environment settings');
264
                $this->setMessage($message, 'warning');
265
            }
266
        }
267
    }
268
269
    /**
270
     * Sets JavaScript settings on the file edit page
271
     */
272
    protected function setJsSettingsEditor()
273
    {
274
        $settings = array(
275
            'readonly' => !$this->canSaveEditor(),
276
            'file_extension' => $this->data_extension
277
        );
278
279
        $this->setJsSettings('editor', $settings);
280
    }
281
282
    /**
283
     * Saves an array of submitted data
284
     */
285
    protected function submitEditor()
286
    {
287
        if ($this->isPosted('save') && $this->validateEditor()) {
288
            $this->saveEditor();
289
        }
290
    }
291
292
    /**
293
     * Validates a submitted data when editing a theme file
294
     * @return bool
295
     */
296
    protected function validateEditor()
297
    {
298
        $this->setSubmitted('editor', null, false);
299
300
        $this->setSubmitted('user_id', $this->uid);
301
        $this->setSubmitted('path', $this->data_file);
302
        $this->setSubmitted('module', $this->data_module);
303
304
        $this->validateSyntaxEditor();
305
306
        return !$this->hasErrors();
307
    }
308
309
    /**
310
     * Validate syntax of a submitted file
311
     */
312
    protected function validateSyntaxEditor()
313
    {
314
        $code = $this->getSubmitted('content');
315
316
        if (empty($code) || $this->data_extension !== 'php') {
317
            return null;
318
        }
319
320
        $result = $this->editor->validatePhpCode($code);
321
322
        if (!isset($result) || $result === true) {
323
            return null;
324
        }
325
326
        $error = empty($result) ? $this->text('There is a syntax error in your file') : $result;
327
        $this->setError('content', $error);
328
    }
329
330
    /**
331
     * Writes a submitted content to a theme file
332
     */
333
    protected function saveEditor()
334
    {
335
        $this->controlAccessSaveEditor();
336
337
        $submitted = $this->getSubmitted();
338
        $result = $this->editor->save($submitted);
339
340
        if ($result === true) {
341
            $message = $this->text('Theme file has been saved');
342
            $this->redirect("admin/tool/editor/{$submitted['module']['id']}", $message, 'success');
343
        }
344
345
        $this->redirect('', $this->text('An error occurred'), 'warning');
346
    }
347
348
    /**
349
     * Whether the current user can save the file
350
     */
351
    protected function canSaveEditor()
352
    {
353
        return $this->access('editor_edit')//
354
                && $this->current_theme['id'] != $this->data_module['id'];
355
    }
356
357
    /**
358
     * Controls permissions to save a theme file for the current user
359
     */
360
    protected function controlAccessSaveEditor()
361
    {
362
        if (!$this->canSaveEditor()) {
363
            $this->outputHttpStatus(403);
364
        }
365
    }
366
367
    /**
368
     * Sets titles on the file edit page
369
     */
370
    protected function setTitleEditEditor()
371
    {
372
        $vars = array('%name' => str_replace('\\', '/', gplcart_relative_path($this->data_file)));
373
        $text = $this->text('Edit file %name', $vars);
374
        $this->setTitle($text);
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
        $file = "{$this->data_module['directory']}/$filepath";
423
424
        if (!is_file($file) || !is_readable($file)) {
425
            $this->outputHttpStatus(404);
426
        }
427
428
        $this->data_file = $file;
429
        $this->data_extension = pathinfo($file, PATHINFO_EXTENSION);
430
    }
431
432
    /**
433
     * Returns a content of the file
434
     * @return string
435
     */
436
    protected function getFileContentEditor()
437
    {
438
        return file_get_contents($this->data_file);
439
    }
440
441
    /**
442
     * Returns the total number of lines in the file
443
     * @return integer
444
     */
445
    protected function getFileTotalLinesEditor()
446
    {
447
        return count(file($this->data_file));
448
    }
449
450
}
451