SuggestionsWidget   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 318
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 97.5%

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 6
dl 0
loc 318
ccs 39
cts 40
cp 0.975
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 6 1
A initInputOptions() 0 5 1
A run() 0 5 1
A renderWidget() 0 8 2
A registerAssets() 0 5 1
A registerPlugin() 0 7 2
B initOptions() 0 47 7
1
<?php
2
3
namespace corpsepk\DaData;
4
5
use yii\helpers\Html;
6
use yii\helpers\Json;
7
use yii\widgets\InputWidget;
8
use yii\base\InvalidConfigException;
9
10
/**
11
 * SuggestionsWidget widget is a Yii2 wrapper for the DaData Suggestions jQuery plugin.
12
 *
13
 * ```php
14
 * echo SuggestionsWidget::widget([
15
 *     'model' => $model,
16
 *     'attribute' => 'inn',
17
 *     'token' => 'your apiKey'
18
 * ]);
19
 * ```
20
 *
21
 * The following example will use the name property instead:
22
 *
23
 * ```php
24
 * echo SuggestionsWidget::widget([
25
 *     'name' => 'inn',
26
 *     'token' => 'your apiKey'
27
 * ]);
28
 * ```
29
 *
30
 * You can also use this widget in an [[yii\widgets\ActiveForm|ActiveForm]] using the [[yii\widgets\ActiveField::widget()|widget()]]
31
 * method, for example like this:
32
 *
33
 * ```php
34
 * <?= $form->field($model, 'inn')->widget(SuggestionsWidget::class, [
35
 *     'token' => 'your apiKey'
36
 * ]) ?>
37
 * ```
38
 *
39
 * Параметры jQuery плагина
40
 * @see https://confluence.hflabs.ru/pages/viewpage.action?pageId=207454318
41
 *
42
 * @author Alexsandr Khramov <[email protected]>
43
 * @see https://github.com/corpsepk/...
44
 */
