Completed
Push — master ( 36960d...148007 )
by Alexander
24:32 queued 21:36
created

framework/helpers/BaseHtml.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\helpers;
9
10
use Yii;
11
use yii\base\InvalidParamException;
12
use yii\db\ActiveRecordInterface;
13
use yii\validators\StringValidator;
14
use yii\web\Request;
15
use yii\base\Model;
16
17
/**
18
 * BaseHtml provides concrete implementation for [[Html]].
19
 *
20
 * Do not use BaseHtml. Use [[Html]] instead.
21
 *
22
 * @author Qiang Xue <[email protected]>
23
 * @since 2.0
24
 */
25
class BaseHtml
26
{
27
    /**
28
     * @var array list of void elements (element name => 1)
29
     * @see http://www.w3.org/TR/html-markup/syntax.html#void-element
30
     */
31
    public static $voidElements = [
32
        'area' => 1,
33
        'base' => 1,
34
        'br' => 1,
35
        'col' => 1,
36
        'command' => 1,
37
        'embed' => 1,
38
        'hr' => 1,
39
        'img' => 1,
40
        'input' => 1,
41
        'keygen' => 1,
42
        'link' => 1,
43
        'meta' => 1,
44
        'param' => 1,
45
        'source' => 1,
46
        'track' => 1,
47
        'wbr' => 1,
48
    ];
49
    /**
50
     * @var array the preferred order of attributes in a tag. This mainly affects the order of the attributes
51
     * that are rendered by [[renderTagAttributes()]].
52
     */
53
    public static $attributeOrder = [
54
        'type',
55
        'id',
56
        'class',
57
        'name',
58
        'value',
59
60
        'href',
61
        'src',
62
        'srcset',
63
        'action',
64
        'method',
65
66
        'selected',
67
        'checked',
68
        'readonly',
69
        'disabled',
70
        'multiple',
71
72
        'size',
73
        'maxlength',
74
        'width',
75
        'height',
76
        'rows',
77
        'cols',
78
79
        'alt',
80
        'title',
81
        'rel',
82
        'media',
83
    ];
84
    /**
85
     * @var array list of tag attributes that should be specially handled when their values are of array type.
86
     * In particular, if the value of the `data` attribute is `['name' => 'xyz', 'age' => 13]`, two attributes
87
     * will be generated instead of one: `data-name="xyz" data-age="13"`.
88
     * @since 2.0.3
89
     */
90
    public static $dataAttributes = ['data', 'data-ng', 'ng'];
91
92
93
    /**
94
     * Encodes special characters into HTML entities.
95
     * The [[\yii\base\Application::charset|application charset]] will be used for encoding.
96
     * @param string $content the content to be encoded
97
     * @param bool $doubleEncode whether to encode HTML entities in `$content`. If false,
98
     * HTML entities in `$content` will not be further encoded.
99
     * @return string the encoded content
100
     * @see decode()
101
     * @see http://www.php.net/manual/en/function.htmlspecialchars.php
102 182
     */
103
    public static function encode($content, $doubleEncode = true)
104 182
    {
105
        return htmlspecialchars($content, ENT_QUOTES | ENT_SUBSTITUTE, Yii::$app ? Yii::$app->charset : 'UTF-8', $doubleEncode);
106
    }
107
108
    /**
109
     * Decodes special HTML entities back to the corresponding characters.
110
     * This is the opposite of [[encode()]].
111
     * @param string $content the content to be decoded
112
     * @return string the decoded content
113
     * @see encode()
114
     * @see http://www.php.net/manual/en/function.htmlspecialchars-decode.php
115 1
     */
116
    public static function decode($content)
117 1
    {
118
        return htmlspecialchars_decode($content, ENT_QUOTES);
119
    }
120
121
    /**
122
     * Generates a complete HTML tag.
123
     * @param string|bool|null $name the tag name. If $name is `null` or `false`, the corresponding content will be rendered without any tag.
124
     * @param string $content the content to be enclosed between the start and end tags. It will not be HTML-encoded.
125
     * If this is coming from end users, you should consider [[encode()]] it to prevent XSS attacks.
126
     * @param array $options the HTML tag attributes (HTML options) in terms of name-value pairs.
127
     * These will be rendered as the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
128
     * If a value is null, the corresponding attribute will not be rendered.
129
     *
130
     * For example when using `['class' => 'my-class', 'target' => '_blank', 'value' => null]` it will result in the
131
     * html attributes rendered like this: `class="my-class" target="_blank"`.
132
     *
133
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
134
     *
135
     * @return string the generated HTML tag
136
     * @see beginTag()
137
     * @see endTag()
138 171
     */
139
    public static function tag($name, $content = '', $options = [])
140 171
    {
141 3
        if ($name === null || $name === false) {
142
            return $content;
143 170
        }
144 170
        $html = "<$name" . static::renderTagAttributes($options) . '>';
145
        return isset(static::$voidElements[strtolower($name)]) ? $html : "$html$content</$name>";
146
    }
147
148
    /**
149
     * Generates a start tag.
150
     * @param string|bool|null $name the tag name. If $name is `null` or `false`, the corresponding content will be rendered without any tag.
151
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
152
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
153
     * If a value is null, the corresponding attribute will not be rendered.
154
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
155
     * @return string the generated start tag
156
     * @see endTag()
157
     * @see tag()
158 35
     */
159
    public static function beginTag($name, $options = [])
160 35
    {
161 3
        if ($name === null || $name === false) {
162
            return '';
163 35
        }
164
        return "<$name" . static::renderTagAttributes($options) . '>';
165
    }
166
167
    /**
168
     * Generates an end tag.
169
     * @param string|bool|null $name the tag name. If $name is `null` or `false`, the corresponding content will be rendered without any tag.
170
     * @return string the generated end tag
171
     * @see beginTag()
172
     * @see tag()
173 12
     */
174
    public static function endTag($name)
175 12
    {
176 3
        if ($name === null || $name === false) {
177
            return '';
178 11
        }
179
        return "</$name>";
180
    }
181
182
    /**
183
     * Generates a style tag.
184
     * @param string $content the style content
185
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
186
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
187
     * If a value is null, the corresponding attribute will not be rendered.
188
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
189
     * @return string the generated style tag
190 1
     */
191
    public static function style($content, $options = [])
192 1
    {
193
        return static::tag('style', $content, $options);
194
    }
195
196
    /**
197
     * Generates a script tag.
198
     * @param string $content the script content
199
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
200
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
201
     * If a value is null, the corresponding attribute will not be rendered.
202
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
203
     * @return string the generated script tag
204 1
     */
205
    public static function script($content, $options = [])
206 1
    {
207
        return static::tag('script', $content, $options);
208
    }
209
210
    /**
211
     * Generates a link tag that refers to an external CSS file.
212
     * @param array|string $url the URL of the external CSS file. This parameter will be processed by [[Url::to()]].
213
     * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
214
     *
215
     * - condition: specifies the conditional comments for IE, e.g., `lt IE 9`. When this is specified,
216
     *   the generated `link` tag will be enclosed within the conditional comments. This is mainly useful
217
     *   for supporting old versions of IE browsers.
218
     * - noscript: if set to true, `link` tag will be wrapped into `<noscript>` tags.
219
     *
220
     * The rest of the options will be rendered as the attributes of the resulting link tag. The values will
221
     * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
222
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
223
     * @return string the generated link tag
224
     * @see Url::to()
225 20
     */
226
    public static function cssFile($url, $options = [])
227 20
    {
228 20
        if (!isset($options['rel'])) {
229 20
            $options['rel'] = 'stylesheet';
230 20
        }
231
        $options['href'] = Url::to($url);
232 20
233 1
        if (isset($options['condition'])) {
234 1
            $condition = $options['condition'];
235 1
            unset($options['condition']);
236 20
            return self::wrapIntoCondition(static::tag('link', '', $options), $condition);
237
        } elseif (isset($options['noscript']) && $options['noscript'] === true) {
238
            unset($options['noscript']);
239
            return '<noscript>' . static::tag('link', '', $options) . '</noscript>';
240 20
        } else {
241
            return static::tag('link', '', $options);
242
        }
243
    }
244
245
    /**
246
     * Generates a script tag that refers to an external JavaScript file.
247
     * @param string $url the URL of the external JavaScript file. This parameter will be processed by [[Url::to()]].
248
     * @param array $options the tag options in terms of name-value pairs. The following option is specially handled:
249
     *
250
     * - condition: specifies the conditional comments for IE, e.g., `lt IE 9`. When this is specified,
251
     *   the generated `script` tag will be enclosed within the conditional comments. This is mainly useful
252
     *   for supporting old versions of IE browsers.
253
     *
254
     * The rest of the options will be rendered as the attributes of the resulting script tag. The values will
255
     * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
256
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
257
     * @return string the generated script tag
258
     * @see Url::to()
259 22
     */
260
    public static function jsFile($url, $options = [])
261 22
    {
262 22
        $options['src'] = Url::to($url);
263 1
        if (isset($options['condition'])) {
264 1
            $condition = $options['condition'];
265 1
            unset($options['condition']);
266
            return self::wrapIntoCondition(static::tag('script', '', $options), $condition);
267 22
        } else {
268
            return static::tag('script', '', $options);
269
        }
270
    }
271
272
    /**
273
     * Wraps given content into conditional comments for IE, e.g., `lt IE 9`.
274
     * @param string $content raw HTML content.
275
     * @param string $condition condition string.
276
     * @return string generated HTML.
277 2
     */
278
    private static function wrapIntoCondition($content, $condition)
279 2
    {
280 2
        if (strpos($condition, '!IE') !== false) {
281
            return "<!--[if $condition]><!-->\n" . $content . "\n<!--<![endif]-->";
282 2
        }
283
        return "<!--[if $condition]>\n" . $content . "\n<![endif]-->";
284
    }
285
286
    /**
287
     * Generates the meta tags containing CSRF token information.
288
     * @return string the generated meta tags
289
     * @see Request::enableCsrfValidation
290
     */
291
    public static function csrfMetaTags()
292
    {
293
        $request = Yii::$app->getRequest();
294
        if ($request instanceof Request && $request->enableCsrfValidation) {
295
            return static::tag('meta', '', ['name' => 'csrf-param', 'content' => $request->csrfParam]) . "\n    "
296
                . static::tag('meta', '', ['name' => 'csrf-token', 'content' => $request->getCsrfToken()]) . "\n";
297
        } else {
298
            return '';
299
        }
300
    }
301
302
    /**
303
     * Generates a form start tag.
304
     * @param array|string $action the form action URL. This parameter will be processed by [[Url::to()]].
305
     * @param string $method the form submission method, such as "post", "get", "put", "delete" (case-insensitive).
306
     * Since most browsers only support "post" and "get", if other methods are given, they will
307
     * be simulated using "post", and a hidden input will be added which contains the actual method type.
308
     * See [[\yii\web\Request::methodParam]] for more details.
309
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
310
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
311
     * If a value is null, the corresponding attribute will not be rendered.
312
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
313
     *
314
     * Special options:
315
     *
316
     *  - `csrf`: whether to generate the CSRF hidden input. Defaults to true.
317
     *
318
     * @return string the generated form start tag.
319
     * @see endForm()
320 33
     */
321
    public static function beginForm($action = '', $method = 'post', $options = [])
322 33
    {
323
        $action = Url::to($action);
324 33
325
        $hiddenInputs = [];
326 33
327 33
        $request = Yii::$app->getRequest();
328 30
        if ($request instanceof Request) {
329
            if (strcasecmp($method, 'get') && strcasecmp($method, 'post')) {
330
                // simulate PUT, DELETE, etc. via POST
331
                $hiddenInputs[] = static::hiddenInput($request->methodParam, $method);
332
                $method = 'post';
333 30
            }
334
            $csrf = ArrayHelper::remove($options, 'csrf', true);
335 30
336 29
            if ($csrf && $request->enableCsrfValidation && strcasecmp($method, 'post') === 0) {
337 29
                $hiddenInputs[] = static::hiddenInput($request->csrfParam, $request->getCsrfToken());
338 30
            }
339
        }
340 33
341
        if (!strcasecmp($method, 'get') && ($pos = strpos($action, '?')) !== false) {
342
            // query parameters in the action are ignored for GET method
343 1
            // we use hidden fields to add them back
344 1
            foreach (explode('&', substr($action, $pos + 1)) as $pair) {
345 1
                if (($pos1 = strpos($pair, '=')) !== false) {
346 1
                    $hiddenInputs[] = static::hiddenInput(
347 1
                        urldecode(substr($pair, 0, $pos1)),
348 1
                        urldecode(substr($pair, $pos1 + 1))
349 1
                    );
350
                } else {
351
                    $hiddenInputs[] = static::hiddenInput(urldecode($pair), '');
352 1
                }
353 1
            }
354 1
            $action = substr($action, 0, $pos);
355
        }
356 33
357 33
        $options['action'] = $action;
358 33
        $options['method'] = $method;
359 33
        $form = static::beginTag('form', $options);
360 30
        if (!empty($hiddenInputs)) {
361 30
            $form .= "\n" . implode("\n", $hiddenInputs);
362
        }
363 33
364
        return $form;
365
    }
366
367
    /**
368
     * Generates a form end tag.
369
     * @return string the generated tag
370
     * @see beginForm()
371 32
     */
372
    public static function endForm()
373 32
    {
374
        return '</form>';
375
    }
376
377
    /**
378
     * Generates a hyperlink tag.
379
     * @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code
380
     * such as an image tag. If this is coming from end users, you should consider [[encode()]]
381
     * it to prevent XSS attacks.
382
     * @param array|string|null $url the URL for the hyperlink tag. This parameter will be processed by [[Url::to()]]
383
     * and will be used for the "href" attribute of the tag. If this parameter is null, the "href" attribute
384
     * will not be generated.
385
     *
386
     * If you want to use an absolute url you can call [[Url::to()]] yourself, before passing the URL to this method,
387
     * like this:
388
     *
389
     * ```php
390
     * Html::a('link text', Url::to($url, true))
391
     * ```
392
     *
393
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
394
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
395
     * If a value is null, the corresponding attribute will not be rendered.
396
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
397
     * @return string the generated hyperlink
398
     * @see \yii\helpers\Url::to()
399 13
     */
400
    public static function a($text, $url = null, $options = [])
401 13
    {
402 13
        if ($url !== null) {
403 13
            $options['href'] = Url::to($url);
404 13
        }
405
        return static::tag('a', $text, $options);
406
    }
407
408
    /**
409
     * Generates a mailto hyperlink.
410
     * @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code
411
     * such as an image tag. If this is coming from end users, you should consider [[encode()]]
412
     * it to prevent XSS attacks.
413
     * @param string $email email address. If this is null, the first parameter (link body) will be treated
414
     * as the email address and used.
415
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
416
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
417
     * If a value is null, the corresponding attribute will not be rendered.
418
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
419
     * @return string the generated mailto link
420 2
     */
421
    public static function mailto($text, $email = null, $options = [])
422 2
    {
423 2
        $options['href'] = 'mailto:' . ($email === null ? $text : $email);
424
        return static::tag('a', $text, $options);
425
    }
426
427
    /**
428
     * Generates an image tag.
429
     * @param array|string $src the image URL. This parameter will be processed by [[Url::to()]].
430
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
431
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
432
     * If a value is null, the corresponding attribute will not be rendered.
433
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
434
     * @since 2.0.12 It is possible to pass the "srcset" option as an array which keys are
435
     * descriptors and values are URLs. All URLs will be processed by [[Url::to()]].
436
     * @return string the generated image tag
437 10
     */
438
    public static function img($src, $options = [])
439 10
    {
440
        $options['src'] = Url::to($src);
441 10
442 5
        if (isset($options['srcset']) && is_array($options['srcset'])) {
443 5
            $srcset = [];
444 4
            foreach ($options['srcset'] as $descriptor => $url) {
445 5
                $srcset[] = Url::to($url) . ' ' . $descriptor;
446 5
            }
447 5
            $options['srcset'] = implode(',', $srcset);
448
        }
449 10
450 9
        if (!isset($options['alt'])) {
451 9
            $options['alt'] = '';
452 10
        }
453
        return static::tag('img', '', $options);
454
    }
455
456
    /**
457
     * Generates a label tag.
458
     * @param string $content label text. It will NOT be HTML-encoded. Therefore you can pass in HTML code
459
     * such as an image tag. If this is is coming from end users, you should [[encode()]]
460
     * it to prevent XSS attacks.
461
     * @param string $for the ID of the HTML element that this label is associated with.
462
     * If this is null, the "for" attribute will not be generated.
463
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
464
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
465
     * If a value is null, the corresponding attribute will not be rendered.
466
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
467
     * @return string the generated label tag
468 20
     */
469
    public static function label($content, $for = null, $options = [])
470 20
    {
471 20
        $options['for'] = $for;
472
        return static::tag('label', $content, $options);
473
    }
474
475
    /**
476
     * Generates a button tag.
477
     * @param string $content the content enclosed within the button tag. It will NOT be HTML-encoded.
478
     * Therefore you can pass in HTML code such as an image tag. If this is is coming from end users,
479
     * you should consider [[encode()]] it to prevent XSS attacks.
480
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
481
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
482
     * If a value is null, the corresponding attribute will not be rendered.
483
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
484
     * @return string the generated button tag
485 3
     */
486
    public static function button($content = 'Button', $options = [])
487 3
    {
488 1
        if (!isset($options['type'])) {
489 1
            $options['type'] = 'button';
490 3
        }
491
        return static::tag('button', $content, $options);
492
    }
493
494
    /**
495
     * Generates a submit button tag.
496
     *
497
     * Be careful when naming form elements such as submit buttons. According to the [jQuery documentation](https://api.jquery.com/submit/) there
498
     * are some reserved names that can cause conflicts, e.g. `submit`, `length`, or `method`.
499
     *
500
     * @param string $content the content enclosed within the button tag. It will NOT be HTML-encoded.
501
     * Therefore you can pass in HTML code such as an image tag. If this is is coming from end users,
502
     * you should consider [[encode()]] it to prevent XSS attacks.
503
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
504
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
505
     * If a value is null, the corresponding attribute will not be rendered.
506
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
507
     * @return string the generated submit button tag
508 1
     */
509
    public static function submitButton($content = 'Submit', $options = [])
510 1
    {
511 1
        $options['type'] = 'submit';
512
        return static::button($content, $options);
513
    }
514
515
    /**
516
     * Generates a reset button tag.
517
     * @param string $content the content enclosed within the button tag. It will NOT be HTML-encoded.
518
     * Therefore you can pass in HTML code such as an image tag. If this is is coming from end users,
519
     * you should consider [[encode()]] it to prevent XSS attacks.
520
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
521
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
522
     * If a value is null, the corresponding attribute will not be rendered.
523
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
524
     * @return string the generated reset button tag
525 1
     */
526
    public static function resetButton($content = 'Reset', $options = [])
527 1
    {
528 1
        $options['type'] = 'reset';
529
        return static::button($content, $options);
530
    }
531
532
    /**
533
     * Generates an input type of the given type.
534
     * @param string $type the type attribute.
535
     * @param string $name the name attribute. If it is null, the name attribute will not be generated.
536
     * @param string $value the value attribute. If it is null, the value attribute will not be generated.
537
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
538
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
539
     * If a value is null, the corresponding attribute will not be rendered.
540
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
541
     * @return string the generated input tag
542 63
     */
543
    public static function input($type, $name = null, $value = null, $options = [])
544 63
    {
545 63
        if (!isset($options['type'])) {
546 63
            $options['type'] = $type;
547 63
        }
548 63
        $options['name'] = $name;
549 63
        $options['value'] = $value === null ? null : (string) $value;
550
        return static::tag('input', '', $options);
551
    }
552
553
    /**
554
     * Generates an input button.
555
     * @param string $label the value attribute. If it is null, the value attribute will not be generated.
556
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
557
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
558
     * If a value is null, the corresponding attribute will not be rendered.
559
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
560
     * @return string the generated button tag
561 1
     */
562
    public static function buttonInput($label = 'Button', $options = [])
563 1
    {
564 1
        $options['type'] = 'button';
565 1
        $options['value'] = $label;
566
        return static::tag('input', '', $options);
567
    }
568
569
    /**
570
     * Generates a submit input button.
571
     *
572
     * Be careful when naming form elements such as submit buttons. According to the [jQuery documentation](https://api.jquery.com/submit/) there
573
     * are some reserved names that can cause conflicts, e.g. `submit`, `length`, or `method`.
574
     *
575
     * @param string $label the value attribute. If it is null, the value attribute will not be generated.
576
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
577
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
578
     * If a value is null, the corresponding attribute will not be rendered.
579
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
580
     * @return string the generated button tag
581 1
     */
582
    public static function submitInput($label = 'Submit', $options = [])
583 1
    {
584 1
        $options['type'] = 'submit';
585 1
        $options['value'] = $label;
586
        return static::tag('input', '', $options);
587
    }
588
589
    /**
590
     * Generates a reset input button.
591
     * @param string $label the value attribute. If it is null, the value attribute will not be generated.
592
     * @param array $options the attributes of the button tag. The values will be HTML-encoded using [[encode()]].
593
     * Attributes whose value is null will be ignored and not put in the tag returned.
594
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
595
     * @return string the generated button tag
596 1
     */
597
    public static function resetInput($label = 'Reset', $options = [])
598 1
    {
599 1
        $options['type'] = 'reset';
600 1
        $options['value'] = $label;
601
        return static::tag('input', '', $options);
602
    }
603
604
    /**
605
     * Generates a text input field.
606
     * @param string $name the name attribute.
607
     * @param string $value the value attribute. If it is null, the value attribute will not be generated.
608
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
609
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
610
     * If a value is null, the corresponding attribute will not be rendered.
611
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
612
     * @return string the generated text input tag
613 1
     */
614
    public static function textInput($name, $value = null, $options = [])
615 1
    {
616
        return static::input('text', $name, $value, $options);
617
    }
618
619
    /**
620
     * Generates a hidden input field.
621
     * @param string $name the name attribute.
622
     * @param string $value the value attribute. If it is null, the value attribute will not be generated.
623
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
624
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
625
     * If a value is null, the corresponding attribute will not be rendered.
626
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
627
     * @return string the generated hidden input tag
628 41
     */
629
    public static function hiddenInput($name, $value = null, $options = [])
630 41
    {
631
        return static::input('hidden', $name, $value, $options);
632
    }
633
634
    /**
635
     * Generates a password input field.
636
     * @param string $name the name attribute.
637
     * @param string $value the value attribute. If it is null, the value attribute will not be generated.
638
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
639
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
640
     * If a value is null, the corresponding attribute will not be rendered.
641
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
642
     * @return string the generated password input tag
643 1
     */
644
    public static function passwordInput($name, $value = null, $options = [])
645 1
    {
646
        return static::input('password', $name, $value, $options);
647
    }
648
649
    /**
650
     * Generates a file input field.
651
     * To use a file input field, you should set the enclosing form's "enctype" attribute to
652
     * be "multipart/form-data". After the form is submitted, the uploaded file information
653
     * can be obtained via $_FILES[$name] (see PHP documentation).
654
     * @param string $name the name attribute.
655
     * @param string $value the value attribute. If it is null, the value attribute will not be generated.
656
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
657
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
658
     * If a value is null, the corresponding attribute will not be rendered.
659
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
660
     * @return string the generated file input tag
661 1
     */
662
    public static function fileInput($name, $value = null, $options = [])
663 1
    {
664
        return static::input('file', $name, $value, $options);
665
    }
666
667
    /**
668
     * Generates a text area input.
669
     * @param string $name the input name
670
     * @param string $value the input value. Note that it will be encoded using [[encode()]].
671
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
672
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
673
     * If a value is null, the corresponding attribute will not be rendered.
674
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
675
     * The following special options are recognized:
676
     *
677
     * - `doubleEncode`: whether to double encode HTML entities in `$value`. If `false`, HTML entities in `$value` will not
678
     *   be further encoded. This option is available since version 2.0.11.
679
     *
680
     * @return string the generated text area tag
681 8
     */
682
    public static function textarea($name, $value = '', $options = [])
683 8
    {
684 8
        $options['name'] = $name;
685 8
        $doubleEncode = ArrayHelper::remove($options, 'doubleEncode', true);
686
        return static::tag('textarea', static::encode($value, $doubleEncode), $options);
687
    }
688
689
    /**
690
     * Generates a radio button input.
691
     * @param string $name the name attribute.
692
     * @param bool $checked whether the radio button should be checked.
693
     * @param array $options the tag options in terms of name-value pairs.
694
     * See [[booleanInput()]] for details about accepted attributes.
695
     *
696
     * @return string the generated radio button tag
697 9
     */
698
    public static function radio($name, $checked = false, $options = [])
699 9
    {
700
        return static::booleanInput('radio', $name, $checked, $options);
701
    }
702
703
    /**
704
     * Generates a checkbox input.
705
     * @param string $name the name attribute.
706
     * @param bool $checked whether the checkbox should be checked.
707
     * @param array $options the tag options in terms of name-value pairs.
708
     * See [[booleanInput()]] for details about accepted attributes.
709
     *
710
     * @return string the generated checkbox tag
711 8
     */
712
    public static function checkbox($name, $checked = false, $options = [])
713 8
    {
714
        return static::booleanInput('checkbox', $name, $checked, $options);
715
    }
716
717
    /**
718
     * Generates a boolean input.
719
     * @param string $type the input type. This can be either `radio` or `checkbox`.
720
     * @param string $name the name attribute.
721
     * @param bool $checked whether the checkbox should be checked.
722
     * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
723
     *
724
     * - uncheck: string, the value associated with the uncheck state of the checkbox. When this attribute
725
     *   is present, a hidden input will be generated so that if the checkbox is not checked and is submitted,
726
     *   the value of this attribute will still be submitted to the server via the hidden input.
727
     * - label: string, a label displayed next to the checkbox.  It will NOT be HTML-encoded. Therefore you can pass
728
     *   in HTML code such as an image tag. If this is is coming from end users, you should [[encode()]] it to prevent XSS attacks.
729
     *   When this option is specified, the checkbox will be enclosed by a label tag.
730
     * - labelOptions: array, the HTML attributes for the label tag. Do not set this option unless you set the "label" option.
731
     *
732
     * The rest of the options will be rendered as the attributes of the resulting checkbox tag. The values will
733
     * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
734
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
735
     *
736
     * @return string the generated checkbox tag
737
     * @since 2.0.9
738 17
     */
739
    protected static function booleanInput($type, $name, $checked = false, $options = [])
740 17
    {
741 17
        $options['checked'] = (bool) $checked;
742 17
        $value = array_key_exists('value', $options) ? $options['value'] : '1';
743
        if (isset($options['uncheck'])) {
744 6
            // add a hidden field so that if the checkbox is not selected, it still submits a value
745 6
            $hidden = static::hiddenInput($name, $options['uncheck']);
0 ignored issues
show
$options['uncheck'] is of type boolean, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
746 6
            unset($options['uncheck']);
747 13
        } else {
748
            $hidden = '';
749 17
        }
750 8
        if (isset($options['label'])) {
751 8
            $label = $options['label'];
752 8
            $labelOptions = isset($options['labelOptions']) ? $options['labelOptions'] : [];
753 8
            unset($options['label'], $options['labelOptions']);
754 8
            $content = static::label(static::input($type, $name, $value, $options) . ' ' . $label, null, $labelOptions);
755
            return $hidden . $content;
756 13
        } else {
757
            return $hidden . static::input($type, $name, $value, $options);
758
        }
759
    }
760
761
    /**
762
     * Generates a drop-down list.
763
     * @param string $name the input name
764
     * @param string|array|null $selection the selected value(s). String for single or array for multiple selection(s).
765
     * @param array $items the option data items. The array keys are option values, and the array values
766
     * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too).
767
     * For each sub-array, an option group will be generated whose label is the key associated with the sub-array.
768
     * If you have a list of data models, you may convert them into the format described above using
769
     * [[\yii\helpers\ArrayHelper::map()]].
770
     *
771
     * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
772
     * the labels will also be HTML-encoded.
773
     * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
774
     *
775
     * - prompt: string, a prompt text to be displayed as the first option. Since version 2.0.11 you can use an array
776
     *   to override the value and to set other tag attributes:
777
     *
778
     *   ```php
779
     *   ['text' => 'Please select', 'options' => ['value' => 'none', 'class' => 'prompt', 'label' => 'Select']],
780
     *   ```
781
     *
782
     * - options: array, the attributes for the select option tags. The array keys must be valid option values,
783
     *   and the array values are the extra attributes for the corresponding option tags. For example,
784
     *
785
     *   ```php
786
     *   [
787
     *       'value1' => ['disabled' => true],
788
     *       'value2' => ['label' => 'value 2'],
789
     *   ];
790
     *   ```
791
     *
792
     * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options',
793
     *   except that the array keys represent the optgroup labels specified in $items.
794
     * - encodeSpaces: bool, whether to encode spaces in option prompt and option value with `&nbsp;` character.
795
     *   Defaults to false.
796
     * - encode: bool, whether to encode option prompt and option value characters.
797
     *   Defaults to `true`. This option is available since 2.0.3.
798
     *
799
     * The rest of the options will be rendered as the attributes of the resulting tag. The values will
800
     * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
801
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
802
     *
803
     * @return string the generated drop-down list tag
804 2
     */
805
    public static function dropDownList($name, $selection = null, $items = [], $options = [])
806 2
    {
807
        if (!empty($options['multiple'])) {
808
            return static::listBox($name, $selection, $items, $options);
809 2
        }
810 2
        $options['name'] = $name;
811 2
        unset($options['unselect']);
812 2
        $selectOptions = static::renderSelectOptions($selection, $items, $options);
813
        return static::tag('select', "\n" . $selectOptions . "\n", $options);
814
    }
815
816
    /**
817
     * Generates a list box.
818
     * @param string $name the input name
819
     * @param string|array|null $selection the selected value(s). String for single or array for multiple selection(s).
820
     * @param array $items the option data items. The array keys are option values, and the array values
821
     * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too).
822
     * For each sub-array, an option group will be generated whose label is the key associated with the sub-array.
823
     * If you have a list of data models, you may convert them into the format described above using
824
     * [[\yii\helpers\ArrayHelper::map()]].
825
     *
826
     * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
827
     * the labels will also be HTML-encoded.
828
     * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
829
     *
830
     * - prompt: string, a prompt text to be displayed as the first option. Since version 2.0.11 you can use an array
831
     *   to override the value and to set other tag attributes:
832
     *
833
     *   ```php
834
     *   ['text' => 'Please select', 'options' => ['value' => 'none', 'class' => 'prompt', 'label' => 'Select']],
835
     *   ```
836
     *
837
     * - options: array, the attributes for the select option tags. The array keys must be valid option values,
838
     *   and the array values are the extra attributes for the corresponding option tags. For example,
839
     *
840
     *   ```php
841
     *   [
842
     *       'value1' => ['disabled' => true],
843
     *       'value2' => ['label' => 'value 2'],
844
     *   ];
845
     *   ```
846
     *
847
     * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options',
848
     *   except that the array keys represent the optgroup labels specified in $items.
849
     * - unselect: string, the value that will be submitted when no option is selected.
850
     *   When this attribute is set, a hidden field will be generated so that if no option is selected in multiple
851
     *   mode, we can still obtain the posted unselect value.
852
     * - encodeSpaces: bool, whether to encode spaces in option prompt and option value with `&nbsp;` character.
853
     *   Defaults to false.
854
     * - encode: bool, whether to encode option prompt and option value characters.
855
     *   Defaults to `true`. This option is available since 2.0.3.
856
     *
857
     * The rest of the options will be rendered as the attributes of the resulting tag. The values will
858
     * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
859
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
860
     *
861
     * @return string the generated list box tag
862 3
     */
863
    public static function listBox($name, $selection = null, $items = [], $options = [])
864 3
    {
865 3
        if (!array_key_exists('size', $options)) {
866 3
            $options['size'] = 4;
867 3
        }
868 2
        if (!empty($options['multiple']) && !empty($name) && substr_compare($name, '[]', -2, 2)) {
869 2
            $name .= '[]';
870 3
        }
871 3
        $options['name'] = $name;
872
        if (isset($options['unselect'])) {
873 3
            // add a hidden field so that if the list box has no option being selected, it still submits a value
874 1
            if (!empty($name) && substr_compare($name, '[]', -2, 2) === 0) {
875 1
                $name = substr($name, 0, -2);
876 3
            }
877 3
            $hidden = static::hiddenInput($name, $options['unselect']);
878 3
            unset($options['unselect']);
879 1
        } else {
880
            $hidden = '';
881 3
        }
882 3
        $selectOptions = static::renderSelectOptions($selection, $items, $options);
883
        return $hidden . static::tag('select', "\n" . $selectOptions . "\n", $options);
884
    }
885
886
    /**
887
     * Generates a list of checkboxes.
888
     * A checkbox list allows multiple selection, like [[listBox()]].
889
     * As a result, the corresponding submitted value is an array.
890
     * @param string $name the name attribute of each checkbox.
891
     * @param string|array|null $selection the selected value(s). String for single or array for multiple selection(s).
892
     * @param array $items the data item used to generate the checkboxes.
893
     * The array keys are the checkbox values, while the array values are the corresponding labels.
894
     * @param array $options options (name => config) for the checkbox list container tag.
895
     * The following options are specially handled:
896
     *
897
     * - tag: string|false, the tag name of the container element. False to render checkbox without container.
898
     *   See also [[tag()]].
899
     * - unselect: string, the value that should be submitted when none of the checkboxes is selected.
900
     *   By setting this option, a hidden input will be generated.
901
     * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true.
902
     *   This option is ignored if `item` option is set.
903
     * - separator: string, the HTML code that separates items.
904
     * - itemOptions: array, the options for generating the checkbox tag using [[checkbox()]].
905
     * - item: callable, a callback that can be used to customize the generation of the HTML code
906
     *   corresponding to a single item in $items. The signature of this callback must be:
907
     *
908
     *   ```php
909
     *   function ($index, $label, $name, $checked, $value)
910
     *   ```
911
     *
912
     *   where $index is the zero-based index of the checkbox in the whole list; $label
913
     *   is the label for the checkbox; and $name, $value and $checked represent the name,
914
     *   value and the checked status of the checkbox input, respectively.
915
     *
916
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
917
     *
918
     * @return string the generated checkbox list
919 1
     */
920
    public static function checkboxList($name, $selection = null, $items = [], $options = [])
921 1
    {
922 1
        if (substr($name, -2) !== '[]') {
923 1
            $name .= '[]';
924
        }
925 1
926 1
        $formatter = ArrayHelper::remove($options, 'item');
927 1
        $itemOptions = ArrayHelper::remove($options, 'itemOptions', []);
928 1
        $encode = ArrayHelper::remove($options, 'encode', true);
929 1
        $separator = ArrayHelper::remove($options, 'separator', "\n");
930
        $tag = ArrayHelper::remove($options, 'tag', 'div');
931 1
932 1
        $lines = [];
933 1
        $index = 0;
934 1
        foreach ($items as $value => $label) {
935 1
            $checked = $selection !== null &&
936 1
                (!ArrayHelper::isTraversable($selection) && !strcmp($value, $selection)
937 1
                    || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn($value, $selection));
938 1
            if ($formatter !== null) {
939 1
                $lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value);
940 1
            } else {
941 1
                $lines[] = static::checkbox($name, $checked, array_merge($itemOptions, [
942 1
                    'value' => $value,
943 1
                    'label' => $encode ? static::encode($label) : $label,
944
                ]));
945 1
            }
946 1
            $index++;
947
        }
948 1
949
        if (isset($options['unselect'])) {
950 1
            // add a hidden field so that if the list box has no option being selected, it still submits a value
951 1
            $name2 = substr($name, -2) === '[]' ? substr($name, 0, -2) : $name;
952 1
            $hidden = static::hiddenInput($name2, $options['unselect']);
953 1
            unset($options['unselect']);
954 1
        } else {
955
            $hidden = '';
956
        }
957 1
958
        $visibleContent = implode($separator, $lines);
959 1
960 1
        if ($tag === false) {
961
            return $hidden . $visibleContent;
962
        }
963 1
964
        return $hidden . static::tag($tag, $visibleContent, $options);
965
    }
