Skip to content

Instantly share code, notes, and snippets.

@rhpaiva
Last active January 3, 2019 11:39
Show Gist options
  • Save rhpaiva/7d08b2bb647e7100a65002327454bcd7 to your computer and use it in GitHub Desktop.
Save rhpaiva/7d08b2bb647e7100a65002327454bcd7 to your computer and use it in GitHub Desktop.
JMS Serializer Visitor Service that does not perform type casting on deserialization.
<?php
declare(strict_types = 1);
namespace Api\Request;
use Api\Request\Exception\DeserializationException;
use JMS\Serializer\Context;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\GenericDeserializationVisitor;
use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
/**
* Reimplements JMS Serializer visitor methods without type casting.
*
* @package Api\Request
*/
class ApiJsonDeserializationVisitor extends GenericDeserializationVisitor
{
private $result;
/**
* @var JsonDeserializationVisitor
*/
private $jsonDeserializationVisitor;
/**
* Overwriting the constructor to be able to pass the original JSON visitor.
*
* @param PropertyNamingStrategyInterface $namingStrategy
* @param JsonDeserializationVisitor $jsonDeserializationVisitor
*/
public function __construct(
PropertyNamingStrategyInterface $namingStrategy,
JsonDeserializationVisitor $jsonDeserializationVisitor
) {
$this->jsonDeserializationVisitor = $jsonDeserializationVisitor;
parent::__construct($namingStrategy);
}
/**
* @param mixed $data
* @param array $type
* @param Context $context
*
* @return bool|mixed
*/
public function visitBoolean($data, array $type, Context $context)
{
return $this->visit($data);
}
/**
* @param mixed $data
* @param array $type
* @param Context $context
*
* @return bool|mixed
*/
public function visitDouble($data, array $type, Context $context)
{
return $this->visit($data);
}
/**
* @param mixed $data
* @param array $type
* @param Context $context
*
* @return bool|mixed
*/
public function visitInteger($data, array $type, Context $context)
{
return $this->visit($data);
}
/**
* @param mixed $data
* @param array $type
* @param Context $context
*
* @return bool|mixed
*/
public function visitString($data, array $type, Context $context)
{
return $this->visit($data);
}
/**
* Proxy to the original decode() from JMS Serializer.
*
* @param $str
*
* @return array
* @throws DeserializationException When deserialization fails.
*/
protected function decode($str)
{
try {
$decoded = $this->jsonDeserializationVisitor->decode($str);
} catch (RuntimeException $e) {
throw new DeserializationException($e->getMessage(), $e->getCode(), $e->getPrevious());
}
return $decoded;
}
/**
* Reimplementation of visit<Type> from base class.
*
* @param $data
*
* @return mixed
*/
private function visit($data)
{
if ($this->result === null) {
$this->result = $data;
}
return $data;
}
}
<?php
declare(strict_types = 1);
namespace Tests\Unit\Api\Request;
use Api\Request\Exception\DeserializationException;
use JMS\Serializer\Context;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
use Api\Request\ApiJsonDeserializationVisitor;
/**
* Class ApiJsonDeserializationVisitorTest
* @package Tests\Unit\Api\Request
*/
class ApiJsonDeserializationVisitorTest extends \PHPUnit_Framework_TestCase
{
/**
* @var PropertyNamingStrategyInterface
*/
private $namingStrategy;
/**
* @var JsonDeserializationVisitor
*/
private $originalJsonVisitor;
/**
* @var ApiJsonDeserializationVisitor
*/
private $apiJsonVisitor;
/**
* @var Context
*/
private $serializationContext;
public function setUp()
{
$this->namingStrategy = self::createMock(PropertyNamingStrategyInterface::class);
$this->originalJsonVisitor = self::createMock(JsonDeserializationVisitor::class);
$this->apiJsonVisitor = new ApiJsonDeserializationVisitor(
$this->namingStrategy,
$this->originalJsonVisitor
);
$this->serializationContext = self::createMock(Context::class);
}
/**
* @param mixed $data
*
* @dataProvider providerDeserializationData
*/
public function testBooleanVisitorPerformsNoTypeCast($data)
{
$visitedData = $this->apiJsonVisitor->visitBoolean($data, [], $this->serializationContext);
self::assertEquals($data, $visitedData);
}
/**
* @param mixed $data
*
* @dataProvider providerDeserializationData
*/
public function testDoubleVisitorPerformsNoTypeCast($data)
{
$visitedData = $this->apiJsonVisitor->visitDouble($data, [], $this->serializationContext);
self::assertEquals($data, $visitedData);
}
/**
* @param mixed $data
*
* @dataProvider providerDeserializationData
*/
public function testIntegerVisitorPerformsNoTypeCast($data)
{
$visitedData = $this->apiJsonVisitor->visitInteger($data, [], $this->serializationContext);
self::assertEquals($data, $visitedData);
}
/**
* @param mixed $data
*
* @dataProvider providerDeserializationData
*/
public function testStringVisitorPerformsNoTypeCast($data)
{
$visitedData = $this->apiJsonVisitor->visitString($data, [], $this->serializationContext);
self::assertEquals($data, $visitedData);
}
/**
* @return array
*/
public function providerDeserializationData()
{
return [
['23edsa'],
['asd23edsa'],
['asdedsa'],
[54.564],
[0.00254684],
[3565],
[false],
[true],
[0],
[1],
];
}
/**
* @covers ApiJsonDeserializationVisitor::decode
*/
public function testDeserializationError()
{
self::expectException(DeserializationException::class);
$this->apiJsonVisitor->prepare('asdsad');
}
}
<?php
declare(strict_types = 1);
namespace Api\Request\Exception;
/**
* Exception thrown during a JSON deserialization.
*
* @package Api\Request\Exception
*/
class DeserializationException extends \RuntimeException
{
}
# this goes into your Symfony service definition
# overwrites the default json deserializer from JMSSerializer
api.request.json_deserialization_visitor:
class: Api\Request\ApiJsonDeserializationVisitor
decorates: jms_serializer.json_deserialization_visitor
decoration_inner_name: jms_serializer.json_deserialization_visitor.original
arguments:
- '@jms_serializer.cache_naming_strategy'
- '@jms_serializer.json_deserialization_visitor.original'
tags:
- { name: jms_serializer.deserialization_visitor, format: json }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment