From 8c03368d5c566ecdf8e4ad3b3b91f9cb00e166b7 Mon Sep 17 00:00:00 2001 From: Francisco Edno Date: Fri, 8 Oct 2021 14:53:27 -0300 Subject: [PATCH 1/4] Add support for php 8 attributes Refactor the current schema generation test case in order to reuse the same logic for schema generation with php 8 attributes. Create a new schema attribute reader for extracting schema info from php attributes. --- .../Generation/Annotations/AvroItems.php | 21 ++++++- .../Generation/Annotations/AvroValues.php | 21 ++++++- .../Annotations/ContainsOnlyTypes.php | 50 ---------------- .../Schema/Generation/AttributeReader.php | 31 ++++++++++ .../Generation/Attributes/AvroAliases.php | 50 ++++++++++++++++ .../Generation/Attributes/AvroDefault.php | 42 ++++++++++++++ .../Schema/Generation/Attributes/AvroDoc.php | 43 ++++++++++++++ .../Generation/Attributes/AvroItems.php | 45 ++++++++++++++ .../Schema/Generation/Attributes/AvroName.php | 33 +++++++++++ .../Generation/Attributes/AvroNamespace.php | 34 +++++++++++ .../Generation/Attributes/AvroOrder.php | 42 ++++++++++++++ .../Schema/Generation/Attributes/AvroSize.php | 42 ++++++++++++++ .../Generation/Attributes/AvroSymbols.php | 50 ++++++++++++++++ .../Generation/Attributes/AvroTargetClass.php | 33 +++++++++++ .../Schema/Generation/Attributes/AvroType.php | 58 +++++++++++++++++++ .../Generation/Attributes/AvroValues.php | 45 ++++++++++++++ .../Schema/Generation/Attributes/Order.php | 12 ++++ .../Schema/Generation/Attributes/Type.php | 31 ++++++++++ .../Schema/Generation/TypeOnlyAttribute.php | 6 ++ .../AnnotationSchemaGeneratorTest.php | 23 ++++++++ .../AttributeSchemaGeneratorTest.php | 16 +++++ .../Fixture/ArraysWithComplexType.php | 30 ++++++++++ .../Schema/Generation/Fixture/EmptyRecord.php | 7 +++ .../Fixture/MapsWithComplexType.php | 28 +++++++++ .../Generation/Fixture/PrimitiveTypes.php | 25 ++++++++ .../Fixture/RecordWithComplexTypes.php | 43 ++++++++++++++ .../Fixture/RecordWithRecordType.php | 18 +++++- .../Generation/Fixture/SimpleRecord.php | 10 ++++ .../Schema/Generation/SchemaGeneratorTest.php | 15 ++--- 29 files changed, 842 insertions(+), 62 deletions(-) delete mode 100644 src/Objects/Schema/Generation/Annotations/ContainsOnlyTypes.php create mode 100644 src/Objects/Schema/Generation/AttributeReader.php create mode 100644 src/Objects/Schema/Generation/Attributes/AvroAliases.php create mode 100644 src/Objects/Schema/Generation/Attributes/AvroDefault.php create mode 100644 src/Objects/Schema/Generation/Attributes/AvroDoc.php create mode 100644 src/Objects/Schema/Generation/Attributes/AvroItems.php create mode 100644 src/Objects/Schema/Generation/Attributes/AvroName.php create mode 100644 src/Objects/Schema/Generation/Attributes/AvroNamespace.php create mode 100644 src/Objects/Schema/Generation/Attributes/AvroOrder.php create mode 100644 src/Objects/Schema/Generation/Attributes/AvroSize.php create mode 100644 src/Objects/Schema/Generation/Attributes/AvroSymbols.php create mode 100644 src/Objects/Schema/Generation/Attributes/AvroTargetClass.php create mode 100644 src/Objects/Schema/Generation/Attributes/AvroType.php create mode 100644 src/Objects/Schema/Generation/Attributes/AvroValues.php create mode 100644 src/Objects/Schema/Generation/Attributes/Order.php create mode 100644 src/Objects/Schema/Generation/Attributes/Type.php create mode 100644 test/Objects/Schema/Generation/AnnotationSchemaGeneratorTest.php create mode 100644 test/Objects/Schema/Generation/AttributeSchemaGeneratorTest.php diff --git a/src/Objects/Schema/Generation/Annotations/AvroItems.php b/src/Objects/Schema/Generation/Annotations/AvroItems.php index 2ebd5f6..5c158bf 100644 --- a/src/Objects/Schema/Generation/Annotations/AvroItems.php +++ b/src/Objects/Schema/Generation/Annotations/AvroItems.php @@ -5,6 +5,7 @@ namespace FlixTech\AvroSerializer\Objects\Schema\Generation\Annotations; use FlixTech\AvroSerializer\Objects\Schema\AttributeName; +use FlixTech\AvroSerializer\Objects\Schema\Generation\SchemaAttributes; use FlixTech\AvroSerializer\Objects\Schema\Generation\TypeOnlyAttribute; /** @@ -12,7 +13,25 @@ */ final class AvroItems implements TypeOnlyAttribute { - use ContainsOnlyTypes; + public $value; + + public function value(): array + { + $value = is_array($this->value) ? $this->value : [$this->value]; + + return array_map(function ($value) { + if ($value instanceof AvroType) { + return $value; + } + + return AvroType::create($value); + }, $value); + } + + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(...$this->value()); + } /** * {@inheritdoc} diff --git a/src/Objects/Schema/Generation/Annotations/AvroValues.php b/src/Objects/Schema/Generation/Annotations/AvroValues.php index 581d580..713f756 100644 --- a/src/Objects/Schema/Generation/Annotations/AvroValues.php +++ b/src/Objects/Schema/Generation/Annotations/AvroValues.php @@ -5,6 +5,7 @@ namespace FlixTech\AvroSerializer\Objects\Schema\Generation\Annotations; use FlixTech\AvroSerializer\Objects\Schema\AttributeName; +use FlixTech\AvroSerializer\Objects\Schema\Generation\SchemaAttributes; use FlixTech\AvroSerializer\Objects\Schema\Generation\TypeOnlyAttribute; /** @@ -12,7 +13,25 @@ */ final class AvroValues implements TypeOnlyAttribute { - use ContainsOnlyTypes; + public $value; + + public function value(): array + { + $value = is_array($this->value) ? $this->value : [$this->value]; + + return array_map(function ($value) { + if ($value instanceof AvroType) { + return $value; + } + + return AvroType::create($value); + }, $value); + } + + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(...$this->value()); + } /** * {@inheritdoc} diff --git a/src/Objects/Schema/Generation/Annotations/ContainsOnlyTypes.php b/src/Objects/Schema/Generation/Annotations/ContainsOnlyTypes.php deleted file mode 100644 index 8340848..0000000 --- a/src/Objects/Schema/Generation/Annotations/ContainsOnlyTypes.php +++ /dev/null @@ -1,50 +0,0 @@ - - */ - public $value; - - /** - * {@inheritdoc} - * - * @return array - */ - public function value(): array - { - if (!\is_array($this->value)) { - return [$this->valueToType($this->value)]; - } - - return \array_map([$this, 'valueToType'], $this->value); - } - - /** - * {@inheritdoc} - */ - public function attributes(): SchemaAttributes - { - return new SchemaAttributes(...$this->value()); - } - - /** - * @param string|AvroType $value - */ - private function valueToType($value): AvroType - { - if ($value instanceof AvroType) { - return $value; - } - - return AvroType::create($value); - } -} diff --git a/src/Objects/Schema/Generation/AttributeReader.php b/src/Objects/Schema/Generation/AttributeReader.php new file mode 100644 index 0000000..ed419b9 --- /dev/null +++ b/src/Objects/Schema/Generation/AttributeReader.php @@ -0,0 +1,31 @@ +getAttributes(); + return $this->getSchemaAttributes(...$attributes); + } + + public function readPropertyAttributes(ReflectionProperty $property): SchemaAttributes + { + $attributes = $property->getAttributes(); + return $this->getSchemaAttributes(...$attributes); + } + + private function getSchemaAttributes(ReflectionAttribute ...$attributes): SchemaAttributes + { + $attributes = array_map(fn($attr) => $attr->newInstance(), $attributes); + $attributes = array_filter($attributes, fn($attr) => $attr instanceof SchemaAttribute); + return new SchemaAttributes(...$attributes); + } +} diff --git a/src/Objects/Schema/Generation/Attributes/AvroAliases.php b/src/Objects/Schema/Generation/Attributes/AvroAliases.php new file mode 100644 index 0000000..77277a7 --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/AvroAliases.php @@ -0,0 +1,50 @@ + + */ + public array $aliases; + + public function __construct( + string ...$aliases, + ) { + $this->aliases = $aliases; + } + + /** + * {@inheritdoc} + */ + public function name(): string + { + return AttributeName::ALIASES; + } + + /** + * {@inheritdoc} + * + * @return array + */ + public function value(): array + { + return $this->aliases; + } + + /** + * {@inheritdoc} + */ + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(); + } +} diff --git a/src/Objects/Schema/Generation/Attributes/AvroDefault.php b/src/Objects/Schema/Generation/Attributes/AvroDefault.php new file mode 100644 index 0000000..ba5593c --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/AvroDefault.php @@ -0,0 +1,42 @@ +value; + } + + /** + * {@inheritdoc} + */ + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(); + } +} diff --git a/src/Objects/Schema/Generation/Attributes/AvroDoc.php b/src/Objects/Schema/Generation/Attributes/AvroDoc.php new file mode 100644 index 0000000..934e605 --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/AvroDoc.php @@ -0,0 +1,43 @@ +value; + } + + /** + * {@inheritdoc} + */ + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(); + } +} diff --git a/src/Objects/Schema/Generation/Attributes/AvroItems.php b/src/Objects/Schema/Generation/Attributes/AvroItems.php new file mode 100644 index 0000000..b3c38de --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/AvroItems.php @@ -0,0 +1,45 @@ +types = array_map(function ($type) { + if ($type instanceof AvroType) { + return $type; + } + + return new AvroType($type); + }, $types); + } + + public function value(): array + { + return $this->types; + } + + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(...$this->value()); + } + + /** + * {@inheritdoc} + */ + public function name(): string + { + return AttributeName::ITEMS; + } +} diff --git a/src/Objects/Schema/Generation/Attributes/AvroName.php b/src/Objects/Schema/Generation/Attributes/AvroName.php new file mode 100644 index 0000000..c9ccc94 --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/AvroName.php @@ -0,0 +1,33 @@ +value; + } + + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(); + } +} diff --git a/src/Objects/Schema/Generation/Attributes/AvroNamespace.php b/src/Objects/Schema/Generation/Attributes/AvroNamespace.php new file mode 100644 index 0000000..db72efa --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/AvroNamespace.php @@ -0,0 +1,34 @@ +value; + } + + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(); + } +} diff --git a/src/Objects/Schema/Generation/Attributes/AvroOrder.php b/src/Objects/Schema/Generation/Attributes/AvroOrder.php new file mode 100644 index 0000000..b9b7d85 --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/AvroOrder.php @@ -0,0 +1,42 @@ +order->value; + } + + /** + * {@inheritdoc} + */ + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(); + } +} diff --git a/src/Objects/Schema/Generation/Attributes/AvroSize.php b/src/Objects/Schema/Generation/Attributes/AvroSize.php new file mode 100644 index 0000000..abadebe --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/AvroSize.php @@ -0,0 +1,42 @@ +size; + } + + /** + * {@inheritdoc} + */ + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(); + } +} diff --git a/src/Objects/Schema/Generation/Attributes/AvroSymbols.php b/src/Objects/Schema/Generation/Attributes/AvroSymbols.php new file mode 100644 index 0000000..f11a4fb --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/AvroSymbols.php @@ -0,0 +1,50 @@ + + */ + private array $symbols; + + public function __construct( + string ...$symbols, + ) { + $this->symbols = $symbols; + } + + /** + * {@inheritdoc} + */ + public function name(): string + { + return AttributeName::SYMBOLS; + } + + /** + * {@inheritdoc} + * + * @return array + */ + public function value(): array + { + return $this->symbols; + } + + /** + * {@inheritdoc} + */ + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(); + } +} diff --git a/src/Objects/Schema/Generation/Attributes/AvroTargetClass.php b/src/Objects/Schema/Generation/Attributes/AvroTargetClass.php new file mode 100644 index 0000000..b5d9c1f --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/AvroTargetClass.php @@ -0,0 +1,33 @@ +value; + } + + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(); + } +} diff --git a/src/Objects/Schema/Generation/Attributes/AvroType.php b/src/Objects/Schema/Generation/Attributes/AvroType.php new file mode 100644 index 0000000..f109ae5 --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/AvroType.php @@ -0,0 +1,58 @@ + + */ + public $attributes = []; + + public string $value; + + public function __construct( + Type|string $value, + SchemaAttribute ...$attributes + ) { + if (is_string($value)) { + $this->value = $value; + } else { + $this->value = $value->value; + } + + $this->attributes = $attributes; + } + + /** + * {@inheritdoc} + */ + public function name(): string + { + return AttributeName::TYPE; + } + + /** + * {@inheritdoc} + */ + public function value(): string + { + return $this->value; + } + + /** + * {@inheritdoc} + */ + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(...$this->attributes); + } +} diff --git a/src/Objects/Schema/Generation/Attributes/AvroValues.php b/src/Objects/Schema/Generation/Attributes/AvroValues.php new file mode 100644 index 0000000..af2cecd --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/AvroValues.php @@ -0,0 +1,45 @@ +types = array_map(function ($type) { + if ($type instanceof AvroType) { + return $type; + } + + return new AvroType($type); + }, $types); + } + + public function value(): array + { + return $this->types; + } + + public function attributes(): SchemaAttributes + { + return new SchemaAttributes(...$this->value()); + } + + /** + * {@inheritdoc} + */ + public function name(): string + { + return AttributeName::VALUES; + } +} diff --git a/src/Objects/Schema/Generation/Attributes/Order.php b/src/Objects/Schema/Generation/Attributes/Order.php new file mode 100644 index 0000000..32ad437 --- /dev/null +++ b/src/Objects/Schema/Generation/Attributes/Order.php @@ -0,0 +1,12 @@ + + */ + public function value(): array; } diff --git a/test/Objects/Schema/Generation/AnnotationSchemaGeneratorTest.php b/test/Objects/Schema/Generation/AnnotationSchemaGeneratorTest.php new file mode 100644 index 0000000..ea27969 --- /dev/null +++ b/test/Objects/Schema/Generation/AnnotationSchemaGeneratorTest.php @@ -0,0 +1,23 @@ + 42, 'bar' => 42]), + )] private $map; /** @@ -35,6 +59,12 @@ class RecordWithComplexTypes * @SerDe\AvroSymbols({"SPADES", "HEARTS", "DIAMONDS", "CLUBS"}) * }) */ + #[AvroOrder(Order::ASC)] + #[AvroType( + Type::ENUM, + new AvroName("Suit"), + new AvroSymbols("SPADES", "HEARTS", "DIAMONDS", "CLUBS"), + )] private $enum; /** @@ -45,6 +75,13 @@ class RecordWithComplexTypes * @SerDe\AvroSize(16) * }) */ + #[AvroType( + Type::FIXED, + new AvroName("md5"), + new AvroNamespace("org.acme"), + new AvroAliases("foo", "bar"), + new AvroSize(16) + )] private $fixed; /** @@ -54,5 +91,11 @@ class RecordWithComplexTypes * @SerDe\AvroItems("string"), * }) */ + #[AvroType(Type::STRING)] + #[AvroType(Type::INT)] + #[AvroType( + Type::ARRAY, + new AvroItems(Type::STRING), + )] private $union; } diff --git a/test/Objects/Schema/Generation/Fixture/RecordWithRecordType.php b/test/Objects/Schema/Generation/Fixture/RecordWithRecordType.php index 4a9a08c..d889f00 100644 --- a/test/Objects/Schema/Generation/Fixture/RecordWithRecordType.php +++ b/test/Objects/Schema/Generation/Fixture/RecordWithRecordType.php @@ -5,20 +5,33 @@ namespace FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture; use FlixTech\AvroSerializer\Objects\Schema\Generation\Annotations as SerDe; +use FlixTech\AvroSerializer\Objects\Schema\Generation\Attributes\AvroDoc; +use FlixTech\AvroSerializer\Objects\Schema\Generation\Attributes\AvroName; +use FlixTech\AvroSerializer\Objects\Schema\Generation\Attributes\AvroTargetClass; +use FlixTech\AvroSerializer\Objects\Schema\Generation\Attributes\AvroType; +use FlixTech\AvroSerializer\Objects\Schema\Generation\Attributes\Type; /** * @SerDe\AvroType("record") * @SerDe\AvroName("RecordWithRecordType") */ +#[AvroType(Type::RECORD)] +#[AvroName("RecordWithRecordType")] class RecordWithRecordType { /** * @SerDe\AvroName("simpleField") * @SerDe\AvroType("record", attributes={ * @SerDe\AvroTargetClass("\FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\SimpleRecord"), - * @SerDe\AvroDoc("This a simple record for testing purposes") + * @SerDe\AvroDoc("This is a simple record for testing purposes") * }) */ + #[AvroName("simpleField")] + #[AvroType( + Type::RECORD, + new AvroTargetClass("\FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\SimpleRecord"), + new AvroDoc("This is a simple record for testing purposes") + )] private $simpleRecord; /** @@ -26,5 +39,8 @@ class RecordWithRecordType * @SerDe\AvroType("null") * @SerDe\AvroType("org.acme.SimpleRecord") */ + #[AvroName("unionField")] + #[AvroType(Type::NULL)] + #[AvroType("org.acme.SimpleRecord")] private $unionRecord; } diff --git a/test/Objects/Schema/Generation/Fixture/SimpleRecord.php b/test/Objects/Schema/Generation/Fixture/SimpleRecord.php index 16e4769..673ab38 100644 --- a/test/Objects/Schema/Generation/Fixture/SimpleRecord.php +++ b/test/Objects/Schema/Generation/Fixture/SimpleRecord.php @@ -5,17 +5,27 @@ namespace FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture; use FlixTech\AvroSerializer\Objects\Schema\Generation\Annotations as SerDe; +use FlixTech\AvroSerializer\Objects\Schema\Generation\Attributes\AvroDefault; +use FlixTech\AvroSerializer\Objects\Schema\Generation\Attributes\AvroName; +use FlixTech\AvroSerializer\Objects\Schema\Generation\Attributes\AvroNamespace; +use FlixTech\AvroSerializer\Objects\Schema\Generation\Attributes\AvroType; +use FlixTech\AvroSerializer\Objects\Schema\Generation\Attributes\Type; /** * @SerDe\AvroName("SimpleRecord") * @SerDe\AvroNamespace("org.acme") * @SerDe\AvroType("record") */ +#[AvroName("SimpleRecord")] +#[AvroNamespace("org.acme")] +#[AvroType(Type::RECORD)] class SimpleRecord { /** * @SerDe\AvroType("int") * @SerDe\AvroDefault(42) */ + #[AvroType(Type::INT)] + #[AvroDefault(42)] private $intType; } diff --git a/test/Objects/Schema/Generation/SchemaGeneratorTest.php b/test/Objects/Schema/Generation/SchemaGeneratorTest.php index 05fc440..2c8d877 100644 --- a/test/Objects/Schema/Generation/SchemaGeneratorTest.php +++ b/test/Objects/Schema/Generation/SchemaGeneratorTest.php @@ -4,9 +4,8 @@ namespace FlixTech\AvroSerializer\Test\Objects\Schema\Generation; -use Doctrine\Common\Annotations\AnnotationReader; -use Doctrine\Common\Annotations\AnnotationRegistry; use FlixTech\AvroSerializer\Objects\Schema; +use FlixTech\AvroSerializer\Objects\Schema\Generation\SchemaAttributeReader; use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\ArraysWithComplexType; use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\EmptyRecord; use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\MapsWithComplexType; @@ -15,7 +14,7 @@ use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\RecordWithRecordType; use PHPUnit\Framework\TestCase; -class SchemaGeneratorTest extends TestCase +abstract class SchemaGeneratorTest extends TestCase { /** * @var Schema\Generation\SchemaGenerator @@ -24,15 +23,13 @@ class SchemaGeneratorTest extends TestCase protected function setUp(): void { - AnnotationRegistry::registerLoader('class_exists'); - $this->generator = new Schema\Generation\SchemaGenerator( - new Schema\Generation\AnnotationReader( - new AnnotationReader() - ) + $this->makeSchemaAttributeReader() ); } + abstract protected function makeSchemaAttributeReader(): SchemaAttributeReader; + /** * @test */ @@ -155,7 +152,7 @@ public function it_should_generate_records_containing_records() Schema::record() ->name('SimpleRecord') ->namespace('org.acme') - ->doc('This a simple record for testing purposes') + ->doc('This is a simple record for testing purposes') ->field( 'intType', Schema::int(), From f349ff50a53474824995050f6ee9c8da56ccfbf4 Mon Sep 17 00:00:00 2001 From: Francisco Edno Date: Tue, 2 Nov 2021 11:54:45 -0300 Subject: [PATCH 2/4] Add support for php 8.1 features without breaking older php versions - Refactor unit tests in order to remove php 8.1 specific tests from older php versions - Conditionally remove or add code to static analysis based on the current php version - Update minimum phpunit version --- .php-cs-fixer.dist.php | 7 +++ Dockerfile | 2 +- Makefile | 2 +- composer.json | 2 +- phpstan-conditional.config.php | 15 +++++ phpstan.neon | 2 + src/Objects/Exceptions/Exceptions.php | 16 +++++ .../UnsupportedPhpVersionException.php | 11 ++++ .../Generation/Annotations/AvroItems.php | 5 +- .../Generation/Annotations/AvroValues.php | 5 +- .../Schema/Generation/AttributeReader.php | 13 ++++ .../AnnotationSchemaGeneratorTest.php | 35 +++++++++++ .../Schema/Generation/AttributeReaderTest.php | 23 +++++++ .../AttributeSchemaGeneratorTest.php | 39 ++++++++++++ .../Annotations/ArraysWithComplexType.php | 33 ++++++++++ .../Fixture/Annotations/EmptyRecord.php | 16 +++++ .../Annotations/MapsWithComplexType.php | 33 ++++++++++ .../Fixture/Annotations/PrimitiveTypes.php | 60 +++++++++++++++++++ .../Annotations/RecordWithComplexTypes.php | 58 ++++++++++++++++++ .../Annotations/RecordWithRecordType.php | 30 ++++++++++ .../Fixture/Annotations/SimpleRecord.php | 21 +++++++ .../ArraysWithComplexType.php | 22 +------ .../Fixture/{ => Attributes}/EmptyRecord.php | 8 +-- .../{ => Attributes}/MapsWithComplexType.php | 22 +------ .../{ => Attributes}/PrimitiveTypes.php | 37 +----------- .../RecordWithComplexTypes.php | 41 +------------ .../{ => Attributes}/RecordWithRecordType.php | 21 +------ .../Fixture/{ => Attributes}/SimpleRecord.php | 12 +--- .../Schema/Generation/SchemaGeneratorTest.php | 34 ++++++----- 29 files changed, 451 insertions(+), 174 deletions(-) create mode 100644 phpstan-conditional.config.php create mode 100644 src/Objects/Exceptions/UnsupportedPhpVersionException.php create mode 100644 test/Objects/Schema/Generation/AttributeReaderTest.php create mode 100644 test/Objects/Schema/Generation/Fixture/Annotations/ArraysWithComplexType.php create mode 100644 test/Objects/Schema/Generation/Fixture/Annotations/EmptyRecord.php create mode 100644 test/Objects/Schema/Generation/Fixture/Annotations/MapsWithComplexType.php create mode 100644 test/Objects/Schema/Generation/Fixture/Annotations/PrimitiveTypes.php create mode 100644 test/Objects/Schema/Generation/Fixture/Annotations/RecordWithComplexTypes.php create mode 100644 test/Objects/Schema/Generation/Fixture/Annotations/RecordWithRecordType.php create mode 100644 test/Objects/Schema/Generation/Fixture/Annotations/SimpleRecord.php rename test/Objects/Schema/Generation/Fixture/{ => Attributes}/ArraysWithComplexType.php (64%) rename test/Objects/Schema/Generation/Fixture/{ => Attributes}/EmptyRecord.php (72%) rename test/Objects/Schema/Generation/Fixture/{ => Attributes}/MapsWithComplexType.php (64%) rename test/Objects/Schema/Generation/Fixture/{ => Attributes}/PrimitiveTypes.php (65%) rename test/Objects/Schema/Generation/Fixture/{ => Attributes}/RecordWithComplexTypes.php (63%) rename test/Objects/Schema/Generation/Fixture/{ => Attributes}/RecordWithRecordType.php (55%) rename test/Objects/Schema/Generation/Fixture/{ => Attributes}/SimpleRecord.php (70%) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 474bb52..4df4185 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -6,6 +6,13 @@ ->in(['src', 'test']) ; +if (version_compare(PHP_VERSION, '8.1') < 0) { + $finder = $finder + ->notPath('Objects/Schema/Generation/Attributes') + ->notPath('Objects/Schema/Generation/AttributeReader.php') + ->notPath('Objects/Schema/Generation/Fixture/Attributes'); +} + return (new PhpCsFixer\Config()) ->setRules([ '@Symfony' => true, diff --git a/Dockerfile b/Dockerfile index 59c571f..d477231 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ ARG PHP_VERSION=7.4 -FROM php:${PHP_VERSION}-cli-alpine +FROM php:${PHP_VERSION}-cli-alpine3.13 ARG XDEBUG_VERSION=3.1.1 diff --git a/Makefile b/Makefile index 25c6e9f..0601d57 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ ZOOKEEPER_IPV4 ?= 192.168.104.101 COMPOSER ?= bin/composer.phar COMPOSER_VERSION ?= 2.1.9 PHP_STAN ?= bin/phpstan.phar -PHP_STAN_VERSION ?= 0.12.99 +PHP_STAN_VERSION ?= 1.0.1 PHP_CS_FIXER ?= bin/php-cs-fixer.phar PHP_CS_FIXER_VERSION ?= 3.2.1 PHPUNIT ?= vendor/bin/phpunit diff --git a/composer.json b/composer.json index 2a6e6a8..91e877d 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "widmogrod/php-functional": "^6.0" }, "require-dev": { - "phpunit/phpunit": "^8.2.3|^9.4.2", + "phpunit/phpunit": "^9.5.10", "phpbench/phpbench": "1.0.0-alpha2", "vlucas/phpdotenv": "~2.4", "symfony/serializer": "^3.4|^4.3", diff --git a/phpstan-conditional.config.php b/phpstan-conditional.config.php new file mode 100644 index 0000000..911b9fc --- /dev/null +++ b/phpstan-conditional.config.php @@ -0,0 +1,15 @@ + [ + 'src/Objects/Schema/Generation/Attributes/', + 'src/Objects/Schema/Generation/AttributeReader.php' + ], + ]; +} + +return $config; diff --git a/phpstan.neon b/phpstan.neon index c7b1758..0532808 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,3 +1,5 @@ +includes: + - phpstan-conditional.config.php parameters: level: 8 paths: [ src ] diff --git a/src/Objects/Exceptions/Exceptions.php b/src/Objects/Exceptions/Exceptions.php index 0b2a96b..f597ade 100644 --- a/src/Objects/Exceptions/Exceptions.php +++ b/src/Objects/Exceptions/Exceptions.php @@ -8,6 +8,7 @@ final class Exceptions { public const ERROR_ENCODING = 501; public const ERROR_DECODING = 502; + public const ERROR_PHP_VERSION = 503; /** * @param mixed $record @@ -41,4 +42,19 @@ public static function forDecode(string $binaryMessage, \Exception $previous = n return new AvroDecodingException($message, self::ERROR_DECODING, $previous); } + + public static function forPhpVersion(string $currentVersion, string $minimumVersion): UnsupportedPhpVersionException + { + $message = sprintf( + 'The current php version \'%s\' is not supported for this feature. ' . + 'Minimum supported version is \'%s\'', + $currentVersion, + $minimumVersion, + ); + + return new UnsupportedPhpVersionException( + $message, + self::ERROR_PHP_VERSION + ); + } } diff --git a/src/Objects/Exceptions/UnsupportedPhpVersionException.php b/src/Objects/Exceptions/UnsupportedPhpVersionException.php new file mode 100644 index 0000000..af319ba --- /dev/null +++ b/src/Objects/Exceptions/UnsupportedPhpVersionException.php @@ -0,0 +1,11 @@ +value) ? $this->value : [$this->value]; + $value = \is_array($this->value) ? $this->value : [$this->value]; return array_map(function ($value) { if ($value instanceof AvroType) { diff --git a/src/Objects/Schema/Generation/Annotations/AvroValues.php b/src/Objects/Schema/Generation/Annotations/AvroValues.php index 713f756..05dde2a 100644 --- a/src/Objects/Schema/Generation/Annotations/AvroValues.php +++ b/src/Objects/Schema/Generation/Annotations/AvroValues.php @@ -13,11 +13,14 @@ */ final class AvroValues implements TypeOnlyAttribute { + /** + * @var mixed + */ public $value; public function value(): array { - $value = is_array($this->value) ? $this->value : [$this->value]; + $value = \is_array($this->value) ? $this->value : [$this->value]; return array_map(function ($value) { if ($value instanceof AvroType) { diff --git a/src/Objects/Schema/Generation/AttributeReader.php b/src/Objects/Schema/Generation/AttributeReader.php index ed419b9..5c0e69b 100644 --- a/src/Objects/Schema/Generation/AttributeReader.php +++ b/src/Objects/Schema/Generation/AttributeReader.php @@ -4,12 +4,25 @@ namespace FlixTech\AvroSerializer\Objects\Schema\Generation; +use FlixTech\AvroSerializer\Objects\Exceptions\Exceptions; use ReflectionAttribute; use ReflectionClass; use ReflectionProperty; class AttributeReader implements SchemaAttributeReader { + private const MINIMUM_REQUIRED_VERSION = '8.1'; + + public function __construct() + { + if (version_compare(PHP_VERSION, self::MINIMUM_REQUIRED_VERSION) < 0) { + throw Exceptions::forPhpVersion( + PHP_VERSION, + self::MINIMUM_REQUIRED_VERSION, + ); + } + } + public function readClassAttributes(ReflectionClass $class): SchemaAttributes { $attributes = $class->getAttributes(); diff --git a/test/Objects/Schema/Generation/AnnotationSchemaGeneratorTest.php b/test/Objects/Schema/Generation/AnnotationSchemaGeneratorTest.php index ea27969..86dc6bd 100644 --- a/test/Objects/Schema/Generation/AnnotationSchemaGeneratorTest.php +++ b/test/Objects/Schema/Generation/AnnotationSchemaGeneratorTest.php @@ -8,6 +8,12 @@ use Doctrine\Common\Annotations\AnnotationRegistry; use FlixTech\AvroSerializer\Objects\Schema\Generation\AnnotationReader as SchemaAnnotationReader; use FlixTech\AvroSerializer\Objects\Schema\Generation\SchemaAttributeReader; +use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\Annotations\ArraysWithComplexType; +use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\Annotations\EmptyRecord; +use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\Annotations\MapsWithComplexType; +use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\Annotations\PrimitiveTypes; +use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\Annotations\RecordWithComplexTypes; +use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\Annotations\RecordWithRecordType; class AnnotationSchemaGeneratorTest extends SchemaGeneratorTest { @@ -20,4 +26,33 @@ protected function makeSchemaAttributeReader(): SchemaAttributeReader ); } + protected function getEmptyRecordClass(): string + { + return EmptyRecord::class; + } + + protected function getPrimitiveTypesClass(): string + { + return PrimitiveTypes::class; + } + + protected function getRecordWithComplexTypesClass(): string + { + return RecordWithComplexTypes::class; + } + + protected function getRecordWithRecordTypeClass(): string + { + return RecordWithRecordType::class; + } + + protected function getArraysWithComplexTypeClass(): string + { + return ArraysWithComplexType::class; + } + + protected function getMapsWithComplexTypeClass(): string + { + return MapsWithComplexType::class; + } } diff --git a/test/Objects/Schema/Generation/AttributeReaderTest.php b/test/Objects/Schema/Generation/AttributeReaderTest.php new file mode 100644 index 0000000..4b04dc4 --- /dev/null +++ b/test/Objects/Schema/Generation/AttributeReaderTest.php @@ -0,0 +1,23 @@ +expectException(UnsupportedPhpVersionException::class); + + new AttributeReader(); + } +} diff --git a/test/Objects/Schema/Generation/AttributeSchemaGeneratorTest.php b/test/Objects/Schema/Generation/AttributeSchemaGeneratorTest.php index 1526c96..f865e61 100644 --- a/test/Objects/Schema/Generation/AttributeSchemaGeneratorTest.php +++ b/test/Objects/Schema/Generation/AttributeSchemaGeneratorTest.php @@ -6,11 +6,50 @@ use FlixTech\AvroSerializer\Objects\Schema\Generation\AttributeReader; use FlixTech\AvroSerializer\Objects\Schema\Generation\SchemaAttributeReader; +use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\Attributes\ArraysWithComplexType; +use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\Attributes\EmptyRecord; +use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\Attributes\MapsWithComplexType; +use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\Attributes\PrimitiveTypes; +use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\Attributes\RecordWithComplexTypes; +use FlixTech\AvroSerializer\Test\Objects\Schema\Generation\Fixture\Attributes\RecordWithRecordType; +/** + * @requires PHP >= 8.1 + */ class AttributeSchemaGeneratorTest extends SchemaGeneratorTest { protected function makeSchemaAttributeReader(): SchemaAttributeReader { return new AttributeReader(); } + + protected function getEmptyRecordClass(): string + { + return EmptyRecord::class; + } + + protected function getPrimitiveTypesClass(): string + { + return PrimitiveTypes::class; + } + + protected function getRecordWithComplexTypesClass(): string + { + return RecordWithComplexTypes::class; + } + + protected function getRecordWithRecordTypeClass(): string + { + return RecordWithRecordType::class; + } + + protected function getArraysWithComplexTypeClass(): string + { + return ArraysWithComplexType::class; + } + + protected function getMapsWithComplexTypeClass(): string + { + return MapsWithComplexType::class; + } } diff --git a/test/Objects/Schema/Generation/Fixture/Annotations/ArraysWithComplexType.php b/test/Objects/Schema/Generation/Fixture/Annotations/ArraysWithComplexType.php new file mode 100644 index 0000000..40d20a3 --- /dev/null +++ b/test/Objects/Schema/Generation/Fixture/Annotations/ArraysWithComplexType.php @@ -0,0 +1,33 @@ +generator->generate(EmptyRecord::class); + $schema = $this->generator->generate($this->getEmptyRecordClass()); $expected = Schema::record() ->name('EmptyRecord') @@ -49,7 +41,7 @@ public function it_should_generate_an_empty_record() */ public function it_should_generate_a_record_schema_with_primitive_types() { - $schema = $this->generator->generate(PrimitiveTypes::class); + $schema = $this->generator->generate($this->getPrimitiveTypesClass()); $expected = Schema::record() ->name('PrimitiveTypes') @@ -99,7 +91,7 @@ public function it_should_generate_a_record_schema_with_primitive_types() */ public function it_should_generate_a_schema_record_with_complex_types() { - $schema = $this->generator->generate(RecordWithComplexTypes::class); + $schema = $this->generator->generate($this->getRecordWithComplexTypesClass()); $expected = Schema::record() ->name('RecordWithComplexTypes') @@ -143,7 +135,7 @@ public function it_should_generate_a_schema_record_with_complex_types() */ public function it_should_generate_records_containing_records() { - $schema = $this->generator->generate(RecordWithRecordType::class); + $schema = $this->generator->generate($this->getRecordWithRecordTypeClass()); $expected = Schema::record() ->name('RecordWithRecordType') @@ -175,7 +167,7 @@ public function it_should_generate_records_containing_records() */ public function it_should_generate_a_record_schema_with_arrays_containing_complex_types() { - $schema = $this->generator->generate(ArraysWithComplexType::class); + $schema = $this->generator->generate($this->getArraysWithComplexTypeClass()); $expected = Schema::record() ->name('ArraysWithComplexType') @@ -205,7 +197,7 @@ public function it_should_generate_a_record_schema_with_arrays_containing_comple */ public function it_should_generate_a_record_schema_with_maps_containing_complex_types() { - $schema = $this->generator->generate(MapsWithComplexType::class); + $schema = $this->generator->generate($this->getMapsWithComplexTypeClass()); $expected = Schema::record() ->name('MapsWithComplexType') @@ -229,4 +221,18 @@ public function it_should_generate_a_record_schema_with_maps_containing_complex_ $this->assertEquals($expected, $schema); } + + abstract protected function makeSchemaAttributeReader(): SchemaAttributeReader; + + abstract protected function getEmptyRecordClass(): string; + + abstract protected function getPrimitiveTypesClass(): string; + + abstract protected function getRecordWithComplexTypesClass(): string; + + abstract protected function getRecordWithRecordTypeClass(): string; + + abstract protected function getArraysWithComplexTypeClass(): string; + + abstract protected function getMapsWithComplexTypeClass(): string; } From c298a36d2f176331d5c4e42e84233b020c8ffe3f Mon Sep 17 00:00:00 2001 From: Francisco Edno Date: Tue, 2 Nov 2021 13:23:59 -0300 Subject: [PATCH 3/4] Add php 8.1 to the build pipeline matrix --- .github/workflows/checks.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 49c3746..effde1f 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -33,6 +33,10 @@ jobs: - version: 8.0 xdebug: 3.1.1 + + - + version: 8.1.0RC3 + xdebug: 3.1.1 runs-on: ubuntu-20.04 steps: - @@ -81,12 +85,18 @@ jobs: - version: 8.0 composer: --prefer-lowest + - + version: 8.1.0RC3 + composer: --prefer-lowest - version: 7.4 composer: --prefer-stable - version: 8.0 composer: --prefer-stable + - + version: 8.1.0RC3 + composer: --prefer-stable steps: - name: Download sources From 8a8ca501f4a5393f45a037d95716726aee20837e Mon Sep 17 00:00:00 2001 From: Francisco Edno Date: Thu, 11 Nov 2021 13:11:33 -0300 Subject: [PATCH 4/4] [wip] add logging to debug failing integration test --- .github/workflows/checks.yml | 1 + Makefile | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index effde1f..890ef91 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -200,6 +200,7 @@ jobs: run: | chmod a+x bin/wait-for-all.sh bin/wait-for-it.sh make platform + make platform-logs docker run -i --rm --net=host --sig-proxy=true --pid=host \ -v "${GITHUB_WORKSPACE}":"${GITHUB_WORKSPACE}" -w "${GITHUB_WORKSPACE}" php-avro-serde:7.4 \ vendor/bin/phpunit --group integration diff --git a/Makefile b/Makefile index 0601d57..0b20df7 100644 --- a/Makefile +++ b/Makefile @@ -75,6 +75,10 @@ platform: docker-compose up -d bin/wait-for-all.sh +platform-logs: + docker-compose ps + docker-compose logs schema_registry + clean: rm -rf build docker-compose down