966
967
    /**
968
     * Generates a list of radio buttons.
969
     * A radio button list is like a checkbox list, except that it only allows single selection.
970
     * @param string $name the name attribute of each radio button.
971
     * @param string|array|null $selection the selected value(s). String for single or array for multiple selection(s).
972
     * @param array $items the data item used to generate the radio buttons.
973
     * The array keys are the radio button values, while the array values are the corresponding labels.
974
     * @param array $options options (name => config) for the radio button list container tag.
975
     * The following options are specially handled:
976
     *
977
     * - tag: string|false, the tag name of the container element. False to render radio buttons without container.
978
     *   See also [[tag()]].
979
     * - unselect: string, the value that should be submitted when none of the radio buttons is selected.
980
     *   By setting this option, a hidden input will be generated.
981
     * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true.
982
     *   This option is ignored if `item` option is set.
983
     * - separator: string, the HTML code that separates items.
984
     * - itemOptions: array, the options for generating the radio button tag using [[radio()]].
985
     * - item: callable, a callback that can be used to customize the generation of the HTML code
986
     *   corresponding to a single item in $items. The signature of this callback must be:
987
     *
988
     *   ```php
989
     *   function ($index, $label, $name, $checked, $value)
990
     *   ```
991
     *
992
     *   where $index is the zero-based index of the radio button in the whole list; $label
993
     *   is the label for the radio button; and $name, $value and $checked represent the name,
994
     *   value and the checked status of the radio button input, respectively.
995
     *
996
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
997
     *
998
     * @return string the generated radio button list
999 1
     */
