Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 547cb46

Browse filesBrowse files
committed
[TypeInfo] Add accepts method
1 parent 78f4d9a commit 547cb46
Copy full SHA for 547cb46

16 files changed

+265
-0
lines changed

‎src/Symfony/Component/TypeInfo/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/CHANGELOG.md
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
7.3
5+
---
6+
7+
* Add `Type::accepts()` method
8+
49
7.2
510
---
611

‎src/Symfony/Component/TypeInfo/Tests/Type/BackedEnumTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Tests/Type/BackedEnumTypeTest.php
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,12 @@ public function testToString()
2929
{
3030
$this->assertSame(DummyBackedEnum::class, (string) new BackedEnumType(DummyBackedEnum::class, Type::int()));
3131
}
32+
33+
public function testAccepts()
34+
{
35+
$type = new BackedEnumType(DummyBackedEnum::class, Type::int());
36+
37+
$this->assertFalse($type->accepts('string'));
38+
$this->assertTrue($type->accepts(DummyBackedEnum::ONE));
39+
}
3240
}

‎src/Symfony/Component/TypeInfo/Tests/Type/BuiltinTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Tests/Type/BuiltinTypeTest.php
+44Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,48 @@ public function testIsNullable()
3939
$this->assertTrue((new BuiltinType(TypeIdentifier::MIXED))->isNullable());
4040
$this->assertFalse((new BuiltinType(TypeIdentifier::INT))->isNullable());
4141
}
42+
43+
public function testAccepts()
44+
{
45+
$this->assertFalse((new BuiltinType(TypeIdentifier::ARRAY))->accepts('string'));
46+
$this->assertTrue((new BuiltinType(TypeIdentifier::ARRAY))->accepts([]));
47+
48+
$this->assertFalse((new BuiltinType(TypeIdentifier::BOOL))->accepts('string'));
49+
$this->assertTrue((new BuiltinType(TypeIdentifier::BOOL))->accepts(true));
50+
51+
$this->assertFalse((new BuiltinType(TypeIdentifier::CALLABLE))->accepts('string'));
52+
$this->assertTrue((new BuiltinType(TypeIdentifier::CALLABLE))->accepts('strtoupper'));
53+
54+
$this->assertFalse((new BuiltinType(TypeIdentifier::FALSE))->accepts('string'));
55+
$this->assertTrue((new BuiltinType(TypeIdentifier::FALSE))->accepts(false));
56+
57+
$this->assertFalse((new BuiltinType(TypeIdentifier::FLOAT))->accepts('string'));
58+
$this->assertTrue((new BuiltinType(TypeIdentifier::FLOAT))->accepts(1.23));
59+
60+
$this->assertFalse((new BuiltinType(TypeIdentifier::INT))->accepts('string'));
61+
$this->assertTrue((new BuiltinType(TypeIdentifier::INT))->accepts(123));
62+
63+
$this->assertFalse((new BuiltinType(TypeIdentifier::ITERABLE))->accepts('string'));
64+
$this->assertTrue((new BuiltinType(TypeIdentifier::ITERABLE))->accepts([]));
65+
66+
$this->assertTrue((new BuiltinType(TypeIdentifier::MIXED))->accepts('string'));
67+
68+
$this->assertFalse((new BuiltinType(TypeIdentifier::NULL))->accepts('string'));
69+
$this->assertTrue((new BuiltinType(TypeIdentifier::NULL))->accepts(null));
70+
71+
$this->assertFalse((new BuiltinType(TypeIdentifier::OBJECT))->accepts('string'));
72+
$this->assertTrue((new BuiltinType(TypeIdentifier::OBJECT))->accepts(new \stdClass()));
73+
74+
$this->assertFalse((new BuiltinType(TypeIdentifier::RESOURCE))->accepts('string'));
75+
$this->assertTrue((new BuiltinType(TypeIdentifier::RESOURCE))->accepts(fopen('php://temp', 'r')));
76+
77+
$this->assertFalse((new BuiltinType(TypeIdentifier::STRING))->accepts(123));
78+
$this->assertTrue((new BuiltinType(TypeIdentifier::STRING))->accepts('string'));
79+
80+
$this->assertFalse((new BuiltinType(TypeIdentifier::TRUE))->accepts('string'));
81+
$this->assertTrue((new BuiltinType(TypeIdentifier::TRUE))->accepts(true));
82+
83+
$this->assertFalse((new BuiltinType(TypeIdentifier::NEVER))->accepts('string'));
84+
$this->assertFalse((new BuiltinType(TypeIdentifier::VOID))->accepts('string'));
85+
}
4286
}

‎src/Symfony/Component/TypeInfo/Tests/Type/CollectionTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Tests/Type/CollectionTypeTest.php
+37Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,41 @@ public function testToString()
8888
$type = new CollectionType(new GenericType(Type::builtin(TypeIdentifier::ARRAY), Type::string(), Type::bool()));
8989
$this->assertEquals('array<string,bool>', (string) $type);
9090
}
91+
92+
public function testAccepts()
93+
{
94+
$type = new CollectionType(Type::generic(Type::builtin(TypeIdentifier::ARRAY), Type::string(), Type::bool()));
95+
96+
$this->assertFalse($type->accepts(new \ArrayObject(['foo' => true, 'bar' => true])));
97+
98+
$this->assertTrue($type->accepts(['foo' => true, 'bar' => true]));
99+
$this->assertFalse($type->accepts(['foo' => true, 'bar' => 123]));
100+
$this->assertFalse($type->accepts([1 => true]));
101+
102+
$type = new CollectionType(Type::generic(Type::builtin(TypeIdentifier::ARRAY), Type::int(), Type::bool()));
103+
104+
$this->assertTrue($type->accepts([1 => true]));
105+
$this->assertFalse($type->accepts(['foo' => true]));
106+
107+
$type = new CollectionType(Type::generic(Type::builtin(TypeIdentifier::ARRAY), Type::int(), Type::bool()), isList: true);
108+
109+
$this->assertTrue($type->accepts([0 => true, 1 => false]));
110+
$this->assertFalse($type->accepts([0 => true, 2 => false]));
111+
112+
$type = new CollectionType(Type::generic(Type::builtin(TypeIdentifier::ITERABLE), Type::string(), Type::bool()));
113+
114+
$this->assertTrue($type->accepts(new \ArrayObject(['foo' => true, 'bar' => true])));
115+
$this->assertFalse($type->accepts(new \ArrayObject(['foo' => true, 'bar' => 123])));
116+
$this->assertFalse($type->accepts(new \ArrayObject([1 => true])));
117+
118+
$type = new CollectionType(Type::generic(Type::builtin(TypeIdentifier::ITERABLE), Type::int(), Type::bool()));
119+
120+
$this->assertTrue($type->accepts(new \ArrayObject([1 => true])));
121+
$this->assertFalse($type->accepts(new \ArrayObject(['foo' => true])));
122+
123+
$type = new CollectionType(Type::generic(Type::builtin(TypeIdentifier::ITERABLE), Type::int(), Type::bool()));
124+
125+
$this->assertTrue($type->accepts(new \ArrayObject([0 => true, 1 => false])));
126+
$this->assertFalse($type->accepts(new \ArrayObject([0 => true, 1 => 'string'])));
127+
}
91128
}

‎src/Symfony/Component/TypeInfo/Tests/Type/EnumTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Tests/Type/EnumTypeTest.php
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,12 @@ public function testToString()
2121
{
2222
$this->assertSame(DummyEnum::class, (string) new EnumType(DummyEnum::class));
2323
}
24+
25+
public function testAccepts()
26+
{
27+
$type = new EnumType(DummyEnum::class);
28+
29+
$this->assertFalse($type->accepts('string'));
30+
$this->assertTrue($type->accepts(DummyEnum::ONE));
31+
}
2432
}

‎src/Symfony/Component/TypeInfo/Tests/Type/GenericTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Tests/Type/GenericTypeTest.php
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,12 @@ public function testWrappedTypeIsSatisfiedBy()
4545
$type = new GenericType(Type::builtin(TypeIdentifier::ITERABLE), Type::bool());
4646
$this->assertFalse($type->wrappedTypeIsSatisfiedBy(static fn (Type $t): bool => 'array' === (string) $t));
4747
}
48+
49+
public function testAccepts()
50+
{
51+
$type = new GenericType(Type::object(self::class), Type::string());
52+
53+
$this->assertFalse($type->accepts('string'));
54+
$this->assertTrue($type->accepts($this));
55+
}
4856
}

