Skip to content

Commit a256373

Browse files
authored
save work on union type fix (#42)
* save work on union type fix * fix cs * fix return logic * add more tests
1 parent 32d5b78 commit a256373

File tree

6 files changed

+114
-11
lines changed

6 files changed

+114
-11
lines changed

example/classes/SomeTestClass.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,6 @@ class SomeTestClass extends SomeBaseClass
7979
* @var array|SomeOtherTestClass[]
8080
*/
8181
public $someOtherTestClasses;
82+
83+
public int|string $blaaaaaaaa;
8284
}

src/Converter/PhpClassConverter.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace PhpKafka\PhpAvroSchemaGenerator\Converter;
66

7+
use PHP_CodeSniffer\Tokenizers\PHP;
78
use PhpKafka\PhpAvroSchemaGenerator\Avro\Avro;
89
use PhpKafka\PhpAvroSchemaGenerator\Parser\ClassParserInterface;
910
use PhpKafka\PhpAvroSchemaGenerator\PhpClass\PhpClass;
@@ -147,7 +148,7 @@ private function getConvertedUnionType(array $types): array
147148

148149
if (0 !== count($convertedUnionType) && [] !== $arrayType) {
149150
$convertedUnionType[] = $arrayType;
150-
} else {
151+
} elseif (0 === count($convertedUnionType) && [] !== $arrayType) {
151152
return $arrayType;
152153
}
153154