1000
    public static function radioList($name, $selection = null, $items = [], $options = [])
1001 1
    {
1002 1
        $formatter = ArrayHelper::remove($options, 'item');
1003 1
        $itemOptions = ArrayHelper::remove($options, 'itemOptions', []);
1004 1
        $encode = ArrayHelper::remove($options, 'encode', true);
1005 1
        $separator = ArrayHelper::remove($options, 'separator', "\n");
1006
        $tag = ArrayHelper::remove($options, 'tag', 'div');
1007 1
        // add a hidden field so that if the list box has no option being selected, it still submits a value
1008 1
        $hidden = isset($options['unselect']) ? static::hiddenInput($name, $options['unselect']) : '';
1009
        unset($options['unselect']);
1010 1
1011 1
        $lines = [];
1012 1
        $index = 0;
1013 1
        foreach ($items as $value => $label) {
1014 1
            $checked = $selection !== null &&
1015 1
                (!ArrayHelper::isTraversable($selection) && !strcmp($value, $selection)
1016 1
                    || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn($value, $selection));
1017 1
            if ($formatter !== null) {
1018 1
                $lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value);
1019 1
            } else {
1020 1
                $lines[] = static::radio($name, $checked, array_merge($itemOptions, [
1021 1
                    'value' => $value,
1022 1
                    'label' => $encode ? static::encode($label) : $label,
1023
                ]));
1024 1
            }
1025 1
            $index++;
1026 1
        }