‎src/Symfony/Component/TypeInfo/Tests/Type/IntersectionTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Tests/Type/IntersectionTypeTest.php
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,22 @@ public function testToString()
7777
$type = new IntersectionType(Type::object(\DateTime::class), Type::object(\Iterator::class), Type::object(\Stringable::class));
7878
$this->assertSame(\sprintf('%s&%s&%s', \DateTime::class, \Iterator::class, \Stringable::class), (string) $type);
7979
}
80+
81+
public function testAccepts()
82+
{
83+
$type = new IntersectionType(Type::object(\Traversable::class), Type::object(\Countable::class));
84+
85+
$traversableAndCountable = new \ArrayObject();
86+
87+
$countable = new class implements \Countable {
88+
public function count(): int
89+
{
90+
return 1;
91+
}
92+
};
93+
94+
$this->assertFalse($type->accepts('string'));
95+
$this->assertFalse($type->accepts($countable));
96+
$this->assertTrue($type->accepts($traversableAndCountable));
97+
}
8098
}

‎src/Symfony/Component/TypeInfo/Tests/Type/NullableTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Tests/Type/NullableTypeTest.php
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,13 @@ public function testWrappedTypeIsSatisfiedBy()
4141
$type = new NullableType(Type::string());
4242
$this->assertFalse($type->wrappedTypeIsSatisfiedBy(static fn (Type $t): bool => 'int' === (string) $t));
4343
}
44+
45+
public function testAccepts()
46+
{
47+
$type = new NullableType(Type::int());
48+
49+
$this->assertFalse($type->accepts('string'));
50+
$this->assertTrue($type->accepts(123));
51+
$this->assertTrue($type->accepts(null));
52+
}
4453
}

‎src/Symfony/Component/TypeInfo/Tests/Type/ObjectTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Tests/Type/ObjectTypeTest.php
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,12 @@ public function testIsIdentifiedBy()
3535

3636
$this->assertTrue((new ObjectType(self::class))->isIdentifiedBy('array', 'object'));
3737
}
38+
39+
public function testAccepts()
40+
{
41+
$this->assertFalse((new ObjectType(self::class))->accepts('string'));
42+
$this->assertFalse((new ObjectType(self::class))->accepts(new \stdClass()));
43+
$this->assertTrue((new ObjectType(TestCase::class))->accepts($this));
44+
$this->assertTrue((new ObjectType(self::class))->accepts($this));
45+
}
3846
}
+26Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\TypeInfo\Tests\Type;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\TypeInfo\Type\BuiltinType;
16+
use Symfony\Component\TypeInfo\Type\TemplateType;
17+
use Symfony\Component\TypeInfo\TypeIdentifier;
18+
19+
class TemplateTypeTest extends TestCase
20+
{
21+
public function testAccepts()
22+
{
23+
$this->assertFalse((new TemplateType('T', new BuiltinType(TypeIdentifier::BOOL)))->accepts('string'));
24+
$this->assertTrue((new TemplateType('T', new BuiltinType(TypeIdentifier::BOOL)))->accepts(true));
25+
}
26+
}

‎src/Symfony/Component/TypeInfo/Tests/Type/UnionTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Tests/Type/UnionTypeTest.php
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,13 @@ public function testToString()
8585
$type = new UnionType(Type::int(), Type::string(), Type::intersection(Type::object(\DateTime::class), Type::object(\Iterator::class)));
8686
$this->assertSame(\sprintf('(%s&%s)|int|string', \DateTime::class, \Iterator::class), (string) $type);
8787
}
88+
89+
public function testAccepts()
90+
{
91+
$type = new UnionType(Type::int(), Type::bool());
92+
93+
$this->assertFalse($type->accepts('string'));
94+
$this->assertTrue($type->accepts(123));
95+
$this->assertTrue($type->accepts(false));
96+
}
8897
}

