Editor::submitEditor()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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