1027
        $visibleContent = implode($separator, $lines);
1028 1
1029 1
        if ($tag === false) {
1030
            return $hidden . $visibleContent;
1031
        }
1032 1
1033
        return $hidden . static::tag($tag, $visibleContent, $options);
1034
    }
1035
1036
    /**
1037
     * Generates an unordered list.
1038
     * @param array|\Traversable $items the items for generating the list. Each item generates a single list item.
1039
     * Note that items will be automatically HTML encoded if `$options['encode']` is not set or true.
1040
     * @param array $options options (name => config) for the radio button list. The following options are supported:
1041
     *
1042
     * - encode: boolean, whether to HTML-encode the items. Defaults to true.
1043
     *   This option is ignored if the `item` option is specified.
1044
     * - separator: string, the HTML code that separates items. Defaults to a simple newline (`"\n"`).
1045
     *   This option is available since version 2.0.7.
1046
     * - itemOptions: array, the HTML attributes for the `li` tags. This option is ignored if the `item` option is specified.
1047
     * - item: callable, a callback that is used to generate each individual list item.
1048
     *   The signature of this callback must be:
1049
     *
1050
     *   ```php
1051
     *   function ($item, $index)
1052
     *   ```
1053
     *
1054
     *   where $index is the array key corresponding to `$item` in `$items`. The callback should return
1055
     *   the whole list item tag.
1056
     *
1057
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1058
     *
1059
     * @return string the generated unordered list. An empty list tag will be returned if `$items` is empty.
1060 4
     */
1061
    public static function ul($items, $options = [])
1062 4
    {
1063 4
        $tag = ArrayHelper::remove($options, 'tag', 'ul');
1064 4
        $encode = ArrayHelper::remove($options, 'encode', true);
1065 4
        $formatter = ArrayHelper::remove($options, 'item');
1066 4
        $separator = ArrayHelper::remove($options, 'separator', "\n");
1067
        $itemOptions = ArrayHelper::remove($options, 'itemOptions', []);
1068 4
1069 2
        if (empty($items)) {
1070
            return static::tag($tag, '', $options);
1071
        }
1072 4
1073 4
        $results = [];
1074 4
        foreach ($items as $index => $item) {
1075 2
            if ($formatter !== null) {
1076 2
                $results[] = call_user_func($formatter, $item, $index);
1077 4
            } else {
1078
                $results[] = static::tag('li', $encode ? static::encode($item) : $item, $itemOptions);
1079 4
            }
1080
        }
1081 4
1082 4
        return static::tag(
1083 4
            $tag,
1084
            $separator . implode($separator, $results) . $separator,
1085 4
            $options
1086
        );
1087
    }
1088
1089
    /**
1090
     * Generates an ordered list.
1091
     * @param array|\Traversable $items the items for generating the list. Each item generates a single list item.
1092
     * Note that items will be automatically HTML encoded if `$options['encode']` is not set or true.
1093
     * @param array $options options (name => config) for the radio button list. The following options are supported:
1094
     *
1095
     * - encode: boolean, whether to HTML-encode the items. Defaults to true.
1096
     *   This option is ignored if the `item` option is specified.
1097
     * - itemOptions: array, the HTML attributes for the `li` tags. This option is ignored if the `item` option is specified.
1098
     * - item: callable, a callback that is used to generate each individual list item.
1099
     *   The signature of this callback must be:
1100
     *
1101
     *   ```php
1102
     *   function ($item, $index)
1103
     *   ```
1104
     *
1105
     *   where $index is the array key corresponding to `$item` in `$items`. The callback should return
1106
     *   the whole list item tag.
1107
     *
1108
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1109
     *
1110
     * @return string the generated ordered list. An empty string is returned if `$items` is empty.
1111 1
     */
1112
    public static function ol($items, $options = [])
1113 1
    {
1114 1
        $options['tag'] = 'ol';
1115
        return static::ul($items, $options);
1116
    }
1117
1118
    /**
1119
     * Generates a label tag for the given model attribute.
1120
     * The label text is the label associated with the attribute, obtained via [[Model::getAttributeLabel()]].
1121
     * @param Model $model the model object
1122
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1123
     * about attribute expression.
1124
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
1125
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
1126
     * If a value is null, the corresponding attribute will not be rendered.
1127
     * The following options are specially handled:
1128
     *
1129
     * - label: this specifies the label to be displayed. Note that this will NOT be [[encode()|encoded]].
1130
     *   If this is not set, [[Model::getAttributeLabel()]] will be called to get the label for display
1131
     *   (after encoding).
1132
     *
1133
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1134
     *
1135
     * @return string the generated label tag
1136 11
     */
1137
    public static function activeLabel($model, $attribute, $options = [])
1138 11
    {
1139 11
        $for = ArrayHelper::remove($options, 'for', static::getInputId($model, $attribute));
1140 11
        $attribute = static::getAttributeName($attribute);
1141 11
        $label = ArrayHelper::remove($options, 'label', static::encode($model->getAttributeLabel($attribute)));
1142
        return static::label($label, $for, $options);
1143
    }
1144
1145
    /**
1146
     * Generates a hint tag for the given model attribute.
1147
     * The hint text is the hint associated with the attribute, obtained via [[Model::getAttributeHint()]].
1148
     * If no hint content can be obtained, method will return an empty string.
1149
     * @param Model $model the model object
1150
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1151
     * about attribute expression.
1152
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
1153
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
1154
     * If a value is null, the corresponding attribute will not be rendered.
1155
     * The following options are specially handled:
1156
     *
1157
     * - hint: this specifies the hint to be displayed. Note that this will NOT be [[encode()|encoded]].
1158
     *   If this is not set, [[Model::getAttributeHint()]] will be called to get the hint for display
1159
     *   (without encoding).
1160
     *
1161
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1162
     *
1163
     * @return string the generated hint tag
1164
     * @since 2.0.4
1165 11
     */
