|
6 | 6 | use Composer\Semver\VersionParser;
|
7 | 7 | use DateTime;
|
8 | 8 | use DateTimeImmutable;
|
9 |
| -use Doctrine\Common\Collections\ArrayCollection; |
10 |
| -use Doctrine\ORM\EntityManagerInterface; |
11 | 9 | use Doctrine\ORM\Mapping\Column;
|
12 |
| -use Doctrine\ORM\Query\AST\TypedExpression; |
13 |
| -use Doctrine\ORM\Tools\SchemaTool; |
14 |
| -use PHPStan\Testing\PHPStanTestCase; |
15 |
| -use PHPStan\Type\Accessory\AccessoryNumericStringType; |
16 |
| -use PHPStan\Type\Constant\ConstantArrayTypeBuilder; |
17 | 10 | use PHPStan\Type\Constant\ConstantIntegerType;
|
18 | 11 | use PHPStan\Type\Constant\ConstantStringType;
|
19 |
| -use PHPStan\Type\ConstantTypeHelper; |
20 |
| -use PHPStan\Type\Doctrine\DescriptorRegistry; |
21 | 12 | use PHPStan\Type\FloatType;
|
22 |
| -use PHPStan\Type\IntegerRangeType; |
23 | 13 | use PHPStan\Type\IntegerType;
|
24 |
| -use PHPStan\Type\IntersectionType; |
25 | 14 | use PHPStan\Type\MixedType;
|
26 | 15 | use PHPStan\Type\NullType;
|
27 | 16 | use PHPStan\Type\ObjectType;
|
28 | 17 | use PHPStan\Type\StringType;
|
29 | 18 | use PHPStan\Type\Type;
|
30 | 19 | use PHPStan\Type\TypeCombinator;
|
31 |
| -use PHPStan\Type\UnionType; |
32 |
| -use PHPStan\Type\VerbosityLevel; |
33 |
| -use QueryResult\Entities\Embedded; |
34 |
| -use QueryResult\Entities\JoinedChild; |
35 | 20 | use QueryResult\Entities\Many;
|
36 | 21 | use QueryResult\Entities\ManyId;
|
37 |
| -use QueryResult\Entities\NestedEmbedded; |
38 | 22 | use QueryResult\Entities\One;
|
39 | 23 | use QueryResult\Entities\OneId;
|
40 |
| -use QueryResult\Entities\SingleTableChild; |
41 |
| -use QueryResult\EntitiesEnum\EntityWithEnum; |
42 | 24 | use QueryResult\EntitiesEnum\IntEnum;
|
43 | 25 | use QueryResult\EntitiesEnum\StringEnum;
|
44 |
| -use Throwable; |
45 |
| -use function array_merge; |
46 |
| -use function array_shift; |
47 | 26 | use function assert;
|
48 | 27 | use function class_exists;
|
49 |
| -use function count; |
50 | 28 | use function property_exists;
|
51 |
| -use function sprintf; |
52 | 29 | use function strpos;
|
53 |
| -use function version_compare; |
54 | 30 | use const PHP_VERSION_ID;
|
55 | 31 |
|
56 |
| -final class QueryResultTypeWalkerTest extends PHPStanTestCase |
| 32 | +final class PDOQueryResultTypeWalkerTest extends QueryResultTypeWalkerTestCase |
57 | 33 | {
|
58 | 34 |
|
59 |
| - /** @var EntityManagerInterface */ |
60 |
| - private static $em; |
61 |
| - |
62 |
| - /** @var DescriptorRegistry */ |
63 |
| - private $descriptorRegistry; |
64 |
| - |
65 |
| - public static function getAdditionalConfigFiles(): array |
66 |
| - { |
67 |
| - return [ |
68 |
| - __DIR__ . '/../data/QueryResult/config.neon', |
69 |
| - ]; |
70 |
| - } |
71 |
| - |
72 |
| - public static function setUpBeforeClass(): void |
73 |
| - { |
74 |
| - $em = require __DIR__ . '/../data/QueryResult/entity-manager.php'; |
75 |
| - self::$em = $em; |
76 |
| - |
77 |
| - $schemaTool = new SchemaTool($em); |
78 |
| - $classes = $em->getMetadataFactory()->getAllMetadata(); |
79 |
| - $schemaTool->createSchema($classes); |
80 |
| - |
81 |
| - $dataOne = [ |
82 |
| - 'intColumn' => [1, 2], |
83 |
| - 'stringColumn' => ['A', 'B'], |
84 |
| - 'stringNullColumn' => ['A', null], |
85 |
| - ]; |
86 |
| - |
87 |
| - $dataMany = [ |
88 |
| - 'intColumn' => [1, 2], |
89 |
| - 'stringColumn' => ['A', 'B'], |
90 |
| - 'stringNullColumn' => ['A', null], |
91 |
| - ]; |
92 |
| - |
93 |
| - $dataJoinedInheritance = [ |
94 |
| - 'parentColumn' => [1, 2], |
95 |
| - 'parentNullColumn' => [1, null], |
96 |
| - 'childColumn' => [1, 2], |
97 |
| - 'childNullColumn' => [1, null], |
98 |
| - ]; |
99 |
| - |
100 |
| - $dataSingleTableInheritance = [ |
101 |
| - 'parentColumn' => [1, 2], |
102 |
| - 'parentNullColumn' => [1, null], |
103 |
| - 'childNullColumn' => [1, null], |
104 |
| - ]; |
105 |
| - |
106 |
| - $id = 1; |
107 |
| - |
108 |
| - foreach (self::combinations($dataOne) as $combination) { |
109 |
| - [$intColumn, $stringColumn, $stringNullColumn] = $combination; |
110 |
| - $one = new One(); |
111 |
| - $one->id = (string) $id++; |
112 |
| - $one->intColumn = $intColumn; |
113 |
| - $one->stringColumn = $stringColumn; |
114 |
| - $one->stringNullColumn = $stringNullColumn; |
115 |
| - $embedded = new Embedded(); |
116 |
| - $embedded->intColumn = $intColumn; |
117 |
| - $embedded->stringColumn = $stringColumn; |
118 |
| - $embedded->stringNullColumn = $stringNullColumn; |
119 |
| - $nestedEmbedded = new NestedEmbedded(); |
120 |
| - $nestedEmbedded->intColumn = $intColumn; |
121 |
| - $nestedEmbedded->stringColumn = $stringColumn; |
122 |
| - $nestedEmbedded->stringNullColumn = $stringNullColumn; |
123 |
| - $embedded->nestedEmbedded = $nestedEmbedded; |
124 |
| - $one->embedded = $embedded; |
125 |
| - $one->manies = new ArrayCollection(); |
126 |
| - |
127 |
| - foreach (self::combinations($dataMany) as $combinationMany) { |
128 |
| - [$intColumnMany, $stringColumnMany, $stringNullColumnMany] = $combinationMany; |
129 |
| - $many = new Many(); |
130 |
| - $many->id = (string) $id++; |
131 |
| - $many->intColumn = $intColumnMany; |
132 |
| - $many->stringColumn = $stringColumnMany; |
133 |
| - $many->stringNullColumn = $stringNullColumnMany; |
134 |
| - $many->datetimeColumn = new DateTime('2001-01-01 00:00:00'); |
135 |
| - $many->datetimeImmutableColumn = new DateTimeImmutable('2001-01-01 00:00:00'); |
136 |
| - $many->simpleArrayColumn = ['foo']; |
137 |
| - $many->one = $one; |
138 |
| - $one->manies->add($many); |
139 |
| - $em->persist($many); |
140 |
| - } |
141 |
| - |
142 |
| - $em->persist($one); |
143 |
| - } |
144 |
| - |
145 |
| - foreach (self::combinations($dataJoinedInheritance) as $combination) { |
146 |
| - [$parentColumn, $parentNullColumn, $childColumn, $childNullColumn] = $combination; |
147 |
| - $child = new JoinedChild(); |
148 |
| - $child->id = (string) $id++; |
149 |
| - $child->parentColumn = $parentColumn; |
150 |
| - $child->parentNullColumn = $parentNullColumn; |
151 |
| - $child->childColumn = $childColumn; |
152 |
| - $child->childNullColumn = $childNullColumn; |
153 |
| - $em->persist($child); |
154 |
| - } |
155 |
| - |
156 |
| - foreach (self::combinations($dataSingleTableInheritance) as $combination) { |
157 |
| - [$parentColumn, $parentNullColumn, $childNullColumn] = $combination; |
158 |
| - $child = new SingleTableChild(); |
159 |
| - $child->id = (string) $id++; |
160 |
| - $child->parentColumn = $parentColumn; |
161 |
| - $child->parentNullColumn = $parentNullColumn; |
162 |
| - $child->childNullColumn = $childNullColumn; |
163 |
| - $em->persist($child); |
164 |
| - } |
165 |
| - |
166 |
| - if (property_exists(Column::class, 'enumType') && PHP_VERSION_ID >= 80100) { |
167 |
| - assert(class_exists(StringEnum::class)); |
168 |
| - assert(class_exists(IntEnum::class)); |
169 |
| - |
170 |
| - $entityWithEnum = new EntityWithEnum(); |
171 |
| - $entityWithEnum->id = '1'; |
172 |
| - $entityWithEnum->stringEnumColumn = StringEnum::A; |
173 |
| - $entityWithEnum->intEnumColumn = IntEnum::A; |
174 |
| - $entityWithEnum->intEnumOnStringColumn = IntEnum::A; |
175 |
| - $em->persist($entityWithEnum); |
176 |
| - } |
177 |
| - |
178 |
| - $em->flush(); |
179 |
| - } |
180 |
| - |
181 |
| - public static function tearDownAfterClass(): void |
182 |
| - { |
183 |
| - self::$em->clear(); |
184 |
| - } |
185 |
| - |
186 |
| - public function setUp(): void |
| 35 | + protected static function getEntityManagerPath(): string |
187 | 36 | {
|
188 |
| - $this->descriptorRegistry = self::getContainer()->getByType(DescriptorRegistry::class); |
189 |
| - } |
190 |
| - |
191 |
| - /** @dataProvider getTestData */ |
192 |
| - public function test(Type $expectedType, string $dql, ?string $expectedExceptionMessage = null, ?string $expectedDeprecationMessage = null): void |
193 |
| - { |
194 |
| - $em = self::$em; |
195 |
| - |
196 |
| - $query = $em->createQuery($dql); |
197 |
| - |
198 |
| - $typeBuilder = new QueryResultTypeBuilder(); |
199 |
| - |
200 |
| - if ($expectedExceptionMessage !== null) { |
201 |
| - $this->expectException(Throwable::class); |
202 |
| - $this->expectExceptionMessage($expectedExceptionMessage); |
203 |
| - } elseif ($expectedDeprecationMessage !== null) { |
204 |
| - $this->expectDeprecation(); |
205 |
| - $this->expectDeprecationMessage($expectedDeprecationMessage); |
206 |
| - } |
207 |
| - |
208 |
| - QueryResultTypeWalker::walk($query, $typeBuilder, $this->descriptorRegistry); |
209 |
| - |
210 |
| - $type = $typeBuilder->getResultType(); |
211 |
| - |
212 |
| - self::assertSame( |
213 |
| - $expectedType->describe(VerbosityLevel::precise()), |
214 |
| - $type->describe(VerbosityLevel::precise()) |
215 |
| - ); |
216 |
| - |
217 |
| - // Double-check our expectations |
218 |
| - |
219 |
| - $query = $em->createQuery($dql); |
220 |
| - |
221 |
| - $result = $query->getResult(); |
222 |
| - self::assertGreaterThan(0, count($result)); |
223 |
| - |
224 |
| - foreach ($result as $row) { |
225 |
| - $rowType = ConstantTypeHelper::getTypeFromValue($row); |
226 |
| - self::assertTrue( |
227 |
| - $type->accepts($rowType, true)->yes(), |
228 |
| - sprintf( |
229 |
| - "The inferred type\n%s\nshould accept actual type\n%s", |
230 |
| - $type->describe(VerbosityLevel::precise()), |
231 |
| - $rowType->describe(VerbosityLevel::precise()) |
232 |
| - ) |
233 |
| - ); |
234 |
| - } |
| 37 | + return __DIR__ . '/../data/QueryResult/entity-manager.php'; |
235 | 38 | }
|
236 | 39 |
|
237 | 40 | /**
|
@@ -1591,113 +1394,4 @@ public function getTestData(): iterable
|
1591 | 1394 | ];
|
1592 | 1395 | }
|
1593 | 1396 |
|
1594 |
| - /** |
1595 |
| - * @param array<int,array{0: ConstantIntegerType|ConstantStringType, 1: Type, 2?: bool}> $elements |
1596 |
| - */ |
1597 |
| - private function constantArray(array $elements): Type |
1598 |
| - { |
1599 |
| - $builder = ConstantArrayTypeBuilder::createEmpty(); |
1600 |
| - |
1601 |
| - foreach ($elements as $element) { |
1602 |
| - $offsetType = $element[0]; |
1603 |
| - $valueType = $element[1]; |
1604 |
| - $optional = $element[2] ?? false; |
1605 |
| - $builder->setOffsetValueType($offsetType, $valueType, $optional); |
1606 |
| - } |
1607 |
| - |
1608 |
| - return $builder->getArray(); |
1609 |
| - } |
1610 |
| - |
1611 |
| - private function numericStringOrInt(): Type |
1612 |
| - { |
1613 |
| - return new UnionType([ |
1614 |
| - new IntegerType(), |
1615 |
| - new IntersectionType([ |
1616 |
| - new StringType(), |
1617 |
| - new AccessoryNumericStringType(), |
1618 |
| - ]), |
1619 |
| - ]); |
1620 |
| - } |
1621 |
| - |
1622 |
| - private function numericString(): Type |
1623 |
| - { |
1624 |
| - return new IntersectionType([ |
1625 |
| - new StringType(), |
1626 |
| - new AccessoryNumericStringType(), |
1627 |
| - ]); |
1628 |
| - } |
1629 |
| - |
1630 |
| - private function uint(): Type |
1631 |
| - { |
1632 |
| - return IntegerRangeType::fromInterval(0, null); |
1633 |
| - } |
1634 |
| - |
1635 |
| - private function intStringified(): Type |
1636 |
| - { |
1637 |
| - return TypeCombinator::union( |
1638 |
| - new IntegerType(), |
1639 |
| - $this->numericString() |
1640 |
| - ); |
1641 |
| - } |
1642 |
| - private function uintStringified(): Type |
1643 |
| - { |
1644 |
| - return TypeCombinator::union( |
1645 |
| - $this->uint(), |
1646 |
| - $this->numericString() |
1647 |
| - ); |
1648 |
| - } |
1649 |
| - |
1650 |
| - private function numericStringified(): Type |
1651 |
| - { |
1652 |
| - return TypeCombinator::union( |
1653 |
| - new FloatType(), |
1654 |
| - new IntegerType(), |
1655 |
| - $this->numericString() |
1656 |
| - ); |
1657 |
| - } |
1658 |
| - |
1659 |
| - private function unumericStringified(): Type |
1660 |
| - { |
1661 |
| - return TypeCombinator::union( |
1662 |
| - new FloatType(), |
1663 |
| - IntegerRangeType::fromInterval(0, null), |
1664 |
| - $this->numericString() |
1665 |
| - ); |
1666 |
| - } |
1667 |
| - |
1668 |
| - private function hasTypedExpressions(): bool |
1669 |
| - { |
1670 |
| - return class_exists(TypedExpression::class); |
1671 |
| - } |
1672 |
| - |
1673 |
| - /** |
1674 |
| - * @param array<mixed[]> $arrays |
1675 |
| - * |
1676 |
| - * @return iterable<mixed[]> |
1677 |
| - */ |
1678 |
| - private static function combinations(array $arrays): iterable |
1679 |
| - { |
1680 |
| - if ($arrays === []) { |
1681 |
| - yield []; |
1682 |
| - return; |
1683 |
| - } |
1684 |
| - |
1685 |
| - $head = array_shift($arrays); |
1686 |
| - |
1687 |
| - foreach ($head as $elem) { |
1688 |
| - foreach (self::combinations($arrays) as $combination) { |
1689 |
| - yield array_merge([$elem], $combination); |
1690 |
| - } |
1691 |
| - } |
1692 |
| - } |
1693 |
| - |
1694 |
| - private function isDoctrine211(): bool |
1695 |
| - { |
1696 |
| - $version = InstalledVersions::getVersion('doctrine/orm'); |
1697 |
| - |
1698 |
| - return $version !== null |
1699 |
| - && version_compare($version, '2.11', '>=') |
1700 |
| - && version_compare($version, '2.12', '<'); |
1701 |
| - } |
1702 |
| - |
1703 | 1397 | }
|
0 commit comments