Merge remote branch 'Seldaek/serializer'

* Seldaek/serializer:
  [Serializer] CS fixes
  [Serializer] Split supports in supportsNormalization and supportsDenormalization
  [Serializer] Add support for Traversable objects
  Fixed docs typo
  [Serializer] updated SerializerInterface
This commit is contained in:
Fabien Potencier 2011-05-06 22:13:18 +02:00
commit c98bf4ff94
9 changed files with 135 additions and 105 deletions

View File

@ -124,6 +124,9 @@ beta1 to beta2
'allow_delete' => true, 'allow_delete' => true,
)); ));
* Serializer: The NormalizerInterface's `supports()` method has been split in
two methods: `supportsNormalization` and `supportsDenormalization`.
PR12 to beta1 PR12 to beta1
------------- -------------

View File

@ -39,13 +39,27 @@ class CustomNormalizer extends AbstractNormalizer
/** /**
* Checks if the given class implements the NormalizableInterface. * Checks if the given class implements the NormalizableInterface.
* *
* @param ReflectionClass $class A ReflectionClass instance of the class * @param mixed $data Data to normalize.
* to serialize into or from.
* @param string $format The format being (de-)serialized from or into. * @param string $format The format being (de-)serialized from or into.
* @return Boolean * @return Boolean
*/ */
public function supports(\ReflectionClass $class, $format = null) public function supportsNormalization($data, $format = null)
{ {
return $class->implementsInterface('Symfony\Component\Serializer\Normalizer\NormalizableInterface'); return $data instanceof NormalizableInterface;
}
/**
* Checks if the given class implements the NormalizableInterface.
*
* @param mixed $data Data to denormalize from.
* @param string $type The class to which the data should be denormalized.
* @param string $format The format being deserialized from.
* @return Boolean
*/
public function supportsDenormalization($data, $type, $format = null)
{
$class = new \ReflectionClass($type);
return $class->isSubclassOf('Symfony\Component\Serializer\Normalizer\NormalizableInterface');
} }
} }

View File

@ -107,23 +107,37 @@ class GetSetMethodNormalizer extends AbstractNormalizer
return $object; return $object;
} }
/**
* {@inheritDoc}
*/
public function supportsNormalization($data, $format = null)
{
return $this->supports(get_class($data));
}
/**
* {@inheritDoc}
*/
public function supportsDenormalization($data, $type, $format = null)
{
return $this->supports($type);
}
/** /**
* Checks if the given class has any get{Property} method. * Checks if the given class has any get{Property} method.
* *
* @param ReflectionClass $class A ReflectionClass instance of the class * @param string $class
* to serialize into or from. * @return Boolean
* @param string $format The format being (de-)serialized from or into.
* @return Boolean Whether the class has any getters.
*/ */
public function supports(\ReflectionClass $class, $format = null) private function supports($class)
{ {
$class = new \ReflectionClass($type);
$methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC); $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method) { foreach ($methods as $method) {
if ($this->isGetMethod($method)) { if ($this->isGetMethod($method)) {
return true; return true;
} }
} }
return false; return false;
} }

View File

