Skip to content

Commit 9382d98

Browse files
authored
Merge pull request #245 from gsteel/attributes-inference-improvement
Improve type inference for element attributes
2 parents 943ece1 + 835a72b commit 9382d98

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+300
-444
lines changed

Diff for: psalm-baseline.xml

+15-115
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<files psalm-version="5.13.0@a0a9c27630bcf8301ee78cb06741d2907d8c9fef">
2+
<files psalm-version="5.15.0@5c774aca4746caf3d239d9c8cadb9f882ca29352">
33
<file src="src/Annotation/AbstractBuilder.php">
44
<InvalidArrayOffset>
55
<code><![CDATA[$params['elementSpec']['spec']['type']]]></code>
@@ -552,9 +552,6 @@
552552
<code><![CDATA[$inputSpec['validators']]]></code>
553553
<code><![CDATA[$inputSpec['validators']]]></code>
554554
</PossiblyUndefinedArrayOffset>
555-
<UndefinedInterfaceMethod>
556-
<code>getValidator</code>
557-
</UndefinedInterfaceMethod>
558555
</file>
559556
<file src="test/Element/MonthSelectTest.php">
560557
<PossiblyInvalidArrayAccess>
@@ -601,6 +598,14 @@
601598
</UndefinedMethod>
602599
</file>
603600
<file src="test/Element/MultiCheckboxTest.php">
601+
<InvalidArgument>
602+
<code><![CDATA[[
603+
'options' => [
604+
'a' => 'A',
605+
'b' => 'B',
606+
],
607+
]]]></code>
608+
</InvalidArgument>
604609
<PossiblyInvalidArrayAccess>
605610
<code><![CDATA[$inputSpec['validators'][0]]]></code>
606611
<code><![CDATA[$inputSpec['validators'][0]]]></code>
@@ -689,6 +694,12 @@
689694
</UndefinedInterfaceMethod>
690695
</file>
691696
<file src="test/Element/SelectTest.php">
697+
<InvalidArgument>
698+
<code><![CDATA[[
699+
'multiple' => true,
700+
'options' => $valueOptions,
701+
]]]></code>
702+
</InvalidArgument>
692703
<PossiblyInvalidArrayAccess>
693704
<code><![CDATA[$inputSpec['validators'][0]]]></code>
694705
<code><![CDATA[$inputSpec['validators'][0]]]></code>
@@ -1101,9 +1112,6 @@
11011112
<InvalidArgument>
11021113
<code>$element</code>
11031114
</InvalidArgument>
1104-
<PossiblyNullArgument>
1105-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1106-
</PossiblyNullArgument>
11071115
</file>
11081116
<file src="test/View/Helper/FormCaptchaTest.php">
11091117
<PossiblyFalseArgument>
@@ -1120,28 +1128,10 @@
11201128
<code>setView</code>
11211129
</DeprecatedMethod>
11221130
</file>
1123-
<file src="test/View/Helper/FormColorTest.php">
1124-
<PossiblyNullArgument>
1125-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1126-
</PossiblyNullArgument>
1127-
</file>
1128-
<file src="test/View/Helper/FormDateTest.php">
1129-
<PossiblyNullArgument>
1130-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1131-
</PossiblyNullArgument>
1132-
</file>
1133-
<file src="test/View/Helper/FormDateTimeLocalTest.php">
1134-
<PossiblyNullArgument>
1135-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1136-
</PossiblyNullArgument>
1137-
</file>
11381131
<file src="test/View/Helper/FormDateTimeTest.php">
11391132
<DeprecatedClass>
11401133
<code>new FormDateTimeHelper()</code>
11411134
</DeprecatedClass>
1142-
<PossiblyNullArgument>
1143-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1144-
</PossiblyNullArgument>
11451135
</file>
11461136
<file src="test/View/Helper/FormElementTest.php">
11471137
<PossiblyInvalidMethodCall>
@@ -1154,104 +1144,14 @@
11541144
<code>getHash</code>
11551145
</UndefinedInterfaceMethod>
11561146
</file>
1157-
<file src="test/View/Helper/FormEmailTest.php">
1158-
<PossiblyNullArgument>
1159-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1160-
</PossiblyNullArgument>
1161-
</file>
1162-
<file src="test/View/Helper/FormFileTest.php">
1163-
<PossiblyNullArgument>
1164-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1165-
</PossiblyNullArgument>
1166-
</file>
1167-
<file src="test/View/Helper/FormHiddenTest.php">
1168-
<PossiblyNullArgument>
1169-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1170-
</PossiblyNullArgument>
1171-
</file>
1172-
<file src="test/View/Helper/FormImageTest.php">
1173-
<PossiblyNullArgument>
1174-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1175-
</PossiblyNullArgument>
1176-
</file>
1177-
<file src="test/View/Helper/FormInputTest.php">
1178-
<PossiblyNullArgument>
1179-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1180-
</PossiblyNullArgument>
1181-
</file>
11821147
<file src="test/View/Helper/FormLabelTest.php">
11831148
<InvalidArgument>
11841149
<code>$element</code>
11851150
</InvalidArgument>
11861151
</file>
1187-
<file src="test/View/Helper/FormMonthTest.php">
1188-
<PossiblyNullArgument>
1189-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1190-
</PossiblyNullArgument>
1191-
</file>
1192-
<file src="test/View/Helper/FormNumberTest.php">
1193-
<PossiblyNullArgument>
1194-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1195-
</PossiblyNullArgument>
1196-
</file>
1197-
<file src="test/View/Helper/FormPasswordTest.php">
1198-
<PossiblyNullArgument>
1199-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1200-
</PossiblyNullArgument>
1201-
</file>
1202-
<file src="test/View/Helper/FormRangeTest.php">
1203-
<PossiblyNullArgument>
1204-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1205-
</PossiblyNullArgument>
1206-
</file>
1207-
<file src="test/View/Helper/FormResetTest.php">
1208-
<PossiblyNullArgument>
1209-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1210-
</PossiblyNullArgument>
1211-
</file>
12121152
<file src="test/View/Helper/FormRowTest.php">
12131153
<PossiblyInvalidFunctionCall>
12141154
<code>$escapeHelper($label)</code>
12151155
</PossiblyInvalidFunctionCall>
12161156
</file>
1217-
<file src="test/View/Helper/FormSearchTest.php">
1218-
<PossiblyNullArgument>
1219-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1220-
</PossiblyNullArgument>
1221-
</file>
1222-
<file src="test/View/Helper/FormSubmitTest.php">
1223-
<PossiblyNullArgument>
1224-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1225-
</PossiblyNullArgument>
1226-
</file>
1227-
<file src="test/View/Helper/FormTelTest.php">
1228-
<PossiblyNullArgument>
1229-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1230-
</PossiblyNullArgument>
1231-
</file>
1232-
<file src="test/View/Helper/FormTextTest.php">
1233-
<PossiblyNullArgument>
1234-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1235-
</PossiblyNullArgument>
1236-
</file>
1237-
<file src="test/View/Helper/FormTextareaTest.php">
1238-
<PossiblyNullArgument>
1239-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1240-
</PossiblyNullArgument>
1241-
</file>
1242-
<file src="test/View/Helper/FormTimeTest.php">
1243-
<PossiblyNullArgument>
1244-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1245-
</PossiblyNullArgument>
1246-
</file>
1247-
<file src="test/View/Helper/FormUrlTest.php">
1248-
<PossiblyNullArgument>
1249-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1250-
</PossiblyNullArgument>
1251-
</file>
1252-
<file src="test/View/Helper/FormWeekTest.php">
1253-
<PossiblyNullArgument>
1254-
<code><![CDATA[$element->getAttribute($attribute)]]></code>
1255-
</PossiblyNullArgument>
1256-
</file>
12571157
</files>

