Completed
Push — master ( b5f6a4...1f08de )
by Iurii
01:14
created

Editor::getFileTotalLinesEditor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
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\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
        foreach ($data as $folder => $files) {
155
            foreach ($files as $file) {
156
157
                $path = trim(str_replace($this->data_module['directory'], '', $file), '/');
158
                $depth = substr_count(str_replace('\\', '/', $path), '/'); // WIN compatibility
159
160
                $pathinfo = pathinfo($path);
161
                $directory = is_dir($file);
162
                $parent = $directory ? $path : $pathinfo['dirname'];
163
164
                $prepared[$folder][$parent][] = array(
165
                    'file' => $file,
166
                    'path' => $path,
167
                    'depth' => $depth,
168
                    'directory' => $directory,
169
                    'name' => $pathinfo['basename'],
170
                    'id' => gplcart_string_encode($path),
171
                    'indentation' => str_repeat('<span class="indentation"></span>', $depth)
172
                );
173
            }
174
175
            ksort($prepared[$folder]);
176
        }
177
        return $prepared;
178
    }
179
180
    /**
181
     * Sets title on theme files overview page
182
     */
183
    protected function setTitleListEditor()
184
    {
185
        $text = $this->text('Edit theme %name', array('%name' => $this->data_module['name']));
186
        $this->setTitle($text);
187
    }
188
189
    /**
190
     * Sets breadcrumbs on theme files overview page
191
     */
192
    protected function setBreadcrumbListEditor()
193
    {
194
        $breadcrumbs = array();
195
196
        $breadcrumbs[] = array(
197
            'url' => $this->url('admin'),
198
            'text' => $this->text('Dashboard')
199
        );
200
201
        $breadcrumbs[] = array(
202
            'url' => $this->url('admin/module/list'),
203
            'text' => $this->text('Modules')
204
        );
205
206
        $this->setBreadcrumbs($breadcrumbs);
207
    }
208
209
    /**
210
     * Renders templates of theme files overview page
211
     */
212
    protected function outputListEditor()
213
    {
214
        $this->output('editor|list');
215
    }
216
217
    /**
218
     * Route callback
219
     * Displays the file edit page
220
     * @param string $module_id
221
     * @param string $file_id
222
     */
223
    public function editEditor($module_id, $file_id)
224
    {
225
        $this->setModuleEditor($module_id);
226
        $this->setFilePathEditor($file_id);
227
        $this->setTitleEditEditor();
228
        $this->setBreadcrumbEditEditor();
229
        $this->setMessageEditEditor();
230
231
        $this->setData('module', $this->data_module);
232
        $this->setData('can_save', $this->canSaveEditor());
233
        $this->setData('lines', count(file($this->data_file)));
234
        $this->setData('editor.content', file_get_contents($this->data_file));
235
236
        $this->submitEditor();
237
        $this->setJsSettingsEditor();
238
        $this->outputEditEditor();
239
    }
240
241
    /**
242
     * Sets messages on the file edit page
243
     */
244
    protected function setMessageEditEditor()
245
    {
246
        if ($this->current_theme['id'] == $this->data_module['id']) {
247
            $message = $this->text('You cannot edit the current theme');
248
            $this->setMessage($message, 'warning');
249
        } else if ($this->canSaveEditor() && $this->data_extension === 'php') {
250
            if (!$this->editor->canValidatePhpCode()) {
251
                $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!');
252
                $this->setMessage($message, 'warning');
253
            }
254
            $this->setMessage($this->text('Be careful! Invalid PHP code can break down all your site!'), 'danger');
255
        }
256
    }
257
258
    /**
259
     * Sets JavaScript settings on the file edit page
260
     */
261
    protected function setJsSettingsEditor()
262
    {
263
        $settings = array(
264
            'readonly' => !$this->canSaveEditor(),
265
            'file_extension' => $this->data_extension
266
        );
267
268
        $this->setJsSettings('editor', $settings);
269
    }
270
271
    /**
272
     * Saves an array of submitted data
273
     */
274
    protected function submitEditor()
275
    {
276
        if ($this->isPosted('save') && $this->validateEditor()) {
277
            $this->saveEditor();
278
        }
279
    }