@ -14,7 +14,7 @@ use Symfony\Component\Serializer\SerializerInterface;
*/ */
/** /**
* Defines the interface of serializers * Defines the interface of normalizers.
* *
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
*/ */
@ -43,16 +43,25 @@ interface NormalizerInterface
function denormalize($data, $class, $format = null); function denormalize($data, $class, $format = null);
/** /**
* Checks whether the given class is supported by this normalizer * Checks whether the given class is supported for normalization by this normalizer
*
* @param ReflectionClass $class
* @param string $format format the given data was extracted from
* *
* @param mixed $data Data to normalize.
* @param string $format The format being (de-)serialized from or into.
* @return Boolean * @return Boolean
*
* @api * @api
*/ */
function supports(\ReflectionClass $class, $format = null); function supportsNormalization($data, $format = null);
/**
* Checks whether the given class is supported for denormalization by this normalizer
*
* @param mixed $data Data to denormalize from.
* @param string $type The class to which the data should be denormalized.
* @param string $format The format being deserialized from.
* @return Boolean
* @api
*/
function supportsDenormalization($data, $type, $format = null);
/** /**
* Sets the owning Serializer object * Sets the owning Serializer object

View File

@ -31,6 +31,7 @@ class Serializer implements SerializerInterface
private $normalizers = array(); private $normalizers = array();
private $encoders = array(); private $encoders = array();
protected $normalizerCache = array(); protected $normalizerCache = array();
protected $denormalizerCache = array();
/** /**
* @param mixed $value value to test * @param mixed $value value to test
@ -46,7 +47,14 @@ class Serializer implements SerializerInterface
*/ */
public function serialize($data, $format) public function serialize($data, $format)
{ {
return $this->encode($data, $format); return $this->encode($this->normalize($data, $format), $format);
}
/**
* {@inheritDoc}
*/
public function deserialize($data, $type, $format) {
return $this->denormalize($this->decode($data, $format), $type, $format);
} }
/** /**
@ -61,9 +69,8 @@ class Serializer implements SerializerInterface
if (isset($this->normalizerCache[$class][$format])) { if (isset($this->normalizerCache[$class][$format])) {
return $this->normalizerCache[$class][$format]->normalize($object, $format, $properties); return $this->normalizerCache[$class][$format]->normalize($object, $format, $properties);
} }
$reflClass = new \ReflectionClass($class);
foreach ($this->normalizers as $normalizer) { foreach ($this->normalizers as $normalizer) {
if ($normalizer->supports($reflClass, $format)) { if ($normalizer->supportsNormalization($object, $class, $format)) {
$this->normalizerCache[$class][$format] = $normalizer; $this->normalizerCache[$class][$format] = $normalizer;
return $normalizer->normalize($object, $format, $properties); return $normalizer->normalize($object, $format, $properties);
} }
@ -79,13 +86,12 @@ class Serializer implements SerializerInterface
if (!$this->normalizers) { if (!$this->normalizers) {
throw new \LogicException('You must register at least one normalizer to be able to denormalize objects.'); throw new \LogicException('You must register at least one normalizer to be able to denormalize objects.');
} }
if (isset($this->normalizerCache[$class][$format])) { if (isset($this->denormalizerCache[$class][$format])) {
return $this->normalizerCache[$class][$format]->denormalize($data, $class, $format); return $this->denormalizerCache[$class][$format]->denormalize($data, $class, $format);
} }
$reflClass = new \ReflectionClass($class);
foreach ($this->normalizers as $normalizer) { foreach ($this->normalizers as $normalizer) {
if ($normalizer->supports($reflClass, $format)) { if ($normalizer->supportsDenormalization($class, $format)) {
$this->normalizerCache[$class][$format] = $normalizer; $this->denormalizerCache[$class][$format] = $normalizer;
return $normalizer->denormalize($data, $class, $format); return $normalizer->denormalize($data, $class, $format);
} }
} }
@ -95,20 +101,38 @@ class Serializer implements SerializerInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function normalize($data, $format) public function normalize($data, $format = null)
{ {
if (is_array($data)) { if (!$this->isStructuredType($data)) {
foreach ($data as $key => $val) {
$data[$key] = $this->isStructuredType($val) ? $this->normalize($val, $format) : $val;
}
return $data; return $data;
} }
if ($data instanceof Traversable) {
$normalized = array();
foreach ($data as $key => $val) {
$normalized[$key] = $this->normalize($val, $format);
}
return $normalized;
}
if (is_object($data)) { if (is_object($data)) {
return $this->normalizeObject($data, $format); return $this->normalizeObject($data, $format);
} }
if (is_array($data)) {
foreach ($data as $key => $val) {
$data[$key] = $this->normalize($val, $format);
}
return $data;
}
throw new \UnexpectedValueException('An unexpected value could not be normalized: '.var_export($data, true)); throw new \UnexpectedValueException('An unexpected value could not be normalized: '.var_export($data, true));
} }
/**
* {@inheritDoc}
*/
public function denormalize($data, $type, $format = null)
{
return $this->denormalizeObject($data, $type, $format);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@ -31,6 +31,15 @@ interface SerializerInterface
*/ */
function serialize($data, $format); function serialize($data, $format);
/**
* Deserializes data into the given type.
*
* @param mixed $data
* @param string $type
* @param string $format
*/
function deserialize($data, $type, $format);
/** /**
* Normalizes any data into a set of arrays/scalars * Normalizes any data into a set of arrays/scalars
* *
@ -39,27 +48,18 @@ interface SerializerInterface
* @return array|scalar * @return array|scalar
* @api * @api
*/ */
function normalize($data, $format); function normalize($data, $format = null);
/** /**
* Normalizes an object into a set of arrays/scalars * Denormalizes data into the given type.
* *
* @param object $object object to normalize * @param mixed $data
* @param string $format format name, present to give the option to normalizers to act differently based on formats * @param string $type
* @param array $properties a list of properties to extract, if null all properties are returned * @param string $format
* @return array|scalar
*/
function normalizeObject($object, $format, $properties = null);
/**
* Denormalizes data back into an object of the given class
* *
* @param mixed $data data to restore * @return mixed
* @param string $class the expected class to instantiate
* @param string $format format name, present to give the option to normalizers to act differently based on formats
* @return object
*/ */
function denormalizeObject($data, $class, $format = null); function denormalize($data, $type, $format = null);
/** /**
* Encodes data into the given format * Encodes data into the given format
@ -80,48 +80,4 @@ interface SerializerInterface
* @api * @api
*/ */
function decode($data, $format); function decode($data, $format);
/**
* @param NormalizerInterface $normalizer
*/
function addNormalizer(NormalizerInterface $normalizer);
/**
* @return array[]NormalizerInterface
*/
function getNormalizers();
/**
* @param NormalizerInterface $normalizer
*/
function removeNormalizer(NormalizerInterface $normalizer);
/**
* @param string $format format name
* @param EncoderInterface $encoder
*/
function setEncoder($format, EncoderInterface $encoder);
/**
* @return EncoderInterface
*/
function getEncoders();
/**
* @return array[]EncoderInterface
*/
function getEncoder($format);
/**
* Checks whether the serializer has an encoder registered for the given format
*
* @param string $format format name
* @return Boolean
*/
function hasEncoder($format);
/**
* @param string $format format name
*/
function removeEncoder($format);
} }

