Skip to content

Commit 65c7e13

Browse files
mtarldfabpot
authored andcommitted
[TypeInfo] Add Type::traverse() method
1 parent 6872336 commit 65c7e13

File tree

3 files changed

+64
-0
lines changed

3 files changed

+64
-0
lines changed

src/Symfony/Component/TypeInfo/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ CHANGELOG
1111
* Add type alias support in `TypeContext` and `StringTypeResolver`
1212
* Add `CollectionType::mergeCollectionValueTypes()` method
1313
* Add `ArrayShapeType` to represent the exact shape of an array
14+
* Add `Type::traverse()` method
1415

1516
7.2
1617
---

src/Symfony/Component/TypeInfo/Tests/TypeTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,44 @@ public function testIsNullable()
3434

3535
$this->assertFalse(Type::int()->isNullable());
3636
}
37+
38+
public function testTraverse()
39+
{
40+
$this->assertEquals([Type::int()], iterator_to_array(Type::int()->traverse()));
41+
42+
$this->assertEquals(
43+
[Type::union(Type::int(), Type::string()), Type::int(), Type::string()],
44+
iterator_to_array(Type::union(Type::int(), Type::string())->traverse()),
45+
);
46+
$this->assertEquals(
47+
[Type::union(Type::int(), Type::string())],
48+
iterator_to_array(Type::union(Type::int(), Type::string())->traverse(traverseComposite: false)),
49+
);
50+
51+
$this->assertEquals(
52+
[Type::generic(Type::object(\Traversable::class), Type::string()), Type::object(\Traversable::class)],
53+
iterator_to_array(Type::generic(Type::object(\Traversable::class), Type::string())->traverse()),
54+
);
55+
$this->assertEquals(
56+
[Type::generic(Type::object(\Traversable::class), Type::string())],
57+
iterator_to_array(Type::generic(Type::object(\Traversable::class), Type::string())->traverse(traverseWrapped: false)),
58+
);
59+
60+
$this->assertEquals(
61+
[Type::nullable(Type::int()), Type::int(), Type::null()],
62+
iterator_to_array(Type::nullable(Type::int())->traverse()),
63+
);
64+
$this->assertEquals(
65+
[Type::nullable(Type::int()), Type::int()],
66+
iterator_to_array(Type::nullable(Type::int())->traverse(traverseComposite: false)),
67+
);
68+
$this->assertEquals(
69+
[Type::nullable(Type::int()), Type::int(), Type::null()],
70+
iterator_to_array(Type::nullable(Type::int())->traverse(traverseWrapped: false)),
71+
);
72+
$this->assertEquals(
73+
[Type::nullable(Type::int())],
74+
iterator_to_array(Type::nullable(Type::int())->traverse(traverseComposite: false, traverseWrapped: false)),
75+
);
76+
}
3777
}

src/Symfony/Component/TypeInfo/Type.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,27 @@ public function accepts(mixed $value): bool
7676

7777
return $this->isSatisfiedBy($specification);
7878
}
79+
80+
/**
81+
* Traverses the whole type tree.
82+
*
83+
* @return iterable<self>
84+
*/
85+
public function traverse(bool $traverseComposite = true, bool $traverseWrapped = true): iterable
86+
{
87+
yield $this;
88+
89+
if ($this instanceof CompositeTypeInterface && $traverseComposite) {
90+
foreach ($this->getTypes() as $type) {
91+
yield $type;
92+
}
93+
94+
// prevent yielding twice when having a type that is both composite and wrapped
95+
return;
96+
}
97+
98+
if ($this instanceof WrappingTypeInterface && $traverseWrapped) {
99+
yield $this->getWrappedType();
100+
}
101+
}
79102
}

0 commit comments

Comments
 (0)