Skip to content

Commit

Permalink
save work on union type fix (#42)
Browse files Browse the repository at this point in the history
* save work on union type fix

* fix cs

* fix return logic

* add more tests
  • Loading branch information
nick-zh authored Jan 5, 2022
1 parent 32d5b78 commit a256373
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 11 deletions.
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

0 comments on commit a256373

Please sign in to comment.