Skip to content

Commit

Permalink
Merge pull request #1492 from pmysiak/feat/allow-stringable
Browse files Browse the repository at this point in the history
feat(stringable-type): Allow stringable object as type.
  • Loading branch information
scyzoryck authored Jun 4, 2023
2 parents 81d2eb1 + 3efa37c commit bd18f0a
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 2 deletions.
28 changes: 28 additions & 0 deletions doc/reference/annotations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,34 @@ Examples:
private $keyValueStore;
}
.. note ::
if you are using ``PHP attributes`` with PHP 8.1 you can pass an object which implements ``__toString()`` method as a value for ``#[Type]`` attribute.
.. code-block :: php
<?php
namespace MyNamespace;
use JMS\Serializer\Annotation\Type;
class BlogPost
{
#[Type(new ArrayOf(Comment::class))]
private $comments;
}
class ArrayOf
{
public function __construct(private string $className) {}
public function __toString(): string
{
return "array<$className>";
}
}
.. _configuration: https://jmsyst.com/bundles/JMSSerializerBundle/master/configuration#configuration-block-2-0

@XmlRoot
Expand Down
14 changes: 12 additions & 2 deletions src/Annotation/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,22 @@ final class Type

/**
* @Required
* @var string|null
* @var string|\Stringable|null
*/
public $name = null;

public function __construct($values = [], ?string $name = null)
public function __construct($values = [], $name = null)
{
if ((null !== $name) && !is_string($name) && !(is_object($name) && method_exists($name, '__toString'))) {
throw new \RuntimeException(
'Type must be either string, null or object implements __toString() method.'
);
}

if (is_object($name)) {
$name = (string) $name;
}

$this->loadAnnotationParameters(get_defined_vars());
}
}
25 changes: 25 additions & 0 deletions tests/Fixtures/ObjectWithTypeAsNonStringableObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace JMS\Serializer\Tests\Fixtures;

use JMS\Serializer\Annotation as Serializer;

class ObjectWithTypeAsNonStringableObject
{
#[Serializer\Type(name: new NonStringableObjectType())]
private $array;

/**
* @param array<string> $array
*/
public function __construct(array $array)
{
$this->array = $array;
}
}

class NonStringableObjectType
{
}
29 changes: 29 additions & 0 deletions tests/Fixtures/ObjectWithTypeAsStringableObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace JMS\Serializer\Tests\Fixtures;

use JMS\Serializer\Annotation as Serializer;

class ObjectWithTypeAsStringableObject
{
#[Serializer\Type(name: new StringableObjectType())]
private $array;

/**
* @param array<string> $array
*/
public function __construct(array $array)
{
$this->array = $array;
}
}

class StringableObjectType
{
public function __toString(): string
{
return 'array<string>';
}
}
34 changes: 34 additions & 0 deletions tests/Metadata/Driver/BaseDriverTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use JMS\Serializer\Exception\InvalidMetadataException;
use JMS\Serializer\Expression\ExpressionEvaluator;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\Driver\AttributeDriver;
use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Metadata\VirtualPropertyMetadata;
Expand All @@ -21,6 +22,8 @@
use JMS\Serializer\Tests\Fixtures\ObjectWithExpressionVirtualPropertiesAndExcludeAll;
use JMS\Serializer\Tests\Fixtures\ObjectWithInvalidExpression;
use JMS\Serializer\Tests\Fixtures\ObjectWithOnlyLifecycleCallbacks;
use JMS\Serializer\Tests\Fixtures\ObjectWithTypeAsNonStringableObject;
use JMS\Serializer\Tests\Fixtures\ObjectWithTypeAsStringableObject;
use JMS\Serializer\Tests\Fixtures\ObjectWithVirtualPropertiesAndDuplicatePropName;
use JMS\Serializer\Tests\Fixtures\ObjectWithVirtualPropertiesAndDuplicatePropNameExcludeAll;
use JMS\Serializer\Tests\Fixtures\ObjectWithVirtualPropertiesAndExcludeAll;
Expand Down Expand Up @@ -662,6 +665,37 @@ public function testShortExposeSyntax(): void
self::assertArrayNotHasKey('age', $m->propertyMetadata);
}

public function testTypeAsStringableObject(): void
{
if (PHP_VERSION_ID < 80100) {
$this->markTestSkipped(sprintf('%s requires PHP 8.1.', __METHOD__));
}

if (!$this->getDriver() instanceof AttributeDriver) {
$this->markTestSkipped('Attribute driver is required.');
}

$m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass(ObjectWithTypeAsStringableObject::class));
\assert($m instanceof ClassMetadata);

self::assertSame(['name' => 'array', 'params' => [['name' => 'string', 'params' => []]]], $m->propertyMetadata['array']->type);
}

public function testTypeAsNonStringableObject(): void
{
if (PHP_VERSION_ID < 80100) {
$this->markTestSkipped(sprintf('%s requires PHP 8.1.', __METHOD__));
}

if (!$this->getDriver() instanceof AttributeDriver) {
$this->markTestSkipped('Attribute driver is required.');
}

$this->expectException(\RuntimeException::class);

$this->getDriver()->loadMetadataForClass(new \ReflectionClass(ObjectWithTypeAsNonStringableObject::class));
}

abstract protected function getDriver(?string $subDir = null, bool $addUnderscoreDir = true): DriverInterface;

protected function getExpressionEvaluator()
Expand Down

0 comments on commit bd18f0a

Please sign in to comment.