Passed
Push — dependabot/github_actions/acti... ( 6c9f07 )
by
unknown
14:42 queued 10:29
created

HtmlForm   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 129
Duplicated Lines 0 %

Test Coverage

Coverage 95.45%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 19
c 2
b 0
f 0
dl 0
loc 129
ccs 21
cts 22
cp 0.9545
rs 10
wmc 9

5 Methods

Rating   Name   Duplication   Size   Complexity  
A parseAttribute() 0 9 2
A getAttributeName() 0 3 1
A getAttributeValue() 0 4 1
A getInputName() 0 15 4
A getInputId() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Form\Helper;
6
7
use InvalidArgumentException;
8
use Yiisoft\Form\FormModelInterface;
9
10
/**
11
 * Form-related HTML tag generation
12
 */
13
final class HtmlForm
14
{
15
    /**
16
     * Returns the value of the specified attribute name or expression.
17
     *
18
     * For an attribute expression like `[0]dates[0]`, this method will return the value of `$form->dates[0]`.
19
     * See {@see getAttributeName()} for more details about attribute expression.
20
     *
21
     * If an attribute value an array of such instances, the primary value(s) of the AR instance(s) will be returned
22
     * instead.
23
     *
24
     * @param FormModelInterface $form the form object.
25
     * @param string $attribute the attribute name or expression.
26
     *
27
     * @throws InvalidArgumentException if the attribute name contains non-word characters.
28
     *
29
     * @return array|string the corresponding attribute value.
30
     */
31 214
    public static function getAttributeValue(FormModelInterface $form, string $attribute)
32
    {
33 214
        return $form->getAttributeValue(
34 214
            self::getAttributeName($attribute)
35
        );
36
    }
37
38
    /**
39
     * Generates an appropriate input ID for the specified attribute name or expression.
40
     *
41
     * This method converts the result {@see getInputName()} into a valid input ID.
42
     *
43
     * For example, if {@see getInputName()} returns `Post[content]`, this method will return `post-content`.
44
     *
45
     * @param FormModelInterface $form the form object
46
     * @param string $attribute the attribute name or expression. See {@see getAttributeName()} for explanation of
47
     * attribute expression.
48
     * @param string $charset default `UTF-8`.
49
     *
50
     * @throws InvalidArgumentException if the attribute name contains non-word characters.
51
     * @throws \UnexpectedValueException if charset is unknown
52
     *
53
     * @return string the generated input ID.
54
     */
55 213
    public static function getInputId(FormModelInterface $form, string $attribute, string $charset = 'UTF-8'): string
56
    {
57 213
        $name = mb_strtolower(self::getInputName($form, $attribute), $charset);
58 213
        return str_replace(['[]', '][', '[', ']', ' ', '.'], ['', '-', '-', '', '-', '-'], $name);
59
    }
60
61
    /**
62
     * Generates an appropriate input name for the specified attribute name or expression.
63
     *
64
     * This method generates a name that can be used as the input name to collect user input for the specified
65
     * attribute. The name is generated according to the of the form and the given attribute name. For example, if the
66
     * form name of the `Post` form is `Post`, then the input name generated for the `content` attribute would be
67
     * `Post[content]`.
68
     *
69
     * See {@see getAttributeName()} for explanation of attribute expression.
70
     *
71
     * @param FormModelInterface $form the form object.
72
     * @param string $attribute the attribute name or expression.
73
     *
74
     * @throws InvalidArgumentException if the attribute name contains non-word characters
75
     * or empty form name for tabular inputs
76
     *
77
     * @return string the generated input name.
78
     */
79 224
    public static function getInputName(FormModelInterface $form, string $attribute): string
80
    {
81 224
        $formName = $form->getFormName();
82
83 224
        $data = self::parseAttribute($attribute);
84
85 224
        if ($formName === '' && $data['prefix'] === '') {
86 2
            return $attribute;
87
        }
88
89 222
        if ($formName !== '') {
90 222
            return $formName . $data['prefix'] . '[' . $data['name'] . ']' . $data['suffix'];
91
        }
92
93
        throw new InvalidArgumentException(get_class($form) . '::formName() cannot be empty for tabular inputs.');
94
    }
95
96
    /**
97
     * Returns the real attribute name from the given attribute expression.
98
     * If `$attribute` has neither prefix nor suffix, it will be returned back without change.
99
     *
100
     * @param string $attribute the attribute name or expression
101
     *
102
     * @throws InvalidArgumentException if the attribute name contains non-word characters.
103
     *
104
     * @return string the attribute name without prefix and suffix.
105
     *
106
     * @see static::parseAttribute()
107
     */
108 222
    public static function getAttributeName(string $attribute): string
109
    {
110 222
        return self::parseAttribute($attribute)['name'];
111
    }
112
113
    /**
114
     * This method parses an attribute expression and returns an associative array containing
115
     * real attribute name, prefix and suffix.
116
     * For example: `['name' => 'content', 'prefix' => '', 'suffix' => '[0]']`
117
     *
118
     * An attribute expression is an attribute name prefixed and/or suffixed with array indexes. It is mainly used in
119
     * tabular data input and/or input of array type. Below are some examples:
120
     *
121
     * - `[0]content` is used in tabular data input to represent the "content" attribute for the first model in tabular
122
     *    input;
123
     * - `dates[0]` represents the first array element of the "dates" attribute;
124
     * - `[0]dates[0]` represents the first array element of the "dates" attribute for the first model in tabular
125
     *    input.
126
     *
127
     * @param string $attribute the attribute name or expression
128
     *
129
     * @throws InvalidArgumentException if the attribute name contains non-word characters.
130
     *
131
     * @return array
132
     */
133 228
    private static function parseAttribute(string $attribute)
134
    {
135 228
        if (!preg_match('/(^|.*\])([\w\.\+]+)(\[.*|$)/u', $attribute, $matches)) {
136 1
            throw new InvalidArgumentException('Attribute name must contain word characters only.');
137
        }
138
        return [
139 228
            'name' => $matches[2],
140 228
            'prefix' => $matches[1],
141 228
            'suffix' => $matches[3],
142
        ];
143
    }
144
}
145