From bb2d1ea411f95e1aaf5c0e7efc7b18c54695f1d9 Mon Sep 17 00:00:00 2001 From: Nick Chiu Date: Wed, 5 Jan 2022 23:47:17 +0100 Subject: [PATCH 1/4] save work on union type fix --- example/classes/SomeTestClass.php | 2 + src/Parser/ClassParser.php | 24 ++++++-- src/Parser/ClassPropertyParser.php | 10 +++- tests/Integration/Parser/ClassParserTest.php | 55 ++++++++++++++++++- tests/Unit/Parser/ClassPropertyParserTest.php | 7 +++ 5 files changed, 88 insertions(+), 10 deletions(-) diff --git a/example/classes/SomeTestClass.php b/example/classes/SomeTestClass.php index c2fe8ac..84d428f 100644 --- a/example/classes/SomeTestClass.php +++ b/example/classes/SomeTestClass.php @@ -79,4 +79,6 @@ class SomeTestClass extends SomeBaseClass * @var array|SomeOtherTestClass[] */ public $someOtherTestClasses; + + public int|string $blaaaaaaaa; } diff --git a/src/Parser/ClassParser.php b/src/Parser/ClassParser.php index e23a069..4574c55 100644 --- a/src/Parser/ClassParser.php +++ b/src/Parser/ClassParser.php @@ -163,13 +163,27 @@ private function getClassProperties(array $statements): array if ($statement instanceof Namespace_) { foreach ($statement->stmts as $nsStatement) { if ($nsStatement instanceof Class_) { - foreach ($nsStatement->stmts as $pStatement) { - if ($pStatement instanceof Property) { - $properties[] = $this->propertyParser->parseProperty($pStatement); - } - } + $properties = $this->getAllClassProperties($nsStatement, $properties); } } + } elseif ($statement instanceof Class_) { + $properties = $this->getAllClassProperties($statement, $properties); + } + } + + return $properties; + } + + /** + * @param Class_ $class + * @param PhpClassPropertyInterface[] $properties + * @return PhpClassPropertyInterface[] + */ + private function getAllClassProperties(Class_ $class, array $properties): array { + + foreach ($class->stmts as $pStatement) { + if ($pStatement instanceof Property) { + $properties[] = $this->propertyParser->parseProperty($pStatement); } } diff --git a/src/Parser/ClassPropertyParser.php b/src/Parser/ClassPropertyParser.php index 870632f..c90e08f 100644 --- a/src/Parser/ClassPropertyParser.php +++ b/src/Parser/ClassPropertyParser.php @@ -9,6 +9,7 @@ use PhpKafka\PhpAvroSchemaGenerator\PhpClass\PhpClassPropertyInterface; use PhpParser\Comment\Doc; use PhpParser\Node\Identifier; +use PhpParser\Node\NullableType; use PhpParser\Node\Stmt\Property; use PhpParser\Node\UnionType; use RuntimeException; @@ -80,7 +81,12 @@ private function getPropertyName(Property $property): string */ private function getPropertyType(Property $property, array $docComments): string { - if ($property->type instanceof Identifier) { + if ($property->type instanceof NullableType) { + if ($property->type->type instanceof Identifier) { + $type = Avro::MAPPED_TYPES[$property->type->type->name] ?? $property->type->type->name; + return 'null|' . $type; + } + } elseif ($property->type instanceof Identifier) { return Avro::MAPPED_TYPES[$property->type->name] ?? $property->type->name; } elseif ($property->type instanceof UnionType) { $types = ''; @@ -89,7 +95,7 @@ private function getPropertyType(Property $property, array $docComments): string foreach ($property->type->types as $type) { $type = Avro::MAPPED_TYPES[$type->name] ?? $type->name; $types .= $separator . $type; - $separator = ','; + $separator = '|'; } return $types; diff --git a/tests/Integration/Parser/ClassParserTest.php b/tests/Integration/Parser/ClassParserTest.php index 7ef9793..ff66347 100644 --- a/tests/Integration/Parser/ClassParserTest.php +++ b/tests/Integration/Parser/ClassParserTest.php @@ -52,7 +52,7 @@ public function testGetProperties() $parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser); $parser->setCode(file_get_contents($filePath)); $properties = $parser->getProperties(); - self::assertCount(15, $properties); + self::assertCount(16, $properties); foreach($properties as $property) { self::assertInstanceOf(PhpClassPropertyInterface::class, $property); @@ -84,12 +84,61 @@ public function testClassWithNoParent(): void } + public function testClassWithNullableType(): void + { + $propertyParser = new ClassPropertyParser(new DocCommentParser()); + $parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser); + $parser->setCode(' + getProperties(); + self::assertEquals(1, count($properties)); + self::assertEquals('null|string', $properties[0]->getPropertyType()); + } + + public function testClassWithUnionType(): void + { + $propertyParser = new ClassPropertyParser(new DocCommentParser()); + $parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser); + $parser->setCode(' + getProperties(); + self::assertEquals(1, count($properties)); + self::assertEquals('int|string', $properties[0]->getPropertyType()); + } + + public function testClassWithDocUnionType(): void + { + $propertyParser = new ClassPropertyParser(new DocCommentParser()); + $parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser); + $parser->setCode(' + getProperties(); + self::assertEquals(1, count($properties)); + self::assertEquals('int|string', $properties[0]->getPropertyType()); + } + public function testClassWithNoParentFile(): void { $propertyParser = new ClassPropertyParser(new DocCommentParser()); $parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser); $parser->setCode('getProperties()); - + $properties = $parser->getProperties(); + self::assertEquals(1, count($properties)); + self::assertEquals('string', $properties[0]->getPropertyType()); } } diff --git a/tests/Unit/Parser/ClassPropertyParserTest.php b/tests/Unit/Parser/ClassPropertyParserTest.php index 5566342..1811e1f 100644 --- a/tests/Unit/Parser/ClassPropertyParserTest.php +++ b/tests/Unit/Parser/ClassPropertyParserTest.php @@ -9,6 +9,7 @@ use PhpKafka\PhpAvroSchemaGenerator\PhpClass\PhpClassPropertyInterface; use PhpParser\Comment\Doc; use PhpParser\Node\Identifier; +use PhpParser\Node\NullableType; use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\PropertyProperty; use PhpParser\Node\UnionType; @@ -28,6 +29,8 @@ public function testParseProperty(): void $ut->types = [$identifier]; $propertyProperty = $this->getMockBuilder(PropertyProperty::class)->disableOriginalConstructor()->getMock(); $propertyProperty->name = $varId; + $nullableType = $this->getMockBuilder(NullableType::class)->disableOriginalConstructor()->getMock(); + $nullableType->type = $identifier; $doc->expects(self::once())->method('getText')->willReturn('bla'); $docParser = $this->getMockForAbstractClass(DocCommentParserInterface::class); $property1 = $this->getMockBuilder(Property::class)->disableOriginalConstructor()->getMock(); @@ -40,11 +43,15 @@ public function testParseProperty(): void $property3 = $this->getMockBuilder(Property::class)->disableOriginalConstructor()->getMock(); $property3->type = $ut; $property3->props = [$propertyProperty]; + $property4 = $this->getMockBuilder(Property::class)->disableOriginalConstructor()->getMock(); + $property4->type = $nullableType; + $property4->props = [$propertyProperty]; $cpp = new ClassPropertyParser($docParser); self::assertInstanceOf(PhpClassPropertyInterface::class, $cpp->parseProperty($property1)); self::assertInstanceOf(PhpClassPropertyInterface::class, $cpp->parseProperty($property2)); self::assertInstanceOf(PhpClassPropertyInterface::class, $cpp->parseProperty($property3)); + self::assertInstanceOf(PhpClassPropertyInterface::class, $cpp->parseProperty($property4)); } public function testParsePropertyExceptionOnNonProperty(): void From 463c62dea3133c7ff3f7379d31d8858d4b4d3acc Mon Sep 17 00:00:00 2001 From: Nick Chiu Date: Wed, 5 Jan 2022 23:54:43 +0100 Subject: [PATCH 2/4] fix cs --- src/Parser/ClassParser.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Parser/ClassParser.php b/src/Parser/ClassParser.php index 4574c55..323f266 100644 --- a/src/Parser/ClassParser.php +++ b/src/Parser/ClassParser.php @@ -179,8 +179,8 @@ private function getClassProperties(array $statements): array * @param PhpClassPropertyInterface[] $properties * @return PhpClassPropertyInterface[] */ - private function getAllClassProperties(Class_ $class, array $properties): array { - + private function getAllClassProperties(Class_ $class, array $properties): array + { foreach ($class->stmts as $pStatement) { if ($pStatement instanceof Property) { $properties[] = $this->propertyParser->parseProperty($pStatement); From 936adc02ff17f7315e54ed50738bc6aa691b810a Mon Sep 17 00:00:00 2001 From: Nick Chiu Date: Thu, 6 Jan 2022 00:10:38 +0100 Subject: [PATCH 3/4] fix return logic --- src/Converter/PhpClassConverter.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Converter/PhpClassConverter.php b/src/Converter/PhpClassConverter.php index 9fab08e..a2f2778 100644 --- a/src/Converter/PhpClassConverter.php +++ b/src/Converter/PhpClassConverter.php @@ -4,6 +4,7 @@ namespace PhpKafka\PhpAvroSchemaGenerator\Converter; +use PHP_CodeSniffer\Tokenizers\PHP; use PhpKafka\PhpAvroSchemaGenerator\Avro\Avro; use PhpKafka\PhpAvroSchemaGenerator\Parser\ClassParserInterface; use PhpKafka\PhpAvroSchemaGenerator\PhpClass\PhpClass; @@ -147,7 +148,7 @@ private function getConvertedUnionType(array $types): array if (0 !== count($convertedUnionType) && [] !== $arrayType) { $convertedUnionType[] = $arrayType; - } else { + } elseif (0 === count($convertedUnionType) && [] !== $arrayType) { return $arrayType; } From 9c622049347b1f0d15319aa11e5b6e26be5e99b2 Mon Sep 17 00:00:00 2001 From: Nick Chiu Date: Thu, 6 Jan 2022 00:17:32 +0100 Subject: [PATCH 4/4] add more tests --- tests/Integration/Parser/ClassParserTest.php | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/Integration/Parser/ClassParserTest.php b/tests/Integration/Parser/ClassParserTest.php index ff66347..ccf267c 100644 --- a/tests/Integration/Parser/ClassParserTest.php +++ b/tests/Integration/Parser/ClassParserTest.php @@ -132,6 +132,30 @@ class foo { self::assertEquals('int|string', $properties[0]->getPropertyType()); } + public function testClassWithAnnotations(): void + { + $propertyParser = new ClassPropertyParser(new DocCommentParser()); + $parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser); + $parser->setCode(' + getProperties(); + self::assertEquals(1, count($properties)); + self::assertEquals('string', $properties[0]->getPropertyType()); + self::assertEquals('abc def', $properties[0]->getPropertyDefault()); + self::assertEquals('some doc bla bla', $properties[0]->getPropertyDoc()); + + } + public function testClassWithNoParentFile(): void { $propertyParser = new ClassPropertyParser(new DocCommentParser());