Skip to content
Open
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
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
"phpunit/phpunit": "^10.5|^11.5.3",
"projektgopher/whisky": "^0.5.1|^0.7"
},
"suggest": {
"phpdocumentor/reflection-docblock": "Enables PhpDoc-based serializer type extraction (for example, `/** @var DTO[] */` collection element inference)."
},
"autoload": {
"psr-4": {
"Thunk\\Verbs\\": "src/",
Expand Down
6 changes: 6 additions & 0 deletions docs/serialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ application. If you need to store more complex data, you may need to add your ow
which you can do in `config/verbs.php` file. You may also change the
[default serializer context](https://symfony.com/doc/current/components/serializer.html#context)
there as well.

For PhpDoc-based type inference (for example `/** @var MyDto[] */` on array properties),
install `phpdocumentor/reflection-docblock`. Verbs will still work without it, but serializer
type extraction falls back to reflection-only behavior and PhpDoc collection element types are
not inferred during deserialization. See also [this PR](https://github.com/hirethunk/verbs/pull/125#issuecomment-2359638427),
that introduced the PhpDoc-based type inference feature.
19 changes: 15 additions & 4 deletions src/VerbsServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,8 @@ public function packageRegistered()

return new PropertyNormalizer(
propertyTypeExtractor: new PropertyInfoExtractor(
typeExtractors: [
new PhpDocExtractor,
new ReflectionExtractor,
]),
typeExtractors: $this->getPropertyTypeExtractors(),
),
classDiscriminatorResolver: new ClassDiscriminatorFromClassMetadata(new ClassMetadataFactory($loader)),
);
});
Expand Down Expand Up @@ -181,4 +179,17 @@ protected function handleEvent($event = null)
app(AutoCommitManager::class)->commitIfAutoCommitting();
}
}

protected function getPropertyTypeExtractors(): array
{
return [
...$this->hasPhpDocExtractorDependency() ? [new PhpDocExtractor] : [],
new ReflectionExtractor,
];
}

protected function hasPhpDocExtractorDependency(): bool
{
return class_exists(PhpDocExtractor::class);
}
}
34 changes: 34 additions & 0 deletions tests/Feature/SerializationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Thunk\Verbs\State;
use Thunk\Verbs\Support\Normalization\NormalizeToPropertiesAndClassName;
use Thunk\Verbs\Support\Serializer;
use Thunk\Verbs\VerbsServiceProvider;

it('supports instantiation via an associative array', function () {
$snowflake = Snowflake::make();
Expand Down Expand Up @@ -167,6 +168,39 @@ public function __construct()
->and($deserialized_event->dtos[0])->toBeInstanceOf(DTO::class);
});

it('falls back to reflection type extraction when PhpDoc extraction is unavailable', function () {
$provider = new class(app()) extends VerbsServiceProvider
{
protected function hasPhpDocExtractorDependency(): bool
{
return false;
}
};

$provider->packageRegistered();
app()->forgetInstance(Serializer::class);
app()->forgetInstance(PropertyNormalizer::class);

$original_event = new EventWithPhpDocArray;
$serialized_data = app(Serializer::class)->serialize($original_event);

$deserialized_event = app(Serializer::class)->deserialize(EventWithPhpDocArray::class, $serialized_data);

expect($deserialized_event->dto)
->toBeInstanceOf(DTO::class);

// NOTE: Type inference via PhpDoc is not available, which breaks the collection type inference.
// See also https://github.com/hirethunk/verbs/pull/125#issuecomment-2359638427
expect($deserialized_event->dtos)
->toBeArray()
->toBe([
[
'fqcn' => DTO::class,
'foo' => 1,
],
]);
});

class EventWithConstructorPromotion extends Event
{
public function __construct(
Expand Down