1166
    public static function activeHint($model, $attribute, $options = [])
1167 11
    {
1168 11
        $attribute = static::getAttributeName($attribute);
1169 11
        $hint = isset($options['hint']) ? $options['hint'] : $model->getAttributeHint($attribute);
1170 3
        if (empty($hint)) {
1171
            return '';
1172 8
        }
1173 8
        $tag = ArrayHelper::remove($options, 'tag', 'div');
1174 8
        unset($options['hint']);
1175
        return static::tag($tag, $hint, $options);
1176
    }
1177
1178
    /**
1179
     * Generates a summary of the validation errors.
1180
     * If there is no validation error, an empty error summary markup will still be generated, but it will be hidden.
1181
     * @param Model|Model[] $models the model(s) whose validation errors are to be displayed.
1182
     * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
1183
     *
1184
     * - header: string, the header HTML for the error summary. If not set, a default prompt string will be used.
1185
     * - footer: string, the footer HTML for the error summary. Defaults to empty string.
1186
     * - encode: boolean, if set to false then the error messages won't be encoded. Defaults to `true`.
1187
     * - showAllErrors: boolean, if set to true every error message for each attribute will be shown otherwise
1188
     *   only the first error message for each attribute will be shown. Defaults to `false`.
1189
     *   Option is available since 2.0.10.
1190
     *
1191
     * The rest of the options will be rendered as the attributes of the container tag.
1192
     *
1193
     * @return string the generated error summary
1194 7
     */
1195
    public static function errorSummary($models, $options = [])
1196 7
    {
1197 7
        $header = isset($options['header']) ? $options['header'] : '<p>' . Yii::t('yii', 'Please fix the following errors:') . '</p>';
1198 7
        $footer = ArrayHelper::remove($options, 'footer', '');
1199 7
        $encode = ArrayHelper::remove($options, 'encode', true);
1200 7
        $showAllErrors = ArrayHelper::remove($options, 'showAllErrors', false);
1201
        unset($options['header']);
1202 7
1203 7
        $lines = [];
1204 7
        if (!is_array($models)) {
1205 7
            $models = [$models];
1206 7
        }
1207
        foreach ($models as $model) {
1208 7
            /* @var $model Model */
1209 5
            foreach ($model->getErrors() as $errors) {
1210 5
                foreach ($errors as $error) {
1211 5
                    $line = $encode ? Html::encode($error) : $error;
1212 5
                    if (array_search($line, $lines) === false) {
1213 5
                        $lines[] = $line;
1214 5
                    }
1215 4
                    if (!$showAllErrors) {
1216
                        break;
1217 5
                    }
1218 7
                }
1219 7
            }
1220
        }
1221 7
1222
        if (empty($lines)) {
1223 2
            // still render the placeholder for client-side validation use
1224 2
            $content = '<ul></ul>';
1225 2
            $options['style'] = isset($options['style']) ? rtrim($options['style'], ';') . '; display:none' : 'display:none';
1226 5
        } else {
1227
            $content = '<ul><li>' . implode("</li>\n<li>", $lines) . '</li></ul>';
1228 7
        }
1229
        return Html::tag('div', $header . $content . $footer, $options);
1230
    }
1231
1232
    /**
1233
     * Generates a tag that contains the first validation error of the specified model attribute.
1234
     * Note that even if there is no validation error, this method will still return an empty error tag.
1235
     * @param Model $model the model object
1236
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1237
     * about attribute expression.
1238
     * @param array $options the tag options in terms of name-value pairs. The values will be HTML-encoded
1239
     * using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
1240
     *
1241
     * The following options are specially handled:
1242
     *
1243
     * - tag: this specifies the tag name. If not set, "div" will be used.
1244
     *   See also [[tag()]].
1245
     * - encode: boolean, if set to false then the error message won't be encoded.
1246
     *
1247
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1248
     *
1249
     * @return string the generated label tag
1250 9
     */
1251
    public static function error($model, $attribute, $options = [])
1252 9
    {
1253 9
        $attribute = static::getAttributeName($attribute);
1254 9
        $error = $model->getFirstError($attribute);
1255 9
        $tag = ArrayHelper::remove($options, 'tag', 'div');
1256 9
        $encode = ArrayHelper::remove($options, 'encode', true);
1257
        return Html::tag($tag, $encode ? Html::encode($error) : $error, $options);
1258
    }
1259
1260
    /**
1261
     * Generates an input tag for the given model attribute.
1262
     * This method will generate the "name" and "value" tag attributes automatically for the model attribute
1263
     * unless they are explicitly specified in `$options`.
1264
     * @param string $type the input type (e.g. 'text', 'password')
1265
     * @param Model $model the model object
1266
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1267
     * about attribute expression.
1268
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
1269
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
1270
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1271
     * @return string the generated input tag
1272 20
     */
1273
    public static function activeInput($type, $model, $attribute, $options = [])
1274 20
    {
1275 20
        $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute);
1276 20
        $value = isset($options['value']) ? $options['value'] : static::getAttributeValue($model, $attribute);
1277 18
        if (!array_key_exists('id', $options)) {
1278 18
            $options['id'] = static::getInputId($model, $attribute);
1279 20
        }
1280
        return static::input($type, $name, $value, $options);
1281
    }
1282
1283
    /**
1284
     * If `maxlength` option is set true and the model attribute is validated by a string validator,
1285
     * the `maxlength` option will take the value of [[\yii\validators\StringValidator::max]].
1286
     * @param Model $model the model object
1287
     * @param string $attribute the attribute name or expression.
1288
     * @param array $options the tag options in terms of name-value pairs.
1289 19
     */
1290
    private static function normalizeMaxLength($model, $attribute, &$options)
1291 19
    {
1292 3
        if (isset($options['maxlength']) && $options['maxlength'] === true) {
1293 3
            unset($options['maxlength']);
1294 3
            $attrName = static::getAttributeName($attribute);
1295 3
            foreach ($model->getActiveValidators($attrName) as $validator) {
1296 3
                if ($validator instanceof StringValidator && $validator->max !== null) {
1297 3
                    $options['maxlength'] = $validator->max;
1298
                    break;
1299 3
                }
1300 3
            }
1301 19
        }
1302
    }
1303
1304
    /**
1305
     * Generates a text input tag for the given model attribute.
1306
     * This method will generate the "name" and "value" tag attributes automatically for the model attribute
1307
     * unless they are explicitly specified in `$options`.
1308
     * @param Model $model the model object
1309
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1310
     * about attribute expression.
1311
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
1312
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
1313
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1314
     * The following special options are recognized:
1315
     *
1316
     * - maxlength: integer|boolean, when `maxlength` is set true and the model attribute is validated
1317
     *   by a string validator, the `maxlength` option will take the value of [[\yii\validators\StringValidator::max]].
1318
     *   This is available since version 2.0.3.
1319
     *
1320
     * @return string the generated input tag
1321 12
     */
1322
    public static function activeTextInput($model, $attribute, $options = [])
1323 12
    {
1324 12
        self::normalizeMaxLength($model, $attribute, $options);
1325
        return static::activeInput('text', $model, $attribute, $options);
1326
    }
1327
1328
    /**
1329
     * Generates a hidden input tag for the given model attribute.
1330
     * This method will generate the "name" and "value" tag attributes automatically for the model attribute
1331
     * unless they are explicitly specified in `$options`.
1332
     * @param Model $model the model object
1333
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1334
     * about attribute expression.
1335
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
1336
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
1337
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1338
     * @return string the generated input tag
1339 3
     */
1340
    public static function activeHiddenInput($model, $attribute, $options = [])
1341 3
    {
1342
        return static::activeInput('hidden', $model, $attribute, $options);
1343
    }
1344
1345
    /**
1346
     * Generates a password input tag for the given model attribute.
1347
     * This method will generate the "name" and "value" tag attributes automatically for the model attribute
1348
     * unless they are explicitly specified in `$options`.
1349
     * @param Model $model the model object
1350
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1351
     * about attribute expression.
1352
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
1353
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
1354
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1355
     * The following special options are recognized:
1356
     *
1357
     * - maxlength: integer|boolean, when `maxlength` is set true and the model attribute is validated
1358
     *   by a string validator, the `maxlength` option will take the value of [[\yii\validators\StringValidator::max]].
1359
     *   This option is available since version 2.0.6.
1360
     *
1361
     * @return string the generated input tag
1362 3
     */
1363
    public static function activePasswordInput($model, $attribute, $options = [])
1364 3
    {
1365 3
        self::normalizeMaxLength($model, $attribute, $options);
1366
        return static::activeInput('password', $model, $attribute, $options);
1367
    }
1368
1369
    /**
1370
     * Generates a file input tag for the given model attribute.
1371
     * This method will generate the "name" and "value" tag attributes automatically for the model attribute
1372
     * unless they are explicitly specified in `$options`.
1373
     * @param Model $model the model object
1374
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1375
     * about attribute expression.
1376
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
1377
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
1378
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1379
     * @return string the generated input tag
1380 1
     */
1381
    public static function activeFileInput($model, $attribute, $options = [])
1382
    {
1383
        // add a hidden field so that if a model only has a file field, we can
1384 1
        // still use isset($_POST[$modelClass]) to detect if the input is submitted
1385 1
        $hiddenOptions = ['id' => null, 'value' => ''];
1386
        if (isset($options['name'])) {
1387
            $hiddenOptions['name'] = $options['name'];
1388 1
        }
1389 1
        return static::activeHiddenInput($model, $attribute, $hiddenOptions)
1390
            . static::activeInput('file', $model, $attribute, $options);
1391
    }
1392
1393
    /**
1394
     * Generates a textarea tag for the given model attribute.
1395
     * The model attribute value will be used as the content in the textarea.
1396
     * @param Model $model the model object
1397
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1398
     * about attribute expression.
1399
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
1400
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
1401
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1402
     * The following special options are recognized:
1403
     *
1404
     * - maxlength: integer|boolean, when `maxlength` is set true and the model attribute is validated
1405
     *   by a string validator, the `maxlength` option will take the value of [[\yii\validators\StringValidator::max]].
1406
     *   This option is available since version 2.0.6.
1407
     *
1408
     * @return string the generated textarea tag
1409 4
     */
1410
    public static function activeTextarea($model, $attribute, $options = [])
1411 4
    {
1412 4
        $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute);
1413 1
        if (isset($options['value'])) {
1414 1
            $value = $options['value'];
1415 1
            unset($options['value']);
1416 3
        } else {
1417
            $value = static::getAttributeValue($model, $attribute);
1418 4
        }
1419 4
        if (!array_key_exists('id', $options)) {
1420 4
            $options['id'] = static::getInputId($model, $attribute);
1421 4
        }
1422 4
        self::normalizeMaxLength($model, $attribute, $options);
1423
        return static::textarea($name, $value, $options);
1424
    }
1425
1426
    /**
1427
     * Generates a radio button tag together with a label for the given model attribute.
1428
     * This method will generate the "checked" tag attribute according to the model attribute value.
1429
     * @param Model $model the model object
1430
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1431
     * about attribute expression.
1432
     * @param array $options the tag options in terms of name-value pairs.
1433
     * See [[booleanInput()]] for details about accepted attributes.
1434
     *
1435
     * @return string the generated radio button tag
1436 4
     */
1437
    public static function activeRadio($model, $attribute, $options = [])