View File

@ -44,9 +44,15 @@ class CustomNormalizerTest extends \PHPUnit_Framework_TestCase
$this->assertNull($obj->xmlFoo); $this->assertNull($obj->xmlFoo);
} }
public function testSupports() public function testSupportsNormalization()
{ {
$this->assertTrue($this->normalizer->supports(new \ReflectionClass(get_class(new ScalarDummy)))); $this->assertTrue($this->normalizer->supportsNormalization(new ScalarDummy));
$this->assertFalse($this->normalizer->supports(new \ReflectionClass('stdClass'))); $this->assertFalse($this->normalizer->supportsNormalization(new \stdClass));
}
public function testSupportsDenormalization()
{
$this->assertTrue($this->normalizer->supportsDenormalization(array(), 'Symfony\Tests\Component\Serializer\Fixtures\ScalarDummy'));
$this->assertFalse($this->normalizer->supportsDenormalization(array(), 'stdClass'));
} }
} }

View File

@ -29,7 +29,8 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase
$obj->setBar('bar'); $obj->setBar('bar');
$this->assertEquals( $this->assertEquals(
array('foo' => 'foo', 'bar' => 'bar', 'foobar' => 'foobar'), array('foo' => 'foo', 'bar' => 'bar', 'foobar' => 'foobar'),
$this->normalizer->normalize($obj, 'any')); $this->normalizer->normalize($obj, 'any')
);
} }
public function testNormalizeRestricted() public function testNormalizeRestricted()
@ -39,14 +40,17 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase
$obj->setBar('bar'); $obj->setBar('bar');
$this->assertEquals( $this->assertEquals(
array('foo' => 'foo'), array('foo' => 'foo'),
$this->normalizer->normalize($obj, 'any', array('foo'))); $this->normalizer->normalize($obj, 'any', array('foo'))
);
} }
public function testDenormalize() public function testDenormalize()
{ {
$obj = $this->normalizer->denormalize( $obj = $this->normalizer->denormalize(
array('foo' => 'foo', 'bar' => 'bar', 'foobar' => 'foobar'), array('foo' => 'foo', 'bar' => 'bar', 'foobar' => 'foobar'),
__NAMESPACE__.'\GetSetDummy', 'any'); __NAMESPACE__.'\GetSetDummy',
'any'
);
$this->assertEquals('foo', $obj->getFoo()); $this->assertEquals('foo', $obj->getFoo());
$this->assertEquals('bar', $obj->getBar()); $this->assertEquals('bar', $obj->getBar());
} }