VisualEditorWidget::getEditHtml()   F
last analyzed

Complexity

Conditions 17
Paths 421

Size

Total Lines 139
Code Lines 100

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 17
eloc 100
nc 421
nop 0
dl 0
loc 139
rs 3.5837
c 2
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace DigitalWand\AdminHelper\Widget;
4
5
/**
6
 * Визуальный редактор.
7
 *
8
 * В отличии от виджета TextAreaWidget, кроме поля указанного в интерфейсе раздела (AdminInterface::fields()),
9
 * обязательно поле {НАЗВАНИЕ ПОЛЯ}_TEXT_TYPE, в котором будет хранится тип контента (text/html).
10
 */
11
class VisualEditorWidget extends TextAreaWidget
12
{
13
    /**
14
     * @const string Текст. Тип содержимого редактора
15
     */
16
    const CONTENT_TYPE_TEXT = 'text';
17
    /**
18
     * @const string HTML-текст. Тип содержимого редактора
19
     */
20
    const CONTENT_TYPE_HTML = 'html';
21
22
    protected static $defaults = array(
23
        'WIDTH' => '100%',
24
        'HEIGHT' => 450,
25
        'EDITORS' => array(
26
            'EDITOR'
27
        ),
28
        'DEFAULT_EDITOR' => 'EDITOR',
29
        'LIGHT_EDITOR_MODE' => 'N',
30
        'EDITOR_TOOLBAR_CONFIG_SET' => 'FULL', // SIMPLE
31
        'EDITOR_TOOLBAR_CONFIG' => false,
32
    );
33
34
    /**
35
     * @inheritdoc
36
     */
37
    protected function getEditHtml()
0 ignored issues
show
Coding Style introduced by
getEditHtml uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
38
    {
39
        if (\CModule::IncludeModule('fileman')) {
40
            ob_start();
41
            $codeType = $this->getContentTypeCode();
42
            /** @var string $className Имя класса без неймспейса */
43
            $className = $this->getEntityShortName();
44
            $entityClass = $this->entityName;
45
            $modelPk = $entityClass::getEntity()->getPrimary();
46
            $id = isset($this->data[$modelPk]) ? $this->data[$modelPk] : false;
47
            $bxCode = $this->code . '_' . $className;
48
            $bxCodeType = $codeType . '_' . $className;
49
50
            if ($this->forceMultiple) {
0 ignored issues
show
Bug introduced by
The property forceMultiple does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
51
                if ($id) {
52
                    $bxCode .= '_' . $id;
53
                    $bxCodeType .= '_' . $id;
54
                } else {
55
                    $bxCode .= '_new_';
56
                    $bxCodeType .= '_new_';
57
                }
58
            }
59
60
            // TODO Избавиться от данного костыля
61
            if ($_REQUEST[$bxCode]) {
62
                $this->data[$this->code] = $_REQUEST[$bxCode];
63
            }
64
65
            $editorToolbarSets = array(
66
                'FULL' => array(
67
                    'Bold', 'Italic', 'Underline', 'Strike', 'RemoveFormat',
68
                    'CreateLink', 'DeleteLink', 'Image', 'Video',
69
                    'BackColor', 'ForeColor',
70
                    'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyFull',
71
                    'InsertOrderedList', 'InsertUnorderedList', 'Outdent', 'Indent',
72
                    'StyleList', 'HeaderList',
73
                    'FontList', 'FontSizeList'
74
                ),
75
                'SIMPLE' => array(
76
                    'Bold', 'Italic', 'Underline', 'Strike', 'RemoveFormat',
77
                    'CreateLink', 'DeleteLink',
78
                    'Video',
79
                    'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyFull',
80
                    'InsertOrderedList', 'InsertUnorderedList', 'Outdent', 'Indent',
81
                    'FontList', 'FontSizeList',
82
                )
83
            );
84
85
            if ($this->getSettings('LIGHT_EDITOR_MODE') == 'Y') {
86
                // Облегченная версия редактора
87
                global $APPLICATION;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
88
                
89
                $editorToolbarConfig = $this->getSettings('EDITOR_TOOLBAR_CONFIG');
90
                
91
                if (!is_array($editorToolbarConfig)) {
92
                    $editorToolbarSet = $this->getSettings('EDITOR_TOOLBAR_CONFIG_SET');
93
                    if (isset($editorToolbarSets[$editorToolbarSet])) {
94
                        $editorToolbarConfig = $editorToolbarSets[$editorToolbarSet];
95
                    } else {
96
                        $editorToolbarConfig = $editorToolbarSets['FULL'];
97
                    }
98
                }
99
                
100
                $APPLICATION->IncludeComponent('bitrix:fileman.light_editor', '', array(
101
                        'CONTENT' => $this->data[$this->code],
102
                        'INPUT_NAME' => $bxCode,
103
                        'INPUT_ID' => $bxCode,
104
                        'WIDTH' => $this->getSettings('WIDTH'),
105
                        'HEIGHT' => $this->getSettings('HEIGHT'),
106
                        'RESIZABLE' => 'N',
107
                        'AUTO_RESIZE' => 'N',
108
                        'VIDEO_ALLOW_VIDEO' => 'Y',
109
                        'VIDEO_MAX_WIDTH' => $this->getSettings('WIDTH'),
110
                        'VIDEO_MAX_HEIGHT' => $this->getSettings('HEIGHT'),
111
                        'VIDEO_BUFFER' => '20',
112
                        'VIDEO_LOGO' => '',
113
                        'VIDEO_WMODE' => 'transparent',
114
                        'VIDEO_WINDOWLESS' => 'Y',
115
                        'VIDEO_SKIN' => '/bitrix/components/bitrix/player/mediaplayer/skins/bitrix.swf',
116
                        'USE_FILE_DIALOGS' => 'Y',
117
                        'ID' => 'LIGHT_EDITOR_' . $bxCode,
118
                        'JS_OBJ_NAME' => $bxCode,
119
                        'TOOLBAR_CONFIG' => $editorToolbarConfig
120
                    )
121
                );
122
            } else {
123
                // Полная версия редактора
124
                \CFileMan::AddHTMLEditorFrame(
125
                    $bxCode,
126
                    $this->data[$this->code],
127
                    $bxCodeType,
128
                    $this->data[$codeType],
129
                    array(
130
                        'width' => $this->getSettings('WIDTH'),
131
                        'height' => $this->getSettings('HEIGHT'),
132
                    )
133
                );
134
                
135
                $defaultEditors = array(
136
                    static::CONTENT_TYPE_TEXT => static::CONTENT_TYPE_TEXT,
137
                    static::CONTENT_TYPE_HTML => static::CONTENT_TYPE_HTML,
138
                    'editor' => 'editor'
139
                );
140
                $editors = $this->getSettings('EDITORS');
141
                $defaultEditor = strtolower($this->getSettings('DEFAULT_EDITOR'));
142
                $contentType = $this->getContentType();
143
                $defaultEditor = isset($contentType) && $contentType == static::CONTENT_TYPE_TEXT ? static::CONTENT_TYPE_TEXT : $defaultEditor;
144
                $defaultEditor = isset($contentType) && $contentType == static::CONTENT_TYPE_HTML ? "editor" : $defaultEditor;
145
146
                if (count($editors) > 1) {
147
                    foreach ($editors as &$editor) {
148
                        $editor = strtolower($editor);
149
                        if (isset($defaultEditors[$editor])) {
150
                            unset($defaultEditors[$editor]);
151
                        }
152
                    }
153
                }
154
155
                $script = '<script type="text/javascript">';
156
                $script .= '$(document).ready(function() {';
157
158
                foreach ($defaultEditors as $editor) {
159
                    $script .= '$("#bxed_' . $bxCode . '_' . $editor . '").parent().hide();';
160
                }
161
162
                $script .= '$("#bxed_' . $bxCode . '_' . $defaultEditor . '").click();';
163
                $script .= 'setTimeout(function() {$("#bxed_' . $bxCode . '_' . $defaultEditor . '").click(); }, 500);';
164
                $script .= "});";
165
                $script .= '</script>';
166
167
                echo $script;
168
            }
169
            $html = ob_get_clean();
170
171
            return $html;
172
        } else {
173
            return parent::getEditHtml();
174
        }
175
    }
176
177
    /**
178
     * @inheritdoc
179
     */
180
    public function showBasicEditField($isPKField)
181
    {
182
        if (!\CModule::IncludeModule('fileman')) {
183
            parent::showBasicEditField($isPKField);
184
        } else {
185
            $title = $this->getSettings('TITLE');
186
            if ($this->getSettings('REQUIRED') === true) {
187
                $title = '<b>' . $title . '</b>';
188
            }
189
            print '<tr class="heading"><td colspan="2">' . $title . '</td></tr>';
190
            print '<tr><td colspan="2">';
191
            $readOnly = $this->getSettings('READONLY');
192
            if (!$readOnly) {
193
                print $this->getEditHtml();
194
            } else {
195
                print $this->getValueReadonly();
196
            }
197
            print '</td></tr>';
198
        }
199
    }
200
201
    /**
202
     * @inheritdoc
203
     */
204
    public function processEditAction()
0 ignored issues
show
Coding Style introduced by
processEditAction uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
205
    {
206
        $entityClass = $this->entityName;
207
        $modelPk = $entityClass::getEntity()->getPrimary();
208
        $className = $this->getEntityShortName();
209
        $currentView = $this->getCurrentViewType();
210
211
        switch ($currentView) {
212
            case HelperWidget::EDIT_HELPER:
213
                $id = isset($this->data[$modelPk]) ? $this->data[$modelPk] : false;
214
                $codeType = $this->getContentTypeCode();
215
                $bxCode = $this->getCode() . '_' . $className;
216
                $bxCodeType = $codeType . '_' . $className;
217
                
218
                if ($this->forceMultiple AND $id) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
219
                    $bxCode .= '_' . $id;
220
                    $bxCodeType .= '_' . $id;
221
                }
222
                
223
                if (!$_REQUEST[$bxCode] && $this->getSettings('REQUIRED') == true) {
224
                    $this->addError('DIGITALWAND_AH_REQUIRED_FIELD_ERROR');
225
                }
226
                
227
                $this->data[$this->code] = $_REQUEST[$bxCode];
228
                $this->data[$codeType] = $_REQUEST[$bxCodeType];
229
                break;
230
            case HelperWidget::LIST_HELPER:
231
            default:
232
                parent::processEditAction();
233
                break;
234
        }
235
    }