1438 4
    {
1439
        return static::activeBooleanInput('radio', $model, $attribute, $options);
1440
    }
1441
1442
    /**
1443
     * Generates a checkbox tag together with a label for the given model attribute.
1444
     * This method will generate the "checked" tag attribute according to the model attribute value.
1445
     * @param Model $model the model object
1446
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1447
     * about attribute expression.
1448
     * @param array $options the tag options in terms of name-value pairs.
1449
     * See [[booleanInput()]] for details about accepted attributes.
1450
     *
1451
     * @return string the generated checkbox tag
1452 4
     */
1453
    public static function activeCheckbox($model, $attribute, $options = [])
1454 4
    {
1455
        return static::activeBooleanInput('checkbox', $model, $attribute, $options);
1456
    }
1457
1458
    /**
1459
     * Generates a boolean input
1460
     * This method is mainly called by [[activeCheckbox()]] and [[activeRadio()]].
1461
     * @param string $type the input type. This can be either `radio` or `checkbox`.
1462
     * @param Model $model the model object
1463
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1464
     * about attribute expression.
1465
     * @param array $options the tag options in terms of name-value pairs.
1466
     * See [[booleanInput()]] for details about accepted attributes.
1467
     * @return string the generated input element
1468
     * @since 2.0.9
1469 8
     */
1470
    protected static function activeBooleanInput($type, $model, $attribute, $options = [])
1471 8
    {
1472 8
        $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute);
1473
        $value = static::getAttributeValue($model, $attribute);
1474 8
1475 8
        if (!array_key_exists('value', $options)) {
1476 8
            $options['value'] = '1';
1477 8
        }
1478 4
        if (!array_key_exists('uncheck', $options)) {
1479 8
            $options['uncheck'] = '0';
1480 4
        } elseif ($options['uncheck'] === false) {
1481 4
            unset($options['uncheck']);
1482 8
        }
1483 4
        if (!array_key_exists('label', $options)) {
1484 8
            $options['label'] = static::encode($model->getAttributeLabel(static::getAttributeName($attribute)));
1485 4
        } elseif ($options['label'] === false) {
1486 4
            unset($options['label']);
1487
        }
1488 8
1489
        $checked = "$value" === "{$options['value']}";
1490 8
1491 8
        if (!array_key_exists('id', $options)) {
1492 8
            $options['id'] = static::getInputId($model, $attribute);
1493
        }
1494 8
1495
        return static::$type($name, $checked, $options);
1496
    }
1497
1498
    /**
1499
     * Generates a drop-down list for the given model attribute.
1500
     * The selection of the drop-down list is taken from the value of the model attribute.
1501
     * @param Model $model the model object
1502
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1503
     * about attribute expression.
1504
     * @param array $items the option data items. The array keys are option values, and the array values
1505
     * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too).
1506
     * For each sub-array, an option group will be generated whose label is the key associated with the sub-array.
1507
     * If you have a list of data models, you may convert them into the format described above using
1508
     * [[\yii\helpers\ArrayHelper::map()]].
1509
     *
1510
     * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
1511
     * the labels will also be HTML-encoded.
1512
     * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
1513
     *
1514
     * - prompt: string, a prompt text to be displayed as the first option. Since version 2.0.11 you can use an array
1515
     *   to override the value and to set other tag attributes:
1516
     *
1517
     *   ```php
1518
     *   ['text' => 'Please select', 'options' => ['value' => 'none', 'class' => 'prompt', 'label' => 'Select']],
1519
     *   ```
1520
     *
1521
     * - options: array, the attributes for the select option tags. The array keys must be valid option values,
1522
     *   and the array values are the extra attributes for the corresponding option tags. For example,
1523
     *
1524
     *   ```php
1525
     *   [
1526
     *       'value1' => ['disabled' => true],
1527
     *       'value2' => ['label' => 'value 2'],
1528
     *   ];
1529
     *   ```
1530
     *
1531
     * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options',
1532
     *   except that the array keys represent the optgroup labels specified in $items.
1533
     * - encodeSpaces: bool, whether to encode spaces in option prompt and option value with `&nbsp;` character.
1534
     *   Defaults to false.
1535
     * - encode: bool, whether to encode option prompt and option value characters.
1536
     *   Defaults to `true`. This option is available since 2.0.3.
1537
     *
1538
     * The rest of the options will be rendered as the attributes of the resulting tag. The values will
1539
     * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
1540
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1541
     *
1542
     * @return string the generated drop-down list tag
1543 1
     */
1544
    public static function activeDropDownList($model, $attribute, $items, $options = [])
1545 1
    {
1546 1
        if (empty($options['multiple'])) {
1547
            return static::activeListInput('dropDownList', $model, $attribute, $items, $options);
1548
        } else {
1549
            return static::activeListBox($model, $attribute, $items, $options);
1550
        }
1551
    }
1552
1553
    /**
1554
     * Generates a list box.
1555
     * The selection of the list box is taken from the value of the model attribute.
1556
     * @param Model $model the model object
1557
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1558
     * about attribute expression.
1559
     * @param array $items the option data items. The array keys are option values, and the array values
1560
     * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too).
1561
     * For each sub-array, an option group will be generated whose label is the key associated with the sub-array.
1562
     * If you have a list of data models, you may convert them into the format described above using
1563
     * [[\yii\helpers\ArrayHelper::map()]].
1564
     *
1565
     * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
1566
     * the labels will also be HTML-encoded.
1567
     * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
1568
     *
1569
     * - prompt: string, a prompt text to be displayed as the first option. Since version 2.0.11 you can use an array
1570
     *   to override the value and to set other tag attributes:
1571
     *
1572
     *   ```php
1573
     *   ['text' => 'Please select', 'options' => ['value' => 'none', 'class' => 'prompt', 'label' => 'Select']],
1574
     *   ```
1575
     *
1576
     * - options: array, the attributes for the select option tags. The array keys must be valid option values,
1577
     *   and the array values are the extra attributes for the corresponding option tags. For example,
1578
     *
1579
     *   ```php
1580
     *   [
1581
     *       'value1' => ['disabled' => true],
1582
     *       'value2' => ['label' => 'value 2'],
1583
     *   ];
1584
     *   ```
1585
     *
1586
     * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options',
1587
     *   except that the array keys represent the optgroup labels specified in $items.
1588
     * - unselect: string, the value that will be submitted when no option is selected.
1589
     *   When this attribute is set, a hidden field will be generated so that if no option is selected in multiple
1590
     *   mode, we can still obtain the posted unselect value.
1591
     * - encodeSpaces: bool, whether to encode spaces in option prompt and option value with `&nbsp;` character.
1592
     *   Defaults to false.
1593
     * - encode: bool, whether to encode option prompt and option value characters.
1594
     *   Defaults to `true`. This option is available since 2.0.3.
1595
     *
1596
     * The rest of the options will be rendered as the attributes of the resulting tag. The values will
1597
     * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
1598
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1599
     *
1600
     * @return string the generated list box tag
1601 2
     */
1602
    public static function activeListBox($model, $attribute, $items, $options = [])
1603 2
    {
1604
        return static::activeListInput('listBox', $model, $attribute, $items, $options);
1605
    }
1606
1607
    /**
1608
     * Generates a list of checkboxes.
1609
     * A checkbox list allows multiple selection, like [[listBox()]].
1610
     * As a result, the corresponding submitted value is an array.
1611
     * The selection of the checkbox list is taken from the value of the model attribute.
1612
     * @param Model $model the model object
1613
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1614
     * about attribute expression.
1615
     * @param array $items the data item used to generate the checkboxes.
1616
     * The array keys are the checkbox values, and the array values are the corresponding labels.
1617
     * Note that the labels will NOT be HTML-encoded, while the values will.
1618
     * @param array $options options (name => config) for the checkbox list container tag.
1619
     * The following options are specially handled:
1620
     *
1621
     * - tag: string|false, the tag name of the container element. False to render checkbox without container.
1622
     *   See also [[tag()]].
1623
     * - unselect: string, the value that should be submitted when none of the checkboxes is selected.
1624
     *   You may set this option to be null to prevent default value submission.
1625
     *   If this option is not set, an empty string will be submitted.
1626
     * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true.
1627
     *   This option is ignored if `item` option is set.
1628
     * - separator: string, the HTML code that separates items.
1629
     * - itemOptions: array, the options for generating the checkbox tag using [[checkbox()]].
1630
     * - item: callable, a callback that can be used to customize the generation of the HTML code
1631
     *   corresponding to a single item in $items. The signature of this callback must be:
1632
     *
1633
     *   ```php
1634
     *   function ($index, $label, $name, $checked, $value)
1635
     *   ```
1636
     *
1637
     *   where $index is the zero-based index of the checkbox in the whole list; $label
1638
     *   is the label for the checkbox; and $name, $value and $checked represent the name,
1639
     *   value and the checked status of the checkbox input.
1640
     *
1641
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1642
     *
1643
     * @return string the generated checkbox list
1644
     */
1645
    public static function activeCheckboxList($model, $attribute, $items, $options = [])
1646
    {
1647
        return static::activeListInput('checkboxList', $model, $attribute, $items, $options);
1648
    }
1649
1650
    /**
1651
     * Generates a list of radio buttons.
1652
     * A radio button list is like a checkbox list, except that it only allows single selection.
1653
     * The selection of the radio buttons is taken from the value of the model attribute.
1654
     * @param Model $model the model object
1655
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1656
     * about attribute expression.
1657
     * @param array $items the data item used to generate the radio buttons.
1658
     * The array keys are the radio values, and the array values are the corresponding labels.
1659
     * Note that the labels will NOT be HTML-encoded, while the values will.
1660
     * @param array $options options (name => config) for the radio button list container tag.
1661
     * The following options are specially handled:
1662
     *
1663
     * - tag: string|false, the tag name of the container element. False to render radio button without container.
1664
     *   See also [[tag()]].
1665
     * - unselect: string, the value that should be submitted when none of the radio buttons is selected.
1666
     *   You may set this option to be null to prevent default value submission.
1667
     *   If this option is not set, an empty string will be submitted.
1668
     * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true.
1669
     *   This option is ignored if `item` option is set.
1670
     * - separator: string, the HTML code that separates items.
1671
     * - itemOptions: array, the options for generating the radio button tag using [[radio()]].
1672
     * - item: callable, a callback that can be used to customize the generation of the HTML code
1673
     *   corresponding to a single item in $items. The signature of this callback must be:
1674
     *
1675
     *   ```php
1676
     *   function ($index, $label, $name, $checked, $value)
1677
     *   ```
1678
     *
1679
     *   where $index is the zero-based index of the radio button in the whole list; $label
1680
     *   is the label for the radio button; and $name, $value and $checked represent the name,
1681
     *   value and the checked status of the radio button input.
1682
     *
1683
     * See [[renderTagAttributes()]] for details on how attributes are being rendered.
1684
     *
1685
     * @return string the generated radio button list
1686
     */
1687
    public static function activeRadioList($model, $attribute, $items, $options = [])
1688
    {
1689
        return static::activeListInput('radioList', $model, $attribute, $items, $options);
1690
    }