Diff for: src/Element.php

+15-35
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Traversable;
1010

1111
use function array_key_exists;
12+
use function assert;
1213
use function is_string;
1314

1415
class Element implements
@@ -17,19 +18,19 @@ class Element implements
1718
InitializableInterface,
1819
LabelAwareInterface
1920
{
20-
/** @var array */
21+
/** @var array<string, scalar|null> */
2122
protected $attributes = [];
2223

2324
/** @var null|string */
2425
protected $label;
2526

26-
/** @var array */
27+
/** @var array<string, scalar|null> */
2728
protected $labelAttributes = [];
2829

2930
/**
3031
* Label specific options
3132
*
32-
* @var array
33+
* @var array<string, mixed>
3334
*/
3435
protected $labelOptions = [];
3536

@@ -87,7 +88,10 @@ public function setName(string $name)
8788
*/
8889
public function getName(): ?string
8990
{
90-
return $this->getAttribute('name');
91+
$name = $this->getAttribute('name');
92+
assert(is_string($name) || $name === null);
93+
94+
return $name;
9195
}
9296

9397
/**
@@ -158,12 +162,7 @@ public function setOption(string $key, $value)
158162
return $this;
159163
}
160164

161-
/**
162-
* Set a single element attribute
163-
*
164-
* @param mixed $value
165-
* @return $this
166-
*/
165+
/** @inheritDoc */
167166
public function setAttribute(string $key, $value)
168167
{
169168
// Do not include the value in the list of attributes
@@ -175,11 +174,7 @@ public function setAttribute(string $key, $value)
175174
return $this;
176175
}
177176

178-
/**
179-
* Retrieve a single element attribute
180-
*
181-
* @return mixed|null
182-
*/
177+
/** @inheritDoc */
183178
public function getAttribute(string $key)
184179
{
185180
if (! isset($this->attributes[$key])) {
@@ -209,11 +204,7 @@ public function hasAttribute(string $key): bool
209204
}
210205

211206
/**
212-
* Set many attributes at once
213-
*
214-
* Implementation will decide if this will overwrite or merge.
215-
*
216-
* @return $this
207+
* @inheritDoc
217208
* @throws Exception\InvalidArgumentException
218209
*/
219210
public function setAttributes(iterable $arrayOrTraversable)
@@ -224,9 +215,7 @@ public function setAttributes(iterable $arrayOrTraversable)
224215
return $this;
225216
}
226217

227-
/**
228-
* Retrieve all attributes at once
229-
*/
218+
/** @inheritDoc */
230219
public function getAttributes(): array
231220
{
232221
return $this->attributes;
@@ -235,7 +224,7 @@ public function getAttributes(): array
235224
/**
236225
* Remove many attributes at once
237226
*
238-
* @param array $keys
227+
* @param list<string> $keys
239228
* @return $this
240229
*/
241230
public function removeAttributes(array $keys)
@@ -304,23 +293,14 @@ public function getLabel(): ?string
304293
return $this->label;
305294
}
306295

307-
/**
308-
* Set the attributes to use with the label
309-
*
310-
* @param array $labelAttributes
311-
* @return $this
312-
*/
296+
/** @inheritDoc */
313297
public function setLabelAttributes(array $labelAttributes)
314298
{
315299
$this->labelAttributes = $labelAttributes;
316300
return $this;
317301
}
318302

319-
/**
320-
* Get the attributes to use with the label
321-
*
322-
* @return array
323-
*/
303+
/** @inheritDoc */
324304
public function getLabelAttributes(): array
325305
{
326306
return $this->labelAttributes;

Diff for: src/Element/AbstractDateTime.php

+6-6
Original file line numberDiff line numberDiff line change
@@ -106,41 +106,41 @@ protected function getValidators(): array
106106

107107
if (
108108
isset($this->attributes['min'])
109-
&& $this->valueIsValidDateTimeFormat($this->attributes['min'])
109+
&& $this->valueIsValidDateTimeFormat((string) $this->attributes['min'])
110110
) {
111111
$validators[] = new GreaterThanValidator([
112112
'min' => $this->attributes['min'],
113113
'inclusive' => true,
114114
]);
115115
} elseif (
116116
isset($this->attributes['min'])
117-
&& ! $this->valueIsValidDateTimeFormat($this->attributes['min'])
117+
&& ! $this->valueIsValidDateTimeFormat((string) $this->attributes['min'])
118118
) {
119119
throw new InvalidArgumentException(sprintf(
120120
'%1$s expects "min" to conform to %2$s; received "%3$s"',
121121
__METHOD__,
122122
$this->format,
123-
$this->attributes['min']
123+
(string) $this->attributes['min']
124124
));
125125
}
126126

127127
if (
128128
isset($this->attributes['max'])
129-
&& $this->valueIsValidDateTimeFormat($this->attributes['max'])
129+
&& $this->valueIsValidDateTimeFormat((string) $this->attributes['max'])
130130
) {
131131
$validators[] = new LessThanValidator([
132132
'max' => $this->attributes['max'],
133133
'inclusive' => true,
134134
]);
135135
} elseif (
136136
isset($this->attributes['max'])
137-
&& ! $this->valueIsValidDateTimeFormat($this->attributes['max'])
137+
&& ! $this->valueIsValidDateTimeFormat((string) $this->attributes['max'])
138138
) {
139139
throw new InvalidArgumentException(sprintf(
140140
'%1$s expects "max" to conform to %2$s; received "%3$s"',
141141
__METHOD__,
142142
$this->format,
143-
$this->attributes['max']
143+
(string) $this->attributes['max']
144144
));
145145
}
146146
if (

Diff for: src/Element/Button.php

+1-5
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@
88

99
class Button extends Element
1010
{
11-
/**
12-
* Seed attributes
13-
*
14-
* @var array
15-
*/
11+
/** @var array<string, scalar|null> */
1612
protected $attributes = [
1713
'type' => 'button',
1814
];

Diff for: src/Element/Checkbox.php

+1-5
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,7 @@
1111

1212
class Checkbox extends Element implements InputProviderInterface
1313
{
14-
/**
15-
* Seed attributes
16-
*
17-
* @var array
18-
*/
14+
/** @var array<string, scalar|null> */
1915
protected $attributes = [
2016
'type' => 'checkbox',
2117
];

0 commit comments

Comments
 (0)