280
281
    /**
282
     * Validates a submitted data when editing a theme file
283
     * @return bool
284
     */
285
    protected function validateEditor()
286
    {
287
        $this->setSubmitted('editor', null, false);
288
289
        $this->setSubmitted('user_id', $this->uid);
290
        $this->setSubmitted('path', $this->data_file);
291
        $this->setSubmitted('module', $this->data_module);
292
293
        $this->validateSyntaxEditor();
294
295
        return !$this->hasErrors();
296
    }
297
298
    /**
299
     * Validate syntax of a submitted file
300
     */
301
    protected function validateSyntaxEditor()
302
    {
303
        $code = $this->getSubmitted('content');
304
305
        if (empty($code) || $this->data_extension !== 'php') {
306
            return null;
307
        }
308
309
        $result = $this->editor->validatePhpCode($code);
310
311
        if (!isset($result) || $result === true) {
312
            return null;
313
        }
314
315
        $error = empty($result) ? $this->text('There is a syntax error in your file') : $result;
316
        $this->setError('content', $error);
317
    }
318
319
    /**
320
     * Writes a submitted content to a theme file
321
     */
322
    protected function saveEditor()
323
    {
324
        $this->controlAccessSaveEditor();
325
326
        $submitted = $this->getSubmitted();
327
        $result = $this->editor->save($submitted);
328
329
        if ($result === true) {
330
            $message = $this->text('File has been saved');
331
            $this->redirect("admin/tool/editor/{$submitted['module']['id']}", $message, 'success');
332
        }
333
334
        $this->redirect('', $this->text('An error occurred'), 'warning');
335
    }
336
337
    /**
338
     * Whether the current user can save the file
339
     */
340
    protected function canSaveEditor()
341
    {
342
        return $this->access('editor_edit') && $this->current_theme['id'] != $this->data_module['id'];
343
    }
344
345
    /**
346
     * Controls permissions to save a theme file for the current user
347
     */
348
    protected function controlAccessSaveEditor()
349
    {
350
        if (!$this->canSaveEditor()) {
351
            $this->outputHttpStatus(403);
352
        }
353
    }
354
355
    /**
356
     * Sets titles on the file edit page
357
     */
358
    protected function setTitleEditEditor()
359
    {
360
        $vars = array('%name' => str_replace('\\', '/', gplcart_path_relative($this->data_file)));
361
        $this->setTitle($this->text('Edit %name', $vars));
362
    }
363
364
    /**
365
     * Sets breadcrumbs on the file edit page
366
     */
367
    protected function setBreadcrumbEditEditor()
368
    {
369
        $breadcrumbs = array();
370
371
        $breadcrumbs[] = array(
372
            'url' => $this->url('admin'),
373
            'text' => $this->text('Dashboard')
374
        );
375
376
        $breadcrumbs[] = array(
377
            'url' => $this->url('admin/module/list'),
378
            'text' => $this->text('Modules')
379
        );
380
381
        $breadcrumbs[] = array(
382
            'url' => $this->url('admin/tool/editor'),
383
            'text' => $this->text('Themes')
384
        );
385
386
        $breadcrumbs[] = array(
387
            'url' => $this->url("admin/tool/editor/{$this->data_module['id']}"),
388
            'text' => $this->text('Edit theme %name', array('%name' => $this->data_module['name']))
389
        );
390
391
        $this->setBreadcrumbs($breadcrumbs);
392
    }
393
394
    /**
395
     * Renders the file edit page
396
     */
397
    protected function outputEditEditor()
398
    {
399
        $this->output('editor|edit');
400
    }
401
402
    /**
403
     * Returns a path to the file to be edited
404
     * @param string $encoded_filename URL encoded base64 hash
405
     */
406
    protected function setFilePathEditor($encoded_filename)
407
    {
408
        $filepath = gplcart_string_decode($encoded_filename);
409
        $this->data_file = "{$this->data_module['directory']}/$filepath";
410
411
        if (!is_file($this->data_file) || !is_readable($this->data_file)) {
412
            $this->outputHttpStatus(404);
413
        }
414
415
        $this->data_extension = pathinfo($this->data_file, PATHINFO_EXTENSION);
416
    }
417
418
}
419