Completed
Push — master ( 39c45f...a739bd )
by Iurii
01:47
created

Editor   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 440
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 45
lcom 1
cbo 1
dl 0
loc 440
rs 8.3673
c 0
b 0
f 0

27 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A themeEditor() 0 9 1
A setTitleThemeEditor() 0 4 1
A setBreadcrumbThemeEditor() 0 16 1
A outputThemeEditor() 0 4 1
A listEditor() 0 12 1
A setModuleEditor() 0 14 3
A getFilesEditor() 0 5 1
B prepareFilesEditor() 0 29 4
A setTitleListEditor() 0 5 1
A setBreadcrumbListEditor() 0 21 1
A outputListEditor() 0 4 1
A editEditor() 0 20 1
A setMessageEditEditor() 0 12 3
A setJsSettingsEditor() 0 9 1
A submitEditor() 0 6 3
A validateEditor() 0 15 2
A validateTwigEditor() 0 20 4
A saveEditor() 0 15 2
A canSaveEditor() 0 5 2
A controlAccessSaveEditor() 0 6 2
A setTitleEditEditor() 0 6 1
A setBreadcrumbEditEditor() 0 21 1
A outputEditEditor() 0 4 1
A setFilePathEditor() 0 11 3
A getFileContentEditor() 0 4 1
A getFileTotalLinesEditor() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Editor often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Editor, and based on these observations, apply Extract Interface, too.

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