Completed
Push — master ( 41bf1b...b49a3d )
by Klochok
04:06 queued 02:24
created

Combo   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 331
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 26.67%

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 9
dl 0
loc 331
ccs 24
cts 90
cp 0.2667
rs 10
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
B init() 0 21 7
A run() 0 6 1
A renderInput() 0 4 1
A registerClientConfig() 0 10 1
A registerClientScript() 0 8 1
A getReturn() 0 4 1
A getRename() 0 4 1
A getFilter() 0 4 1
A setFilter() 0 4 1
A setRename() 0 4 1
A setReturn() 0 4 1
A getPrimaryFilter() 0 4 2
A setPrimaryFilter() 0 4 1
B getPluginOptions() 0 33 2
A getFormIsBulk() 0 4 1
A setPluginOptions() 0 4 1
A getHasId() 0 4 2
A setHasId() 0 4 1
1
<?php
2
3
/*
4
 * Combo widget for Yii2
5
 *
6
 * @link      https://github.com/hiqdev/yii2-combo
7
 * @package   yii2-combo
8
 * @license   BSD-3-Clause
9
 * @copyright Copyright (c) 2015-2016, HiQDev (http://hiqdev.com/)
10
 */
11
12
namespace hiqdev\combo;
13
14
use Yii;
15
use yii\base\Model;
16
use yii\base\Widget;
17
use yii\helpers\ArrayHelper;
18
use yii\helpers\Html;
19
use yii\helpers\Json;
20
use yii\helpers\Url;
21
use yii\web\JsExpression;
22
use yii\web\View;
23
24
/**
25
 * Widget Combo.
26
 *
27
 * @property mixed $return see [[_return]]
28
 * @property mixed $rename see [[_rename]]
29
 * @property mixed $filter see [[_filter]]
30
 * @property mixed $pluginOptions see [[_pluginOptions]]
31
 * @property mixed $primaryFilter see [[_primaryFilter]]
32
 * @property mixed hasId
33
 */
