Skip to content
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);
Comment thread
dgafka marked this conversation as resolved.
Outdated
}

$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