45
class SuggestionsWidget extends InputWidget
46
{
47
    const TYPE_NAME = 'NAME';
48
    const TYPE_ADDRESS = 'ADDRESS';
49
    const TYPE_PARTY = 'PARTY';
50
    const TYPE_BANK = 'BANK';
51
    const TYPE_EMAIL = 'EMAIL';
52
53
    /**
54
     * @see https://confluence.hflabs.ru/pages/viewpage.action?pageId=207454320
55
     */
56
    const CALLBACK_BEFORE_RENDER = 'beforeRender';
57
    const CALLBACK_FORMAT_RESULT = 'formatResult';
58
    const CALLBACK_FORMAT_SELECTED = 'formatSelected';
59
    const CALLBACK_ON_VALIDATE_SELECTION = 'onInvalidateSelection';
60
    const CALLBACK_ON_SEARCH_START = 'onSearchStart';
61
    const CALLBACK_ON_SEARCH_COMPLETE = 'onSearchComplete';
62
    const CALLBACK_ON_SEARCH_ERROR = 'onSearchError';
63
    const CALLBACK_ON_SUGGESTION_FETCH = 'onSuggestionsFetch';
64
    const CALLBACK_ON_SELECT = 'onSelect';
65
    const CALLBACK_ON_SELECT_NOTHING = 'onSelectNothing';
66
67
    /**
68
     * @see https://confluence.hflabs.ru/pages/viewpage.action?pageId=466681916
69
     */
70
    const ADDON_SPINNER = 'spinner';
71
    const ADDON_CLEAR = 'clear';
72
    const ADDON_NONE = 'none';
73
74
    /**
75
     * Тип подсказок:
76
     * NAME — ФИО;
77
     * ADDRESS — адреса;
78
     * PARTY — организации и ИП;
79
     * EMAIL — адрес электронной почты;
80
     * BANK — банковские организации.
81
     * @var string
82
     */
83
    public $type;
84
85
    /**
86
     * Тип подсказок по умолчанию
87
     * @var string
88
     */
89
    public $defaultType = self::TYPE_NAME;
90
91
    /**
92
     * @var array
93
     */
94
    public $inputOptions = [];
95
96
    /**
97
     * API-ключ вашей учетной записи на DaData.ru.
98
     * Можно посмотреть в личном кабинете - https://dadata.ru/profile/#info
99
     * @var string
100
     */
101
    public $token;
102
103
    /**
104
     * Что показывать в правом углу текстового поля подсказок:
105
     * по умолчанию — индикатор загрузки в десктопной версии и крестик очистки в мобильной;
106
     * spinner — индикатор загрузки;
107
     * clear — крестик очистки;
108
     * none — ничего не показывать.
109
     * Обратите внимание, значение нужно передавать как строку (например, addon: "clear").
110
     * @var string
111
     */
112
    public $addon;
113
114
    /**
115
     * Всегда выбирать первую подсказку, если пользователь явно не выбрал другую.
116
     * default - false
117
     * @var bool
118
     */
119
    public $autoSelectFirst;
120
121
    /**
122
     * Максимальное количество подсказок в выпадающем списке. Не может быть больше 20.
123
     * default - 5
124
     * @var int
125
     */
126
    public $count;
127
128
    /**
129
     * Период ожидания перед отправкой запроса на сервер подсказок, в миллисекундах.
130
     * Позволяет не перегружать сервер запросами, если пользователь очень быстро печатает.
131
     * default - 100
132
     * @var int
133
     */
134
    public $deferRequestBy;
135
136
    /**
137
     * Если опция установлена в true,
138
     * выпадающий список отображается поверх всего документа, и ничем не обрезается.
139
     * default - false
140
     * @var bool
141
     */
142
    public $floating;
143
144
    /**
145
     * Объект с дополнительными HTTP-заголовками, которые необходимо передать на сервер.
146
     * @var string
147
     */
148
    public $headers;
149
150
    /**
151
     * Поясняющий текст, который показывается в выпадающем списке над подсказками.
152
     * @var string
153
     */
154
    public $hint;
155
156
    /**
157
     * Периодическая проверка, не стали ли невидимые поля видимыми (время в миллисекундах).
158
     * default - 100
159
     * @var int
160
     */
161
    public $initializeInterval;
162
163
    /**
164
     * Минимальная длина текста, после которой включаются подсказки.
165
     * @var int
166
     */
167
    public $minChars;
168
169
    /**
170
     * Максимальная ширина экрана, при которой будет применен вид,
171
     * адаптированный для мобильных устройств.
172
     * default - 980
173
     * @var int
174
     */
175
    public $mobileWidth;
176
177
    /**
178
     * Кэширование ответов сервера.
179
     * default - false
180
     * @var bool
181
     */
182
    public $noCache;
183
184
    /**
185
     * Поясняющий текст, который показывается,
186
     * если для введённого запроса ничего не найдено.
187
     * Текст зависит от типа подсказок.
188
     *
189
     * NAME: false
190
     * ADDRESS: 'Неизвестный адрес'
191
     * EMAIL: false
192
     * PARTY: 'Неизвестная организация'
193
     * BANK: 'Неизвестный банк'
194
     */
195
    public $noSuggestionsHint;
196
197
    /**
198
     * Прокрутка поля ввода к верхнему краю экрана при фокусе. Для мобильных устройств.
199
     * Если передать jQuery-объект с другим элементом, страница будет прокручиваться до этого элемента.
200
     * default - true
201
     * @var bool
202
     */
203
    public $scrollOnFocus;
204
205
    /**
206
     * URL сервиса standalone-подсказок.
207
     * @var
208
     */
209
    public $serviceUrl;
210
211
    /**
212
     * Не показывать подсказки до ввода символа "@" в подсказках по e-mail.
213
     * default - true
214
     * @var bool
215
     */
216
    public $suggest_local;
217
218
    /**
219
     * Таймаут для отправки ajax-запросов на сервер. Указывается в миллисекундах.
220
     * default - 3000
221
     * @var integer
222
     */
223
    public $timeout;
224
225
    /**
226
     * Автоматически подставлять подходящую подсказку из списка при потере фокуса.
227
     * default - true
228
     * @var bool
229
     */
230
    public $triggerSelectOnBlur;
231
232
    /**
233
     * Автоматически подставлять подходящую подсказку из списка при нажатии на Enter.
234
     * default - true
235
     * @var bool
236
     */
237
    public $triggerSelectOnEnter;
238
239
    /**
240
     * Автоматически подставлять подходящую подсказку из списка
241
     * при нажатии на пробел (по умолчанию отключено).
242
     * default - false
243
     * @var bool
244
     */
245
    public $triggerSelectOnSpace;
246
247
    /**
248
     * Ширина выпадающего списка в пикселях. 'auto' - по ширине текстбокса.
249
     * default - auto
250
     * @var string|int
251
     */
252
    public $width;
253
254
    /**
255
     * @inheritdoc
256
     */
257 9
    public function init()
258
    {
259 9
        parent::init();
260 9
        $this->initOptions();
261 6
        $this->initInputOptions();
262 6
    }
263
264
    /**
265
     * @throws InvalidConfigException
266
     */
267 9
    protected function initOptions()
268
    {
269 9
        if (!$this->type) {
270 9
            $this->type = $this->defaultType;
271
        }
272
273
        $attributes = [
274 9
            'addon',
275
            'autoSelectFirst',
276
            'count',
277
            'deferRequestBy',
278
            'floating',
279
            'headers',
280
            'hint',
281
            'initializeInterval',
282
            'minChars',
283
            'mobileWidth',
284
            'noCache',
285
            'scrollOnFocus',
286
            'serviceUrl',
287
            'suggest_local',
288
            'timeout',
289
            'token',
290
            'triggerSelectOnBlur',
291
            'triggerSelectOnEnter',
292
            'triggerSelectOnSpace',
293
            'type',
294
            'width',
295
        ];
296 9
        foreach ($attributes as $attribute) {
297 9
            if ($this->$attribute === null || isset($this->options[$attribute])) {
298 9
                continue;
299
            }
300
301 9
            $this->options[$attribute] = $this->$attribute;
302
        }
303
304
        // `type` required
305 9
        if (!isset($this->options['type'])) {
306
            throw new InvalidConfigException('`type` param required');
307
        }
308
309
        // `token` required
310 9
        if (!isset($this->options['token'])) {
311 3
            throw new InvalidConfigException('`token` param required');
312
        }
313 6
    }
314
315 6
    protected function initInputOptions()
316
    {
317 6
        $this->inputOptions['id'] = $this->options['id'];
318 6
        Html::addCssClass($this->inputOptions, 'form-control');
319 6
    }
320
321
    /**
322
     * Renders the widget.
323
     */
324 6
    public function run()
325
    {
326 6
        $this->registerAssets();
327 6
        echo $this->renderWidget();
328 6
    }
329
330
    /**
331
     * Renders the SuggestionsWidget widget.
332
     * @return string the rendering result.
333
     */
334 6
    protected function renderWidget()
335
    {
336 6
        if ($this->hasModel()) {
337 3
            return Html::activeTextInput($this->model, $this->attribute, $this->inputOptions);
338
        } else {
339 6
            return Html::textInput($this->name, $this->value, $this->inputOptions);
340
        }
341
    }
342
343
    /**
344
     * Registers the needed assets
345
     */
346 6
    protected function registerAssets()
347
    {
348 6
        SuggestionsWidgetAsset::register($this->getView());
349 6
        $this->registerPlugin();
350 6
    }
351
352
    /**
353
     * Registers plugin
354
     */
355 6
    protected function registerPlugin()
356
    {
357 6
        $id = $this->options['id'];
358 6
        $options = empty($this->options) ? '' : Json::htmlEncode($this->options);
359 6
        $js = "jQuery('#$id').suggestions($options);";
360 6
        $this->getView()->registerJs($js);
361
    }
362
}