src/Parser/ClassParser.php

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,27 @@ private function getClassProperties(array $statements): array
163163
if ($statement instanceof Namespace_) {
164164
foreach ($statement->stmts as $nsStatement) {
165165
if ($nsStatement instanceof Class_) {
166-
foreach ($nsStatement->stmts as $pStatement) {
167-
if ($pStatement instanceof Property) {
168-
$properties[] = $this->propertyParser->parseProperty($pStatement);
169-
}
170-
}
166+
$properties = $this->getAllClassProperties($nsStatement, $properties);
171167
}
172168
}
169+
} elseif ($statement instanceof Class_) {
170+
$properties = $this->getAllClassProperties($statement, $properties);
171+
}
172+
}
173+
174+
return $properties;
175+
}
176+
177+
/**
178+
* @param Class_ $class
179+
* @param PhpClassPropertyInterface[] $properties
180+
* @return PhpClassPropertyInterface[]
181+
*/
182+
private function getAllClassProperties(Class_ $class, array $properties): array
183+
{
184+
foreach ($class->stmts as $pStatement) {
185+
if ($pStatement instanceof Property) {
186+
$properties[] = $this->propertyParser->parseProperty($pStatement);
173187
}
174188
}
175189

src/Parser/ClassPropertyParser.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PhpKafka\PhpAvroSchemaGenerator\PhpClass\PhpClassPropertyInterface;
1010
use PhpParser\Comment\Doc;
1111
use PhpParser\Node\Identifier;
12+
use PhpParser\Node\NullableType;
1213
use PhpParser\Node\Stmt\Property;
1314
use PhpParser\Node\UnionType;
1415
use RuntimeException;
@@ -80,7 +81,12 @@ private function getPropertyName(Property $property): string
8081
*/
8182
private function getPropertyType(Property $property, array $docComments): string
8283
{
83-
if ($property->type instanceof Identifier) {
84+
if ($property->type instanceof NullableType) {
85+
if ($property->type->type instanceof Identifier) {
86+
$type = Avro::MAPPED_TYPES[$property->type->type->name] ?? $property->type->type->name;
87+
return 'null|' . $type;
88+
}
89+
} elseif ($property->type instanceof Identifier) {
8490
return Avro::MAPPED_TYPES[$property->type->name] ?? $property->type->name;
8591
} elseif ($property->type instanceof UnionType) {
8692
$types = '';
@@ -89,7 +95,7 @@ private function getPropertyType(Property $property, array $docComments): string
8995
foreach ($property->type->types as $type) {
9096
$type = Avro::MAPPED_TYPES[$type->name] ?? $type->name;
9197
$types .= $separator . $type;
92-
$separator = ',';
98+
$separator = '|';
9399
}
94100

95101
return $types;

tests/Integration/Parser/ClassParserTest.php

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function testGetProperties()
5252
$parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser);
5353
$parser->setCode(file_get_contents($filePath));
5454
$properties = $parser->getProperties();
55-
self::assertCount(15, $properties);
55+
self::assertCount(16, $properties);
5656

5757
foreach($properties as $property) {
5858
self::assertInstanceOf(PhpClassPropertyInterface::class, $property);
@@ -84,12 +84,85 @@ public function testClassWithNoParent(): void
8484

8585
}
8686

87+
public function testClassWithNullableType(): void
88+
{
89+
$propertyParser = new ClassPropertyParser(new DocCommentParser());
90+
$parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser);
91+
$parser->setCode('
92+
<?php
93+
class foo {
94+
public ?string $bla;
95+
}
96+
');
97+
$properties = $parser->getProperties();
98+
self::assertEquals(1, count($properties));
99+
self::assertEquals('null|string', $properties[0]->getPropertyType());
100+
}
101+
102+
public function testClassWithUnionType(): void
103+
{
104+
$propertyParser = new ClassPropertyParser(new DocCommentParser());
105+
$parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser);
106+
$parser->setCode('
107+
<?php
108+
class foo {
109+
public int|string $bla;
110+
}
111+
');
112+
$properties = $parser->getProperties();
113+
self::assertEquals(1, count($properties));
114+
self::assertEquals('int|string', $properties[0]->getPropertyType());
115+
}
116+
117+
public function testClassWithDocUnionType(): void
118+
{
119+
$propertyParser = new ClassPropertyParser(new DocCommentParser());
120+
$parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser);
121+
$parser->setCode('
122+
<?php
123+
class foo {
124+
/**
125+
* @var int|string
126+
*/
127+
public $bla;
128+
}
129+
');
130+
$properties = $parser->getProperties();
131+
self::assertEquals(1, count($properties));
132+
self::assertEquals('int|string', $properties[0]->getPropertyType());
133+
}
134+
135+
public function testClassWithAnnotations(): void
136+
{
137+
$propertyParser = new ClassPropertyParser(new DocCommentParser());
138+
$parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser);
139+
$parser->setCode('
140+
<?php
141+
class foo {
142+
/**
143+
* @avro-type string
144+
* @avro-default abc def
145+
* @avro-doc some doc bla bla
146+
* @var int|string
147+
*/
148+
public $bla;
149+
}
150+
');
151+
$properties = $parser->getProperties();
152+
self::assertEquals(1, count($properties));
153+
self::assertEquals('string', $properties[0]->getPropertyType());
154+
self::assertEquals('abc def', $properties[0]->getPropertyDefault());
155+
self::assertEquals('some doc bla bla', $properties[0]->getPropertyDoc());
156+
157+
}
158+
87159
public function testClassWithNoParentFile(): void
88160
{
89161
$propertyParser = new ClassPropertyParser(new DocCommentParser());
90162
$parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser);
91163
$parser->setCode('<?php class foo extends \RuntimeException {private $x;}');
92-
self::assertEquals([], $parser->getProperties());
93-
164+
$properties = $parser->getProperties();
165+
self::assertEquals(1, count($properties));
166+
self::assertEquals('string', $properties[0]->getPropertyType());
94167
}
95168
}

tests/Unit/Parser/ClassPropertyParserTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PhpKafka\PhpAvroSchemaGenerator\PhpClass\PhpClassPropertyInterface;
1010
use PhpParser\Comment\Doc;
1111
use PhpParser\Node\Identifier;
12+
use PhpParser\Node\NullableType;
1213
use PhpParser\Node\Stmt\Property;
1314
use PhpParser\Node\Stmt\PropertyProperty;
1415
use PhpParser\Node\UnionType;
@@ -28,6 +29,8 @@ public function testParseProperty(): void
2829
$ut->types = [$identifier];
2930
$propertyProperty = $this->getMockBuilder(PropertyProperty::class)->disableOriginalConstructor()->getMock();
3031
$propertyProperty->name = $varId;
32+
$nullableType = $this->getMockBuilder(NullableType::class)->disableOriginalConstructor()->getMock();
33+
$nullableType->type = $identifier;
3134
$doc->expects(self::once())->method('getText')->willReturn('bla');
3235
$docParser = $this->getMockForAbstractClass(DocCommentParserInterface::class);
3336
$property1 = $this->getMockBuilder(Property::class)->disableOriginalConstructor()->getMock();
@@ -40,11 +43,15 @@ public function testParseProperty(): void
4043
$property3 = $this->getMockBuilder(Property::class)->disableOriginalConstructor()->getMock();
4144
$property3->type = $ut;
4245
$property3->props = [$propertyProperty];
46+
$property4 = $this->getMockBuilder(Property::class)->disableOriginalConstructor()->getMock();
47+
$property4->type = $nullableType;
48+
$property4->props = [$propertyProperty];
4349
$cpp = new ClassPropertyParser($docParser);
4450

4551
self::assertInstanceOf(PhpClassPropertyInterface::class, $cpp->parseProperty($property1));
4652
self::assertInstanceOf(PhpClassPropertyInterface::class, $cpp->parseProperty($property2));
4753
self::assertInstanceOf(PhpClassPropertyInterface::class, $cpp->parseProperty($property3));
54+
self::assertInstanceOf(PhpClassPropertyInterface::class, $cpp->parseProperty($property4));
4855
}
4956

5057
public function testParsePropertyExceptionOnNonProperty(): void

0 commit comments

Comments
 (0)