Completed
Push — master ( 1f4754...7f6945 )
by Dmitry
02:43
created

JsonEditor::registerClientScript()   C

Complexity

Conditions 10
Paths 48

Size

Total Lines 54
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 44
CRAP Score 10

Importance

Changes 0
Metric Value
dl 0
loc 54
ccs 44
cts 44
cp 1
rs 6.8372
c 0
b 0
f 0
cc 10
eloc 38
nc 48
nop 0
crap 10

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 kdn\yii2;
4
5
use kdn\yii2\assets\JsonEditorFullAsset;
6
use kdn\yii2\assets\JsonEditorMinimalistAsset;
7
use yii\helpers\ArrayHelper;
8
use yii\helpers\Html;
9
use yii\helpers\Inflector;
10
use yii\helpers\Json;
11
use yii\web\JsExpression;
12
use yii\widgets\InputWidget;
13
14
/**
15
 * Class JsonEditor.
16
 * @package kdn\yii2
17
 */
18
class JsonEditor extends InputWidget
19
{
20
    /**
21
     * @var array options which will be passed to JSON editor
22
     * @see https://github.com/josdejong/jsoneditor/blob/master/docs/api.md#configuration-options
23
     */
24
    public $clientOptions = [];
25
26
    /**
27
     * @var string[] list of JSON editor modes for which all fields should be collapsed automatically;
28
     * allowed modes 'tree', 'view', and 'form'
29
     * @see https://github.com/josdejong/jsoneditor/blob/master/docs/api.md#jsoneditorcollapseall
30
     */
31
    public $collapseAll = [];
32
33
    /**
34
     * @var array HTML attributes to be applied to the JSON editor container tag
35
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered
36
     */
37
    public $containerOptions = [];
38
39
    /**
40
     * @var string default value
41
     */
42
    public $defaultValue = '{}';
43
44
    /**
45
     * @var string[] list of JSON editor modes for which all fields should be expanded automatically;
46
     * allowed modes 'tree', 'view', and 'form'
47
     * @see https://github.com/josdejong/jsoneditor/blob/master/docs/api.md#jsoneditorexpandall
48
     */
49
    public $expandAll = [];
50
51
    /**
52
     * @var null|boolean whether to use minimalist version of JSON editor;
53
     * note that "minimalist" is not the same as "minimized";
54
     * if property is not set then extension will try to determine automatically whether full version is needed,
55
     * if full version is not required then minimalist version will be used;
56
     * you can explicitly set this property to true or false if automatic detection does not fit for you application
57
     * @see https://github.com/josdejong/jsoneditor/blob/master/dist/which%20files%20do%20I%20need.md
58
     */
59
    public $minimalist;
60
61
    /**
62
     * @var string default JSON editor mode
63
     */
64
    private $mode = 'tree';
65
66
    /**
67
     * @var string[] available JSON editor modes
68
     */
69
    private $modes = [];
70
71
    /**
72
     * @inheritdoc
73
     */
74 6
    public function init()
75
    {
76 6
        parent::init();
77 6
        if (!isset($this->containerOptions['id'])) {
78 6
            $this->containerOptions['id'] = $this->options['id'] . '-json-editor';
79 6
        }
80 6
        if (!array_key_exists('style', $this->containerOptions)) {
81 6
            $this->containerOptions['style'] = 'height: 250px;';
82 6
        }
83 6
        if ($this->hasModel()) {
84 2
            $this->value = Html::getAttributeValue($this->model, $this->attribute);
1 ignored issue
show
Documentation Bug introduced by
It seems like \yii\helpers\Html::getAt...odel, $this->attribute) can also be of type array. However, the property $value is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
85 2
        }
86 6
        if (empty($this->value)) {
87 4
            $this->value = $this->defaultValue;
88 4
        }
89 6
        foreach (['mode', 'modes'] as $parameterName) {
90 6
            $this->$parameterName = ArrayHelper::getValue($this->clientOptions, $parameterName, $this->$parameterName);
91 6
        }
92
        // make sure that "mode" is specified, otherwise JavaScript error can occur in some situations
93 6
        $this->clientOptions['mode'] = $this->mode;
94 6
        if (!isset($this->minimalist)) {
95 6
            $this->minimalist = $this->mode != 'code' && !in_array('code', $this->modes);
96 6
        }
97 6
    }