34
class Combo extends Widget
35
{
36
    /**
37
     * @var Model
38
     */
39
    public $model;
40
41
    /**
42
     * @var string the attribute name
43
     */
44
    public $attribute;
45
46
    /**
47
     * @var array the url that will be passed to [[Url::to()]] method to create the request URL
48
     */
49
    public $url;
50
51
    /**
52
     * @var string the type of the field.
53
     * Usual should be module/comboName.
54
     * For example: client/client, hosting/account, domain/domain.
55
     * In case of the combo overriding with some specific filters,
56
     * the type should represent the filter.
57
     * For example: if the hosting/service combo is extended with filter
58
     * to show only DB services, the type should be hosting/service/db or hosting/dbService.
59
     * The decision of the style depends on overall code style and readability
60
     */
61
    public $type;
62
63
    /**
64
     * @var string the name of the representative field in the model.
65
     * Used by [[getPrimaryFilter]] to create the name of the filtering field
66
     * @see getPrimaryFilter()
67
     */
68
    public $name;
69
70
    /**
71
     * @var string md5 of the configuration.
72
     * Appears only after the combo registration in [[register]]
73
     * @see register()
74
     */
75
    public $configId;
76
77
    /**
78
     * @var array the HTML options for the input element
79
     */
80
    public $inputOptions = [];
81
82
    /**
83
     * @var string the outer element selector, that holds all of related Combos
84
     */
85
    public $formElementSelector = 'form';
86
87
    /**
88
     * @var string the language. Default is application language
89
     */
90
    public $language;
91
92
    /**
93
     * @var bool allow multiple selection
94
     */
95
    public $multiple;
96
97
    /**
98
     * @var mixed returning arguments
99
     * Example:
100
     *
101
     * ```
102
     *  ['id', 'password', 'another_column']
103
     * ```
104
     *
105
     * @see getReturn()
106
     * @see setReturn()
107
     */
108
    protected $_return;
109
110
    /**
111
     * @var array renamed arguments
112
     * Example:
113
     *
114
     * ```
115
     *  [
116
     *      'new_col_name' => 'old_col_name',
117
     *      'text' => 'login',
118
     *      'deep' => 'array.subarray.value' // can extract some value from an array
119
     *  ]
120
     * ```
121
     *
122
     * @see getName()
123
     * @see setName()
124
     */
125
    protected $_rename;
126
127
    /**
128
     * @var array the static filters
129
     * Example:
130
     *
131
     * ```
132
     * [
133
     *      'someStaticValue' => ['format' => 'the_value'],
134
     *      'type'            => ['format' => 'seller'],
135
     *      'is_active'       => [
136
     *          'field'  => 'server',
137
     *          'format' => new JsExpression('function (id, text, field) {
138
     *              if (field.isSet()) {
139
     *                  return 1;
140
     *              }
141
     *          }'),
142
     *      ]
143
     * ]
144
     * @see setFilter()
145
     * @see getFilter()
146
     */
147
    protected $_filter = [];
148
149
    /**
150
     * @var string the name of the primary filter. Default: [[name]]_like
151
     * @see getPrimaryFilter
152
     * @see setPrimaryFilter
153
     */
154
    protected $_primaryFilter;
155
156
    /**
157
     * @var boolean|string whether the combo has a primary key
158
     *   true (default) - the combo has an id in field id
159
     *            false - the combo does not have an id. The value is equal to the id
160
     *      some string - the name of the id field
161
     */
162
    public $_hasId;
163
164
    /**
165
     * Options that will be passed to the plugin.
166
     *
167
     * @var array
168
     * @see getPluginOptions()
169
     */
170
    public $_pluginOptions = [];
171
172
    /** {@inheritdoc} */
173 2
    public function init()
174
    {
175 2
        parent::init();
176
177
        // Set language
178 2
        if ($this->language === null && ($language = Yii::$app->language) !== 'en-US') {
179 2
            $this->language = substr($language, 0, 2);
180 2
        }
181 2
        if (!$this->_return) {
182 2
            $this->return = ['id'];
183 2
        }
184 2
        if (!$this->rename) {
185 2
            $this->rename = ['text' => $this->name];
186 2
        }
187 2
        if (!$this->inputOptions['id']) {
188
            $this->inputOptions['id'] = Html::getInputId($this->model, $this->attribute);
189
        }
190 2
        if (!$this->inputOptions['data-combo-field']) {
191 2
            $this->inputOptions['data-combo-field'] = $this->name;
192 2
        }
193 2
    }
194
195
    public function run()
196
    {
197
        $this->registerClientConfig();
198
        $this->registerClientScript();
199
        return $this->renderInput();
200
    }
201
202
    /**
203
     * Renders text input that will be used by the plugin.
204
     * Must apply [[inputOptions]] to the HTML element.
205
     *
206
     * @return string
207
     */
208
    protected function renderInput()
209
    {
210
        return Html::activeTextInput($this->model, $this->attribute, $this->inputOptions);
211
    }
212
213
    public function registerClientConfig()
214
    {
215
        $view = Yii::$app->getView();
216
        ComboAsset::register($view);
217
218
        $pluginOptions = Json::encode($this->pluginOptions);
219
        $this->configId = md5($this->type . $pluginOptions);
220
        $view->registerJs("$.fn.comboConfig().add('{$this->configId}', $pluginOptions);", View::POS_READY,
221
            'combo_' . $this->configId);
222
    }
223
224
    public function registerClientScript()
225
    {
226
        $selector = $this->inputOptions['id'];
227
        $js = "$('#$selector').closest('{$this->formElementSelector}').combo().register('#$selector', '$this->configId');";
228
229
        $view = Yii::$app->getView();
230
        $view->registerJs($js);
231
    }
232
233
    public function getReturn()
234
    {
235
        return $this->_return;
236
    }
237
238
    /**
239
     * @return mixed
240
     */
241 2
    public function getRename()
242
    {
243 2
        return $this->_rename;
244
    }
245
246
    /**
247
     * @return mixed
248
     */
249
    public function getFilter()
250
    {
251
        return $this->_filter;
252
    }
253
254
    /**
255
     * @param mixed $filter
256
     */
257
    public function setFilter($filter)
258
    {
259
        $this->_filter = $filter;
0 ignored issues
show
Documentation Bug introduced by
It seems like $filter of type * is incompatible with the declared type array of property $_filter.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
260
    }
261
262
    /**
263
     * @param mixed $rename
264
     */
265 2
    public function setRename($rename)
266
    {
267 2
        $this->_rename = $rename;
0 ignored issues
show
Documentation Bug introduced by
It seems like $rename of type * is incompatible with the declared type array of property $_rename.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
268 2
    }
269
270
    /**
271
     * @param mixed $return
272
     */
273 2
    public function setReturn($return)
274
    {
275 2
        $this->_return = $return;
276 2
    }
277
278
    /**
279
     * @return string
280
     * @see _primaryFilter
281
     */
282
    public function getPrimaryFilter()
283
    {
284
        return $this->_primaryFilter ?: $this->name . '_like';
285
    }
286
287
    /**
288
     * @param $primaryFilter
289
     * @see _primaryFilter
290
     */
291
    public function setPrimaryFilter($primaryFilter)
292
    {
293
        $this->_primaryFilter = $primaryFilter;
294
    }
295
296
    /**
297
     * Returns the config of the Combo, merges with the passed $config.
298
     *
299
     * @param array $options
300
     * @return array
301
     */
302
    public function getPluginOptions($options = [])
303
    {
304
        $defaultOptions = [
305
            'name' => $this->name,
306
            'type' => $this->type,
307
            'hasId' => $this->hasId,
308
            'select2Options' => [
309
                'width'       => '100%',
310
                'placeholder' => $this->model->getAttributeLabel($this->attribute),
311
                'minimumInputLength' => '0',
312
                'ajax'        => [
313
                    'url'    => Url::toRoute($this->url),
314
                    'type'   => 'post',
315
                    'return' => $this->return,
316
                    'rename' => $this->rename,
317
                    'filter' => $this->filter,
318
                    'data' => new JsExpression("
319
                        function (term) {
320
                            return $(this).data('field').createFilter({
321
                                '{$this->primaryFilter}': {format: term}
322
                            });
323
                        }
324
                    "),
325
                ],
326
            ],
327
        ];
328
329
        if ($this->multiple !== null) {
330
            $options['select2Options']['multiple'] = $this->multiple;
331
        }
332
333
        return ArrayHelper::merge($defaultOptions, $this->_pluginOptions, $options);
334
    }
335
336
    public function getFormIsBulk()
337
    {
338
        return preg_match("/^\[.*\].+$/", $this->attribute);
339
    }
340
341
    /**
342
     * @param array $pluginOptions
343
     */
344
    public function setPluginOptions($pluginOptions)
345
    {
346
        $this->_pluginOptions = $pluginOptions;
347
    }
348
349
    /**
350
     * @return bool|string
351
     */
352
    public function getHasId()
353
    {
354
        return empty($this->_hasId) ? (substr($this->attribute, -3) === '_id') : $this->_hasId;
355
    }
356
357
    /**
358
     * @param bool|string $hasId
359
     */
360
    public function setHasId($hasId)
361
    {
362
        $this->_hasId = $hasId;
363
    }
364
}
365