Passed
Pull Request — master (#192)
by Alexander
05:47 queued 02:55
created

HtmlForm   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 179
Duplicated Lines 0 %

Test Coverage

Coverage 93.33%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 24
c 2
b 0
f 0
dl 0
loc 179
ccs 28
cts 30
cp 0.9333
rs 10
wmc 13

8 Methods

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