Skip to content

save work on union type fix #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions example/classes/SomeTestClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,6 @@ class SomeTestClass extends SomeBaseClass
* @var array|SomeOtherTestClass[]
*/
public $someOtherTestClasses;

public int|string $blaaaaaaaa;
}
3 changes: 2 additions & 1 deletion src/Converter/PhpClassConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
24 changes: 19 additions & 5 deletions src/Parser/ClassParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/Parser/ClassPropertyParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 = '';
Expand All @@ -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;
Expand Down
79 changes: 76 additions & 3 deletions tests/Integration/Parser/ClassParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -84,12 +84,85 @@ 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('
<?php
class foo {
public ?string $bla;
}
');
$properties = $parser->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('
<?php
class foo {
public int|string $bla;
}
');
$properties = $parser->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('
<?php
class foo {
/**
* @var int|string
*/
public $bla;
}
');
$properties = $parser->getProperties();
self::assertEquals(1, count($properties));
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('
<?php
class foo {
/**
* @avro-type string
* @avro-default abc def
* @avro-doc some doc bla bla
* @var int|string
*/
public $bla;
}
');
$properties = $parser->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());
$parser = new ClassParser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), $propertyParser);
$parser->setCode('<?php class foo extends \RuntimeException {private $x;}');
self::assertEquals([], $parser->getProperties());

$properties = $parser->getProperties();
self::assertEquals(1, count($properties));
self::assertEquals('string', $properties[0]->getPropertyType());
}
}
7 changes: 7 additions & 0 deletions tests/Unit/Parser/ClassPropertyParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand All @@ -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
Expand Down