Skip to content
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

Serialization Context Naming Strategy #1394

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
10 changes: 10 additions & 0 deletions src/GraphNavigator/SerializationGraphNavigator.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use JMS\Serializer\GraphNavigatorInterface;
use JMS\Serializer\Handler\HandlerRegistryInterface;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
use JMS\Serializer\NullAwareVisitorInterface;
use JMS\Serializer\SerializationContext;
use JMS\Serializer\Visitor\SerializationVisitorInterface;
Expand Down Expand Up @@ -80,6 +81,10 @@ final class SerializationGraphNavigator extends GraphNavigator
* @var bool
*/
private $shouldSerializeNull;
/**
* @var PropertyNamingStrategyInterface|null
*/
private $contextPropertyNamingStrategy = null;

public function __construct(
MetadataFactoryInterface $metadataFactory,
Expand All @@ -104,6 +109,7 @@ public function initialize(VisitorInterface $visitor, Context $context): void

parent::initialize($visitor, $context);
$this->shouldSerializeNull = $context->shouldSerializeNull();
$this->contextPropertyNamingStrategy = $context->getPropertyNamingStrategy();
}

/**
Expand Down Expand Up @@ -256,6 +262,10 @@ public function accept($data, ?array $type = null)
continue;
}

if ($this->contextPropertyNamingStrategy) {
$propertyMetadata->serializedName = $this->contextPropertyNamingStrategy->translateName($propertyMetadata);
dgafka marked this conversation as resolved.
Show resolved Hide resolved
}

$v = $this->accessor->getValue($data, $propertyMetadata, $this->context);

if (null === $v && true !== $this->shouldSerializeNull) {
Expand Down
18 changes: 18 additions & 0 deletions src/SerializationContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace JMS\Serializer;

use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
use Metadata\MetadataFactoryInterface;

class SerializationContext extends Context
Expand All @@ -24,6 +25,10 @@ class SerializationContext extends Context
* @var bool
*/
private $serializeNull = false;
/**
* @var PropertyNamingStrategyInterface|null
*/
private $propertyNamingStrategy = null;

public static function create(): self
{
Expand All @@ -50,6 +55,14 @@ public function setSerializeNull(bool $bool): self
return $this;
}

public function setPropertyNamingStrategy(PropertyNamingStrategyInterface $propertyNamingStrategy): self
{
$this->assertMutable();
$this->propertyNamingStrategy = $propertyNamingStrategy;

return $this;
}

/**
* Returns TRUE when NULLs should be serialized
* Returns FALSE when NULLs should not be serialized
Expand All @@ -59,6 +72,11 @@ public function shouldSerializeNull(): bool
return $this->serializeNull;
}

public function getPropertyNamingStrategy(): ?PropertyNamingStrategyInterface
{
return $this->propertyNamingStrategy;
}

/**
* @param mixed $object
*/
Expand Down
21 changes: 21 additions & 0 deletions tests/Fixtures/CustomDeserializationObjectWithInnerClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace JMS\Serializer\Tests\Fixtures;

use JMS\Serializer\Annotation\Type;

class CustomDeserializationObjectWithInnerClass
{
/**
* @Type("JMS\Serializer\Tests\Fixtures\CustomDeserializationObject")
*/
#[Type(name: CustomDeserializationObject::class)]
private $someProperty;

public function __construct(CustomDeserializationObject $value)
{
$this->someProperty = $value;
}
}
73 changes: 73 additions & 0 deletions tests/SerializerBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
use JMS\Serializer\Exception\UnsupportedFormatException;
use JMS\Serializer\Expression\ExpressionEvaluator;
use JMS\Serializer\Handler\HandlerRegistry;
use JMS\Serializer\Naming\CamelCaseNamingStrategy;
use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy;
use JMS\Serializer\SerializationContext;
use JMS\Serializer\SerializerBuilder;
use JMS\Serializer\Tests\Fixtures\CustomDeserializationObject;
use JMS\Serializer\Tests\Fixtures\CustomDeserializationObjectWithInnerClass;
use JMS\Serializer\Tests\Fixtures\DocBlockType\Collection\Details\ProductDescription;
use JMS\Serializer\Tests\Fixtures\DocBlockType\SingleClassFromDifferentNamespaceTypeHint;
use JMS\Serializer\Tests\Fixtures\PersonSecret;
Expand Down Expand Up @@ -201,6 +205,75 @@ public function testSetCallbackSerializationContextWithNotSerializeNull()
self::assertEquals('{"not_null":"ok"}', $result);
}

public function testSetCallbackSerializationContextWithIdenticalPropertyNamingStrategy()
{
$this->builder->setSerializationContextFactory(static function () {
return SerializationContext::create()
->setPropertyNamingStrategy(new IdenticalPropertyNamingStrategy());
});

$serializer = $this->builder
->build();

$object = new CustomDeserializationObject('johny');
$json = '{"someProperty":"johny"}';

self::assertEquals($json, $serializer->serialize($object, 'json'));
self::assertEquals($object, $serializer->deserialize($json, get_class($object), 'json'));
}

public function testSetCallbackSerializationContextWithCamelCaseStrategy()
{
$this->builder->setSerializationContextFactory(static function () {
return SerializationContext::create()
->setPropertyNamingStrategy(new CamelCaseNamingStrategy());
});

$serializer = $this->builder
->build();

$object = new CustomDeserializationObject('johny');
$json = '{"some_property":"johny"}';

self::assertEquals($json, $serializer->serialize($object, 'json'));
self::assertEquals($object, $serializer->deserialize($json, get_class($object), 'json'));
}

public function testSetCallbackSerializationContextOverridingDefaultStrategy()
{
$this->builder->setSerializationContextFactory(static function () {
return SerializationContext::create()
->setPropertyNamingStrategy(new IdenticalPropertyNamingStrategy());
});

$serializer = $this->builder
->setPropertyNamingStrategy(new CamelCaseNamingStrategy())
->build();

$object = new CustomDeserializationObject('johny');
$json = '{"someProperty":"johny"}';

self::assertEquals($json, $serializer->serialize($object, 'json'));
self::assertEquals($object, $serializer->deserialize($json, get_class($object), 'json'));
}

public function testSetCallbackSerializationContextWithIdenticalPropertyNamingForInnerClass()
{
$this->builder->setSerializationContextFactory(static function () {
return SerializationContext::create()
->setPropertyNamingStrategy(new CamelCaseNamingStrategy());
});

$serializer = $this->builder
->build();

$object = new CustomDeserializationObjectWithInnerClass(new CustomDeserializationObject('johny'));
$json = '{"some_property":{"some_property":"johny"}}';

self::assertEquals($json, $serializer->serialize($object, 'json'));
self::assertEquals($object, $serializer->deserialize($json, get_class($object), 'json'));
}

public function expressionFunctionProvider()
{
return [
Expand Down