98
99
    /**
100
     * @inheritdoc
101
     */
102 6
    public function run()
103
    {
104 6
        $this->registerClientScript();
105 6
        if ($this->hasModel()) {
106 2
            echo Html::activeHiddenInput($this->model, $this->attribute, $this->options);
107 2
        } else {
108 4
            echo Html::hiddenInput($this->name, $this->value, $this->options);
109
        }
110 6
        echo Html::tag('div', '', $this->containerOptions);
111 6
    }
112
113
    /**
114
     * Initializes client options.
115
     */
116 6
    protected function initClientOptions()
117
    {
118 6
        $options = $this->clientOptions;
119 6
        $jsExpressionOptions = ['ace', 'ajv', 'onChange', 'onEditable', 'onError', 'onModeChange', 'schema'];
120 6
        foreach ($options as $key => $value) {
121 6
            if (!$value instanceof JsExpression && in_array($key, $jsExpressionOptions)) {
122 1
                $options[$key] = new JsExpression($value);
123 1
            }
124 6
        }
125 6
        $this->clientOptions = $options;
126 6
    }
127
128
    /**
129
     * Registers the needed client script.
130
     */
131 6
    public function registerClientScript()
132
    {
133 6
        $this->initClientOptions();
134 6
        $view = $this->getView();
135
136 6
        if ($this->minimalist) {
137 5
            JsonEditorMinimalistAsset::register($view);
138 5
        } else {
139 3
            JsonEditorFullAsset::register($view);
140
        }
141
142 6
        $hiddenInputId = $this->options['id'];
143 6
        $editorName = Inflector::variablize($hiddenInputId) . 'JsonEditor_' . hash('crc32', $hiddenInputId);
144 6
        $this->options['data-json-editor-name'] = $editorName;
145
146 6
        $jsUpdateHiddenField = "jQuery('#$hiddenInputId').val($editorName.getText());";
147
148 6
        if (isset($this->clientOptions['onChange'])) {
149 1
            $userFunction = " var userFunction = {$this->clientOptions['onChange']}; userFunction.call(this);";
150 1
        } else {
151 5
            $userFunction = '';
152
        }
153 6
        $this->clientOptions['onChange'] = new JsExpression("function() {{$jsUpdateHiddenField}$userFunction}");
154
155 6
        if (!empty($this->collapseAll) || !empty($this->expandAll)) {
156 2
            if (isset($this->clientOptions['onModeChange'])) {
157 1
                $userFunction = " var userFunction = {$this->clientOptions['onModeChange']}; " .
158 1
                    "userFunction.call(this, newMode, oldMode);";
159 1
            } else {
160 1
                $userFunction = '';
161
            }
162 2
            $jsOnModeChange = "function(newMode, oldMode) {";
163 2
            foreach (['collapseAll', 'expandAll'] as $property) {
164 2
                if (!empty($this->$property)) {
165 2
                    $jsOnModeChange .= "if (" . Json::htmlEncode($this->$property) . ".indexOf(newMode) !== -1) " .
166 2
                        "{{$editorName}.$property();}";
167 2
                }
168 2
            }
169 2
            $jsOnModeChange .= "$userFunction}";
170 2
            $this->clientOptions['onModeChange'] = new JsExpression($jsOnModeChange);
171 2
        }
172
173 6
        $encodedValue = Json::htmlEncode(Json::decode($this->value, false));
174 6
        $jsCode = "$editorName = new JSONEditor(document.getElementById('{$this->containerOptions['id']}'), " .
175 6
            Json::htmlEncode($this->clientOptions) . ", $encodedValue);\n" .
176 6
            "jQuery('#$hiddenInputId').parents('form').submit(function() {{$jsUpdateHiddenField}});";
177 6
        if (in_array($this->mode, $this->collapseAll)) {
178 1
            $jsCode .= "\n$editorName.collapseAll();";
179 1
        }
180 6
        if (in_array($this->mode, $this->expandAll)) {
181 1
            $jsCode .= "\n$editorName.expandAll();";
182 1
        }
183 6
        $view->registerJs($jsCode);
184 6
    }
185
}
186