1691
1692
    /**
1693
     * Generates a list of input fields.
1694
     * This method is mainly called by [[activeListBox()]], [[activeRadioList()]] and [[activeCheckboxList()]].
1695
     * @param string $type the input type. This can be 'listBox', 'radioList', or 'checkBoxList'.
1696
     * @param Model $model the model object
1697
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
1698
     * about attribute expression.
1699
     * @param array $items the data item used to generate the input fields.
1700
     * The array keys are the input values, and the array values are the corresponding labels.
1701
     * Note that the labels will NOT be HTML-encoded, while the values will.
1702
     * @param array $options options (name => config) for the input list. The supported special options
1703
     * depend on the input type specified by `$type`.
1704
     * @return string the generated input list
1705 3
     */
1706
    protected static function activeListInput($type, $model, $attribute, $items, $options = [])
1707 3
    {
1708 3
        $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute);
1709 3
        $selection = isset($options['value']) ? $options['value'] : static::getAttributeValue($model, $attribute);
1710 3
        if (!array_key_exists('unselect', $options)) {
1711 3
            $options['unselect'] = '';
1712 3
        }
1713 2
        if (!array_key_exists('id', $options)) {
1714 2
            $options['id'] = static::getInputId($model, $attribute);
1715 3
        }
1716
        return static::$type($name, $selection, $items, $options);
1717
    }
1718
1719
    /**
1720
     * Renders the option tags that can be used by [[dropDownList()]] and [[listBox()]].
1721
     * @param string|array|null $selection the selected value(s). String for single or array for multiple selection(s).
1722
     * @param array $items the option data items. The array keys are option values, and the array values
1723
     * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too).
1724
     * For each sub-array, an option group will be generated whose label is the key associated with the sub-array.
1725
     * If you have a list of data models, you may convert them into the format described above using
1726
     * [[\yii\helpers\ArrayHelper::map()]].
1727
     *
1728
     * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
1729
     * the labels will also be HTML-encoded.
1730
     * @param array $tagOptions the $options parameter that is passed to the [[dropDownList()]] or [[listBox()]] call.
1731
     * This method will take out these elements, if any: "prompt", "options" and "groups". See more details
1732
     * in [[dropDownList()]] for the explanation of these elements.
1733
     *
1734
     * @return string the generated list options
1735 6
     */
1736
    public static function renderSelectOptions($selection, $items, &$tagOptions = [])
1737 6
    {
1738 6
        $lines = [];
1739 6
        $encodeSpaces = ArrayHelper::remove($tagOptions, 'encodeSpaces', false);
1740 6
        $encode = ArrayHelper::remove($tagOptions, 'encode', true);
1741 2
        if (isset($tagOptions['prompt'])) {
1742 2
            $promptOptions = ['value' => ''];
1743 2
            if (is_string($tagOptions['prompt'])) {
1744 2
                $promptText = $tagOptions['prompt'];
1745 1
            } else {
1746 1
                $promptText = $tagOptions['prompt']['text'];
1747
                $promptOptions = array_merge($promptOptions, $tagOptions['prompt']['options']);
1748 2
            }
1749 2
            $promptText = $encode ? static::encode($promptText) : $promptText;
1750 1
            if ($encodeSpaces) {
1751 1
                $promptText = str_replace(' ', '&nbsp;', $promptText);
1752 2
            }
1753 2
            $lines[] = static::tag('option', $promptText, $promptOptions);
1754
        }
1755 6
1756 6
        $options = isset($tagOptions['options']) ? $tagOptions['options'] : [];
1757 6
        $groups = isset($tagOptions['groups']) ? $tagOptions['groups'] : [];
1758 6
        unset($tagOptions['prompt'], $tagOptions['options'], $tagOptions['groups']);
1759 6
        $options['encodeSpaces'] = ArrayHelper::getValue($options, 'encodeSpaces', $encodeSpaces);
1760
        $options['encode'] = ArrayHelper::getValue($options, 'encode', $encode);
1761 6
1762 6
        foreach ($items as $key => $value) {
1763 1
            if (is_array($value)) {
1764 1
                $groupAttrs = isset($groups[$key]) ? $groups[$key] : [];
1765 1
                if (!isset($groupAttrs['label'])) {
1766 1
                    $groupAttrs['label'] = $key;
1767 1
                }
1768 1
                $attrs = ['options' => $options, 'groups' => $groups, 'encodeSpaces' => $encodeSpaces, 'encode' => $encode];
1769 1
                $content = static::renderSelectOptions($selection, $value, $attrs);
1770 1
                $lines[] = static::tag('optgroup', "\n" . $content . "\n", $groupAttrs);
1771 6
            } else {
1772 6
                $attrs = isset($options[$key]) ? $options[$key] : [];
1773 6
                $attrs['value'] = (string) $key;
1774 6
                if (!array_key_exists('selected', $attrs)) {
1775 5
                    $attrs['selected'] = $selection !== null &&
1776 5
                        (!ArrayHelper::isTraversable($selection) && !strcmp($key, $selection)
1777 6
                        || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn($key, $selection));
1778 6
                }
1779 6
                $text = $encode ? static::encode($value) : $value;
1780 2
                if ($encodeSpaces) {
1781 2
                    $text = str_replace(' ', '&nbsp;', $text);
1782 6
                }
1783
                $lines[] = static::tag('option', $text, $attrs);
1784 6
            }
1785
        }
1786 6
1787
        return implode("\n", $lines);
1788
    }
1789
1790
    /**
1791
     * Renders the HTML tag attributes.
1792
     *
1793
     * Attributes whose values are of boolean type will be treated as
1794
     * [boolean attributes](http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes).
1795
     *
1796
     * Attributes whose values are null will not be rendered.
1797
     *
1798
     * The values of attributes will be HTML-encoded using [[encode()]].
1799
     *
1800
     * The "data" attribute is specially handled when it is receiving an array value. In this case,
1801
     * the array will be "expanded" and a list data attributes will be rendered. For example,
1802
     * if `'data' => ['id' => 1, 'name' => 'yii']`, then this will be rendered:
1803
     * `data-id="1" data-name="yii"`.
1804
     * Additionally `'data' => ['params' => ['id' => 1, 'name' => 'yii'], 'status' => 'ok']` will be rendered as:
1805
     * `data-params='{"id":1,"name":"yii"}' data-status="ok"`.
1806
     *
1807
     * @param array $attributes attributes to be rendered. The attribute values will be HTML-encoded using [[encode()]].
1808
     * @return string the rendering result. If the attributes are not empty, they will be rendered
1809
     * into a string with a leading white space (so that it can be directly appended to the tag name
1810
     * in a tag. If there is no attribute, an empty string will be returned.
1811 177
     */
1812
    public static function renderTagAttributes($attributes)
1813 177
    {
1814 133
        if (count($attributes) > 1) {
1815 133
            $sorted = [];
1816 133
            foreach (static::$attributeOrder as $name) {
1817 133
                if (isset($attributes[$name])) {
1818 133
                    $sorted[$name] = $attributes[$name];
1819 133
                }
1820 133
            }
1821 133
            $attributes = array_merge($sorted, $attributes);
1822
        }
1823 177
1824 177
        $html = '';
1825 165
        foreach ($attributes as $name => $value) {
1826 29
            if (is_bool($value)) {
1827 24
                if ($value) {
1828 24
                    $html .= " $name";
1829 165
                }
1830 3
            } elseif (is_array($value)) {
1831 2
                if (in_array($name, static::$dataAttributes)) {
1832 2
                    foreach ($value as $n => $v) {
1833
                        if (is_array($v)) {
1834
                            $html .= " $name-$n='" . Json::htmlEncode($v) . "'";
1835 2
                        } else {
1836
                            $html .= " $name-$n=\"" . static::encode($v) . '"';
1837 2
                        }
1838 3
                    }
1839 1
                } elseif ($name === 'class') {
1840 1
                    if (empty($value)) {
1841
                        continue;
1842 1
                    }
1843 2
                    $html .= " $name=\"" . static::encode(implode(' ', $value)) . '"';
1844 1
                } elseif ($name === 'style') {
1845 1
                    if (empty($value)) {
1846
                        continue;
1847 1
                    }
1848 1
                    $html .= " $name=\"" . static::encode(static::cssStyleFromArray($value)) . '"';
1849 1
                } else {
1850
                    $html .= " $name='" . Json::htmlEncode($value) . "'";
1851 165
                }
1852 165
            } elseif ($value !== null) {
1853 165
                $html .= " $name=\"" . static::encode($value) . '"';
1854 177
            }
1855
        }
1856 177
1857
        return $html;
1858
    }
1859
1860
    /**
1861
     * Adds a CSS class (or several classes) to the specified options.
1862
     * If the CSS class is already in the options, it will not be added again.
1863
     * If class specification at given options is an array, and some class placed there with the named (string) key,
1864
     * overriding of such key will have no effect. For example:
1865
     *
1866
     * ```php
1867
     * $options = ['class' => ['persistent' => 'initial']];
1868
     * Html::addCssClass($options, ['persistent' => 'override']);
1869
     * var_dump($options['class']); // outputs: array('persistent' => 'initial');
1870
     * ```
1871
     *
1872
     * @param array $options the options to be modified.
1873
     * @param string|array $class the CSS class(es) to be added
1874 5
     */
1875
    public static function addCssClass(&$options, $class)
1876 5
    {
1877 4
        if (isset($options['class'])) {
1878 2
            if (is_array($options['class'])) {
1879 2
                $options['class'] = self::mergeCssClasses($options['class'], (array) $class);
1880 3
            } else {
1881 3
                $classes = preg_split('/\s+/', $options['class'], -1, PREG_SPLIT_NO_EMPTY);
1882
                $options['class'] = implode(' ', self::mergeCssClasses($classes, (array) $class));
1883 4
            }
1884 4
        } else {
1885
            $options['class'] = $class;
1886 5
        }
1887
    }
1888
1889
    /**
1890
     * Merges already existing CSS classes with new one.
1891
     * This method provides the priority for named existing classes over additional.
1892
     * @param array $existingClasses already existing CSS classes.
1893
     * @param array $additionalClasses CSS classes to be added.
1894
     * @return array merge result.
1895 4
     */
1896
    private static function mergeCssClasses(array $existingClasses, array $additionalClasses)
1897 4
    {
1898 4
        foreach ($additionalClasses as $key => $class) {
1899 3
            if (is_int($key) && !in_array($class, $existingClasses)) {
1900 4
                $existingClasses[] = $class;
1901 1
            } elseif (!isset($existingClasses[$key])) {
1902 1
                $existingClasses[$key] = $class;
1903 4
            }
1904 4
        }
1905
        return array_unique($existingClasses);
1906
    }
1907
1908
    /**
1909
     * Removes a CSS class from the specified options.
1910
     * @param array $options the options to be modified.
1911
     * @param string|array $class the CSS class(es) to be removed
1912 1
     */
1913
    public static function removeCssClass(&$options, $class)
1914 1
    {
1915 1
        if (isset($options['class'])) {
1916 1
            if (is_array($options['class'])) {
1917 1
                $classes = array_diff($options['class'], (array) $class);
1918 1
                if (empty($classes)) {
1919 1
                    unset($options['class']);
1920 1
                } else {
1921
                    $options['class'] = $classes;
1922 1
                }
1923 1
            } else {
1924 1
                $classes = preg_split('/\s+/', $options['class'], -1, PREG_SPLIT_NO_EMPTY);
1925 1
                $classes = array_diff($classes, (array) $class);
1926 1
                if (empty($classes)) {
1927 1
                    unset($options['class']);
1928 1
                } else {
1929
                    $options['class'] = implode(' ', $classes);
1930
                }
1931 1
            }
1932 1
        }
1933
    }