236
237
    /**
238
     * @inheritdoc
239
     */
240
    protected function getValueReadonly()
241
    {
242
        return $this->getContentType() == static::CONTENT_TYPE_HTML ? $this->data[$this->code] : parent::getValueReadOnly();
243
    }
244
245
    /**
246
     * @inheritdoc
247
     */
248
    public function generateRow(&$row, $data)
249
    {
250
        $text = trim(strip_tags($data[$this->code]));
251
252 View Code Duplication
        if (strlen($text) > self::LIST_TEXT_SIZE && !$this->isExcelView()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
253
            $pos = false;
254
            $pos = $pos === false ? stripos($text, " ", self::LIST_TEXT_SIZE) : $pos;
255
            $pos = $pos === false ? stripos($text, "\n", self::LIST_TEXT_SIZE) : $pos;
256
            $pos = $pos === false ? stripos($text, "</", self::LIST_TEXT_SIZE) : $pos;
257
            $pos = $pos === false ? 300 : $pos;
258
            $text = substr($text, 0, $pos) . " ...";
259
        }
260
261
        $text = static::prepareToOutput($text);
262
        $row->AddViewField($this->code, $text);
263
    }
264
265
    /**
266
     * Тип текста (text/html). По умолчанию html.
267
     * 
268
     * @return string
269
     */
270
    public function getContentType()
271
    {
272
        $contentType = $this->data[$this->getContentTypeCode()];
273
274
        return empty($contentType) ? static::CONTENT_TYPE_HTML : $contentType;
275
    }
276
277
    /**
278
     * Поле, в котором хранится тип текста.
279
     * 
280
     * @return string
281
     */
282
    public function getContentTypeCode()
283
    {
284
        return $this->code . '_TEXT_TYPE';
285
    }
286
287
    /**
288
     * Название класса без неймспейса.
289
     *
290
     * @return string
291
     */
292
    protected function getEntityShortName()
293
    {
294
        return end(explode('\\', $this->entityName));
0 ignored issues
show
Bug introduced by
explode('\\', $this->entityName) cannot be passed to end() as the parameter $array expects a reference.
Loading history...
295
    }
296
}