‎src/Symfony/Component/TypeInfo/Type.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Type.php
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,24 @@ public function isNullable(): bool
5656
{
5757
return false;
5858
}
59+
60+
/**
61+
* Tells if the type (or one of its wrapped/composed parts) accepts the given $value.
62+
*/
63+
public function accepts(mixed $value): bool
64+
{
65+
$specification = static function (Type $type) use (&$specification, $value): bool {
66+
if ($type instanceof WrappingTypeInterface) {
67+
return $type->wrappedTypeIsSatisfiedBy($specification);
68+
}
69+
70+
if ($type instanceof CompositeTypeInterface) {
71+
return $type->composedTypesAreSatisfiedBy($specification);
72+
}
73+
74+
return $type->accepts($value);
75+
};
76+
77+
return $this->isSatisfiedBy($specification);
78+
}
5979
}

‎src/Symfony/Component/TypeInfo/Type/BuiltinType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Type/BuiltinType.php
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,26 @@ public function isNullable(): bool
6262
return \in_array($this->typeIdentifier, [TypeIdentifier::NULL, TypeIdentifier::MIXED]);
6363
}
6464

65+
public function accepts(mixed $value): bool
66+
{
67+
return match ($this->typeIdentifier) {
68+
TypeIdentifier::ARRAY => \is_array($value),
69+
TypeIdentifier::BOOL => \is_bool($value),
70+
TypeIdentifier::CALLABLE => \is_callable($value),
71+
TypeIdentifier::FALSE => false === $value,
72+
TypeIdentifier::FLOAT => \is_float($value),
73+
TypeIdentifier::INT => \is_int($value),
74+
TypeIdentifier::ITERABLE => is_iterable($value),
75+
TypeIdentifier::MIXED => true,
76+
TypeIdentifier::NULL => null === $value,
77+
TypeIdentifier::OBJECT => \is_object($value),
78+
TypeIdentifier::RESOURCE => \is_resource($value),
79+
TypeIdentifier::STRING => \is_string($value),
80+
TypeIdentifier::TRUE => true === $value,
81+
default => false,
82+
};
83+
}
84+
6585
public function __toString(): string
6686
{
6787
return $this->typeIdentifier->value;

‎src/Symfony/Component/TypeInfo/Type/CollectionType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Type/CollectionType.php
+35Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,41 @@ public function wrappedTypeIsSatisfiedBy(callable $specification): bool
9292
return $this->getWrappedType()->isSatisfiedBy($specification);
9393
}
9494

95+
public function accepts(mixed $value): bool
96+
{
97+
if (!parent::accepts($value)) {
98+
return false;
99+
}
100+
101+
if ($this->isList() && !\is_array($value)) {
102+
return false;
103+
}
104+
105+
if ($this->isList()) {
106+
// only array can be list
107+
if (!\is_array($value)) {
108+
return false;
109+
}
110+
111+
// array is not a list
112+
if (!array_is_list($value)) {
113+
return false;
114+
}
115+
}
116+
117+
$keyType = $this->getCollectionKeyType();
118+
$valueType = $this->getCollectionValueType();
119+
120+
foreach ($value as $k => $v) {
121+
// key or value do not match
122+
if (!$keyType->accepts($k) || !$valueType->accepts($v)) {
123+
return false;
124+
}
125+
}
126+
127+
return true;
128+
}
129+
95130
public function __toString(): string
96131
{
97132
return (string) $this->type;

‎src/Symfony/Component/TypeInfo/Type/NullableType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Type/NullableType.php
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,9 @@ public function isNullable(): bool
5959
{
6060
return true;
6161
}
62+
63+
public function accepts(mixed $value): bool
64+
{
65+
return null === $value || parent::accepts($value);
66+
}
6267
}

‎src/Symfony/Component/TypeInfo/Type/ObjectType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/TypeInfo/Type/ObjectType.php
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ public function isIdentifiedBy(TypeIdentifier|string ...$identifiers): bool
6666
return false;
6767
}
6868

69+
public function accepts(mixed $value): bool
70+
{
71+
return $value instanceof $this->className;
72+
}
73+
6974
public function __toString(): string
7075
{
7176
return $this->className;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.