1934
1935
    /**
1936
     * Adds the specified CSS style to the HTML options.
1937
     *
1938
     * If the options already contain a `style` element, the new style will be merged
1939
     * with the existing one. If a CSS property exists in both the new and the old styles,
1940
     * the old one may be overwritten if `$overwrite` is true.
1941
     *
1942
     * For example,
1943
     *
1944
     * ```php
1945
     * Html::addCssStyle($options, 'width: 100px; height: 200px');
1946
     * ```
1947
     *
1948
     * @param array $options the HTML options to be modified.
1949
     * @param string|array $style the new style string (e.g. `'width: 100px; height: 200px'`) or
1950
     * array (e.g. `['width' => '100px', 'height' => '200px']`).
1951
     * @param bool $overwrite whether to overwrite existing CSS properties if the new style
1952
     * contain them too.
1953
     * @see removeCssStyle()
1954
     * @see cssStyleFromArray()
1955
     * @see cssStyleToArray()
1956 1
     */
1957
    public static function addCssStyle(&$options, $style, $overwrite = true)
1958 1
    {
1959 1
        if (!empty($options['style'])) {
1960 1
            $oldStyle = is_array($options['style']) ? $options['style'] : static::cssStyleToArray($options['style']);
1961 1
            $newStyle = is_array($style) ? $style : static::cssStyleToArray($style);
1962 1
            if (!$overwrite) {
1963 1
                foreach ($newStyle as $property => $value) {
1964 1
                    if (isset($oldStyle[$property])) {
1965 1
                        unset($newStyle[$property]);
1966 1
                    }
1967 1
                }
1968 1
            }
1969 1
            $style = array_merge($oldStyle, $newStyle);
1970 1
        }
1971 1
        $options['style'] = is_array($style) ? static::cssStyleFromArray($style) : $style;
1972
    }
1973
1974
    /**
1975
     * Removes the specified CSS style from the HTML options.
1976
     *
1977
     * For example,
1978
     *
1979
     * ```php
1980
     * Html::removeCssStyle($options, ['width', 'height']);
1981
     * ```
1982
     *
1983
     * @param array $options the HTML options to be modified.
1984
     * @param string|array $properties the CSS properties to be removed. You may use a string
1985
     * if you are removing a single property.
1986
     * @see addCssStyle()
1987 1
     */
1988
    public static function removeCssStyle(&$options, $properties)
1989 1
    {
1990 1
        if (!empty($options['style'])) {
1991 1
            $style = is_array($options['style']) ? $options['style'] : static::cssStyleToArray($options['style']);
1992 1
            foreach ((array) $properties as $property) {
1993 1
                unset($style[$property]);
1994 1
            }
1995 1
            $options['style'] = static::cssStyleFromArray($style);
1996 1
        }
1997
    }
1998
1999
    /**
2000
     * Converts a CSS style array into a string representation.
2001
     *
2002
     * For example,
2003
     *
2004
     * ```php
2005
     * print_r(Html::cssStyleFromArray(['width' => '100px', 'height' => '200px']));
2006
     * // will display: 'width: 100px; height: 200px;'
2007
     * ```
2008
     *
2009
     * @param array $style the CSS style array. The array keys are the CSS property names,
2010
     * and the array values are the corresponding CSS property values.
2011
     * @return string the CSS style string. If the CSS style is empty, a null will be returned.
2012 4
     */
2013
    public static function cssStyleFromArray(array $style)
2014 4
    {
2015 4
        $result = '';
2016 4
        foreach ($style as $name => $value) {
2017 4
            $result .= "$name: $value; ";
2018
        }
2019 4
        // return null if empty to avoid rendering the "style" attribute
2020
        return $result === '' ? null : rtrim($result);
2021
    }
2022
2023
    /**
2024
     * Converts a CSS style string into an array representation.
2025
     *
2026
     * The array keys are the CSS property names, and the array values
2027
     * are the corresponding CSS property values.
2028
     *
2029
     * For example,
2030
     *
2031
     * ```php
2032
     * print_r(Html::cssStyleToArray('width: 100px; height: 200px;'));
2033
     * // will display: ['width' => '100px', 'height' => '200px']
2034
     * ```
2035
     *
2036
     * @param string $style the CSS style string
2037
     * @return array the array representation of the CSS style
2038 3
     */
2039
    public static function cssStyleToArray($style)
2040 3
    {
2041 3
        $result = [];
2042 3
        foreach (explode(';', $style) as $property) {
2043 3
            $property = explode(':', $property);
2044 3
            if (count($property) > 1) {
2045 3
                $result[trim($property[0])] = trim($property[1]);
2046 3
            }
2047 3
        }
2048
        return $result;
2049
    }
2050
2051
    /**
2052
     * Returns the real attribute name from the given attribute expression.
2053
     *
2054
     * An attribute expression is an attribute name prefixed and/or suffixed with array indexes.
2055
     * It is mainly used in tabular data input and/or input of array type. Below are some examples:
2056
     *
2057
     * - `[0]content` is used in tabular data input to represent the "content" attribute
2058
     *   for the first model in tabular input;
2059
     * - `dates[0]` represents the first array element of the "dates" attribute;
2060
     * - `[0]dates[0]` represents the first array element of the "dates" attribute
2061
     *   for the first model in tabular input.
2062
     *
2063
     * If `$attribute` has neither prefix nor suffix, it will be returned back without change.
2064
     * @param string $attribute the attribute name or expression
2065
     * @return string the attribute name without prefix and suffix.
2066
     * @throws InvalidParamException if the attribute name contains non-word characters.
2067 30
     */
2068
    public static function getAttributeName($attribute)
2069 30
    {
2070 30
        if (preg_match('/(^|.*\])([\w\.]+)(\[.*|$)/', $attribute, $matches)) {
2071
            return $matches[2];
2072
        } else {
2073
            throw new InvalidParamException('Attribute name must contain word characters only.');
2074
        }
2075
    }
2076
2077
    /**
2078
     * Returns the value of the specified attribute name or expression.
2079
     *
2080
     * For an attribute expression like `[0]dates[0]`, this method will return the value of `$model->dates[0]`.
2081
     * See [[getAttributeName()]] for more details about attribute expression.
2082
     *
2083
     * If an attribute value is an instance of [[ActiveRecordInterface]] or an array of such instances,
2084
     * the primary value(s) of the AR instance(s) will be returned instead.
2085
     *
2086
     * @param Model $model the model object
2087
     * @param string $attribute the attribute name or expression
2088
     * @return string|array the corresponding attribute value
2089
     * @throws InvalidParamException if the attribute name contains non-word characters.
2090 34
     */
2091
    public static function getAttributeValue($model, $attribute)
2092 34
    {
2093
        if (!preg_match('/(^|.*\])([\w\.]+)(\[.*|$)/', $attribute, $matches)) {
2094
            throw new InvalidParamException('Attribute name must contain word characters only.');
2095 34
        }
2096 34
        $attribute = $matches[2];
2097 34
        $value = $model->$attribute;
2098
        if ($matches[3] !== '') {
2099
            foreach (explode('][', trim($matches[3], '[]')) as $id) {
2100
                if ((is_array($value) || $value instanceof \ArrayAccess) && isset($value[$id])) {
2101
                    $value = $value[$id];
2102
                } else {
2103
                    return null;
2104
                }
2105
            }
2106
        }
2107
2108 34
        // https://github.com/yiisoft/yii2/issues/1457
2109
        if (is_array($value)) {
2110
            foreach ($value as $i => $v) {
2111
                if ($v instanceof ActiveRecordInterface) {
2112
                    $v = $v->getPrimaryKey(false);
2113
                    $value[$i] = is_array($v) ? json_encode($v) : $v;
2114
                }
2115 34
            }
2116
        } elseif ($value instanceof ActiveRecordInterface) {
2117
            $value = $value->getPrimaryKey(false);
2118
2119
            return is_array($value) ? json_encode($value) : $value;
2120
        }
2121 34
2122
        return $value;
2123
    }
2124
2125
    /**
2126
     * Generates an appropriate input name for the specified attribute name or expression.
2127
     *
2128
     * This method generates a name that can be used as the input name to collect user input
2129
     * for the specified attribute. The name is generated according to the [[Model::formName|form name]]
2130
     * of the model and the given attribute name. For example, if the form name of the `Post` model
2131
     * is `Post`, then the input name generated for the `content` attribute would be `Post[content]`.
2132
     *
2133
     * See [[getAttributeName()]] for explanation of attribute expression.
2134
     *
2135
     * @param Model $model the model object
2136
     * @param string $attribute the attribute name or expression
2137
     * @return string the generated input name
2138
     * @throws InvalidParamException if the attribute name contains non-word characters.
2139 46
     */
2140
    public static function getInputName($model, $attribute)
2141 46
    {
2142 46
        $formName = $model->formName();
2143
        if (!preg_match('/(^|.*\])([\w\.]+)(\[.*|$)/', $attribute, $matches)) {
2144
            throw new InvalidParamException('Attribute name must contain word characters only.');
2145 46
        }
2146 46
        $prefix = $matches[1];
2147 46
        $attribute = $matches[2];
2148 46
        $suffix = $matches[3];
2149
        if ($formName === '' && $prefix === '') {
2150 46
            return $attribute . $suffix;
2151 46
        } elseif ($formName !== '') {
2152
            return $formName . $prefix . "[$attribute]" . $suffix;
2153
        } else {
2154
            throw new InvalidParamException(get_class($model) . '::formName() cannot be empty for tabular inputs.');
2155
        }
2156
    }
2157
2158
    /**
2159
     * Generates an appropriate input ID for the specified attribute name or expression.
2160
     *
2161
     * This method converts the result [[getInputName()]] into a valid input ID.
2162
     * For example, if [[getInputName()]] returns `Post[content]`, this method will return `post-content`.
2163
     * @param Model $model the model object
2164
     * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for explanation of attribute expression.
2165
     * @return string the generated input ID
2166
     * @throws InvalidParamException if the attribute name contains non-word characters.
2167 43
     */
2168
    public static function getInputId($model, $attribute)
2169 43
    {
2170 43
        $name = strtolower(static::getInputName($model, $attribute));
2171
        return str_replace(['[]', '][', '[', ']', ' ', '.'], ['', '-', '-', '', '-', '-'], $name);
2172
    }
2173
2174
    /**
2175
     * Escapes regular expression to use in JavaScript
2176
     * @param string $regexp the regular expression to be escaped.
2177
     * @return string the escaped result.
2178
     * @since 2.0.6
2179
     */
2180
    public static function escapeJsRegularExpression($regexp)
2181
    {
2182
        $pattern = preg_replace('/\\\\x\{?([0-9a-fA-F]+)\}?/', '\u$1', $regexp);
2183
        $deliminator = substr($pattern, 0, 1);
2184
        $pos = strrpos($pattern, $deliminator, 1);
2185
        $flag = substr($pattern, $pos + 1);
2186
        if ($deliminator !== '/') {
2187
            $pattern = '/' . str_replace('/', '\\/', substr($pattern, 1, $pos - 1)) . '/';
2188
        } else {
2189
            $pattern = substr($pattern, 0, $pos + 1);
2190
        }
2191
        if (!empty($flag)) {
2192
            $pattern .= preg_replace('/[^igm]/', '', $flag);
2193
        }
2194
2195
        return $pattern;
2196
    }
2197
}
2198