Skip to content

Commit

Permalink
Merge pull request #47 from superbrave/normalize-strategy
Browse files Browse the repository at this point in the history
Added traversable normalization for the Exporter class
  • Loading branch information
Jelle van Oosterbosch authored Feb 10, 2020
2 parents 0a22598 + 39dcf8b commit 04795b1
Show file tree
Hide file tree
Showing 10 changed files with 290 additions and 21 deletions.
10 changes: 10 additions & 0 deletions Resources/config/services.exporter.types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ services:
_defaults:
public: false

superbrave_gdpr.exporter.serializer.normalizer.iterable_normalizer:
class: Superbrave\GdprBundle\Serializer\Normalizer\IterableNormalizer
tags:
- { name: "superbrave_gdpr.serializer.normalizer" }

superbrave_gdpr.exporter.serializer.normalizer.datetime_normalizer:
class: Symfony\Component\Serializer\Normalizer\DateTimeNormalizer
tags:
- { name: "superbrave_gdpr.serializer.normalizer" }

superbrave_gdpr.exporter.serializer.normalizer.export_annotation:
class: Superbrave\GdprBundle\Serializer\Normalizer\AnnotationNormalizer
arguments:
Expand Down
21 changes: 15 additions & 6 deletions Serializer/Normalizer/AnnotationNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,20 @@
use Superbrave\GdprBundle\Annotation\AnnotationReader;
use Superbrave\GdprBundle\Manipulator\PropertyManipulator;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

/**
* Normalizes object data based on the specified property annotation.
*
* @author Niels Nijens <nn@superbrave.nl>
* @author Jelle van Oosterbosch <jvo@superbrave.nl>
*/
class AnnotationNormalizer implements NormalizerInterface
class AnnotationNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
use NormalizerAwareTrait;

/**
* The AnnotationReader instance.
*
Expand Down Expand Up @@ -70,6 +75,8 @@ public function __construct(
* @param string $format The format being (de-)serialized from or into
*
* @return bool
*
* @throws \ReflectionException
*/
public function supportsNormalization($data, $format = null)
{
Expand All @@ -93,6 +100,8 @@ public function supportsNormalization($data, $format = null)
* @param array $context Context options for the normalizer
*
* @return array|string|int|float|bool
*
* @throws \ReflectionException
*/
public function normalize($object, $format = null, array $context = array())
{
Expand All @@ -108,7 +117,11 @@ public function normalize($object, $format = null, array $context = array())
$propertyName = $propertyAnnotation->alias;
}

$normalizedData[$propertyName] = $this->getMappedPropertyValue($propertyAnnotation, $propertyValue);
if (false === is_scalar($propertyValue)) {
$normalizedData[$propertyName] = $this->normalizer->normalize($propertyValue, $format, $context);
} else {
$normalizedData[$propertyName] = $this->getMappedPropertyValue($propertyAnnotation, $propertyValue);
}
}

return $normalizedData;
Expand All @@ -124,10 +137,6 @@ public function normalize($object, $format = null, array $context = array())
*/
private function getMappedPropertyValue($annotation, $propertyValue)
{
if (is_scalar($propertyValue) === false) {
return $propertyValue;
}

if (property_exists($annotation, 'valueMap') === false || isset($annotation->valueMap) === false) {
return $propertyValue;
}
Expand Down
53 changes: 53 additions & 0 deletions Serializer/Normalizer/IterableNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
/**
* This file is part of the GDPR bundle.
*
* @category Bundle
* @package Gdpr
* @author SuperBrave <info@superbrave.nl>
* @copyright 2018 SuperBrave <info@superbrave.nl>
* @license https://github.com/superbrave/gdpr-bundle/blob/master/LICENSE MIT
* @link https://www.superbrave.nl/
*/

namespace Superbrave\GdprBundle\Serializer\Normalizer;

use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

/**
* Normalizes data if it's iterable by calling the normalizer chain.
*
* @author Jelle van Oosterbosch <jvo@superbrave.nl>
*/
class IterableNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
use NormalizerAwareTrait;

/**
* {@inheritdoc}
*/
public function supportsNormalization($data, $format = null)
{
if (is_array($data) || $data instanceof \Traversable) {
return true;
}

return false;
}

/**
* {@inheritdoc}
*/
public function normalize($object, $format = null, array $context = array())
{
$normalizedData = [];

foreach ($object as $value) {
$normalizedData[] = $this->normalizer->normalize($value, $format, $context);
}

return $normalizedData;
}
}
20 changes: 20 additions & 0 deletions Tests/AnnotatedMock.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* Class used to test the @see GDPR\AnnotationReader.
*
* @author Niels Nijens <nn@superbrave.nl>
* @author Jelle van Oosterbosch <jvo@superbrave.nl>
*/
class AnnotatedMock
{
Expand Down Expand Up @@ -59,6 +60,15 @@ class AnnotatedMock
*/
private $quux;

/**
* The quuz property.
*
* @GDPR\Export()
*
* @var \DateTime
*/
private $quuz;

/**
* The property that is annotated with the Export annotation, but without getter method.
*
Expand Down Expand Up @@ -90,8 +100,10 @@ public function __construct(AnnotatedMock $annotatedMock = null)
$elements = array();
if ($annotatedMock instanceof AnnotatedMock) {
$elements[] = $annotatedMock;
$elements[] = clone $annotatedMock;
}

$this->quuz = new \DateTime('2016/01/01');
$this->quux = new ArrayCollection($elements);
}

Expand Down Expand Up @@ -135,6 +147,14 @@ public function getQuux()
return $this->quux;
}

/**
* @return \DateTime
*/
public function getQuuz()
{
return $this->quuz;
}

/**
* Returns the value of the notAnnotatedProperty property.
*
Expand Down
10 changes: 6 additions & 4 deletions Tests/Annotation/AnnotationReaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
* AnnotationReaderTest.
*
* @author Niels Nijens <nn@superbrave.nl>
* @author Jelle van Oosterbosch <jvo@superbrave.nl>
*/
class AnnotationReaderTest extends PHPUnit_Framework_TestCase
{
Expand Down Expand Up @@ -64,9 +65,9 @@ public function testGetPropertiesWithAnnotationExport()
);

$this->assertInternalType('array', $result);
$this->assertCount(5, $result);
$this->assertCount(6, $result);
$this->assertSame(
array('foo', 'baz', 'qux', 'quux', 'annotatedPropertyWithoutMethod'),
array('foo', 'baz', 'qux', 'quux', 'quuz', 'annotatedPropertyWithoutMethod'),
array_keys($result)
);
$this->assertInstanceOf(Export::class, current($result));
Expand Down Expand Up @@ -108,11 +109,12 @@ public function testGetPropertiesWithAnnotationForExtendedClass()
);

$this->assertInternalType('array', $result);
$this->assertCount(6, $result);
$this->assertCount(7, $result);
$this->assertSame(
array('extendedProperty', 'foo', 'baz', 'qux', 'quux', 'annotatedPropertyWithoutMethod'),
array('extendedProperty', 'foo', 'baz', 'qux', 'quux', 'quuz', 'annotatedPropertyWithoutMethod'),
array_keys($result)
);

$this->assertInstanceOf(Export::class, current($result));
}
}
1 change: 1 addition & 0 deletions Tests/Resources/json/annotation_normalize_result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"foo":"bar","baz":1,"qux":[],"quuxs":[{"foo":"bar","baz":1,"qux":[],"quuxs":[],"quuz":"2016-01-01T00:00:00+00:00","annotatedPropertyWithoutMethod":"Yes"},{"foo":"bar","baz":1,"qux":[],"quuxs":[],"quuz":"2016-01-01T00:00:00+00:00","annotatedPropertyWithoutMethod":"Yes"}],"quuz":"2016-01-01T00:00:00+00:00","annotatedPropertyWithoutMethod":"Yes"}
1 change: 1 addition & 0 deletions Tests/Resources/json/iterable_normalize_result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["bar",1,[["2020-01-01T00:00:00+00:00","2020-01-01T00:00:00+00:00"]]]
2 changes: 1 addition & 1 deletion Tests/Resources/xml/annotation_normalizer_result.xml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
<?xml version="1.0"?>
<mock><foo>bar</foo><baz>1</baz><qux/><quuxs><item key="0"><foo>bar</foo><baz>1</baz><qux/><quuxs/><annotatedPropertyWithoutMethod>Yes</annotatedPropertyWithoutMethod></item></quuxs><annotatedPropertyWithoutMethod>Yes</annotatedPropertyWithoutMethod></mock>
<mock><foo>bar</foo><baz>1</baz><qux/><quuxs><foo>bar</foo><baz>1</baz><qux/><quuxs/><quuz>2016-01-01T00:00:00+00:00</quuz><annotatedPropertyWithoutMethod>Yes</annotatedPropertyWithoutMethod></quuxs><quuxs><foo>bar</foo><baz>1</baz><qux/><quuxs/><quuz>2016-01-01T00:00:00+00:00</quuz><annotatedPropertyWithoutMethod>Yes</annotatedPropertyWithoutMethod></quuxs><quuz>2016-01-01T00:00:00+00:00</quuz><annotatedPropertyWithoutMethod>Yes</annotatedPropertyWithoutMethod></mock>
67 changes: 57 additions & 10 deletions Tests/Serializer/Normalizer/AnnotationNormalizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,25 @@

namespace Superbrave\GdprBundle\Tests\Serializer\Normalizer;

use Doctrine\Common\Collections\ArrayCollection;
use PHPUnit_Framework_MockObject_MockObject;
use ReflectionClass;
use Superbrave\GdprBundle\Annotation\AnnotationReader;
use Superbrave\GdprBundle\Annotation\Export;
use Superbrave\GdprBundle\Manipulator\PropertyManipulator;
use Superbrave\GdprBundle\Serializer\Normalizer\AnnotationNormalizer;
use Superbrave\GdprBundle\Serializer\Normalizer\IterableNormalizer;
use Superbrave\GdprBundle\Tests\AnnotatedMock;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\Serializer\Serializer;

/**
* AnnotationNormalizerTest.
*
* @author Niels Nijens <nn@superbrave.nl>
* @author Jelle van Oosterbosch <jvo@superbrave.nl>
*/
class AnnotationNormalizerTest extends \PHPUnit_Framework_TestCase
{
Expand Down Expand Up @@ -153,47 +156,91 @@ public function testNormalize()
);

$normalizer = new AnnotationNormalizer($annotationReader, Export::class, $propertyManipulator);
$serializer = new Serializer([
new DateTimeNormalizer(),
new IterableNormalizer(),
$normalizer,
]);
$normalizer->setNormalizer($serializer);

$annotatedMock = new AnnotatedMock();

$this->assertEquals(
array(
'foo' => 'bar',
'baz' => 1,
'qux' => array(),
'quuxs' => new ArrayCollection(),
'qux' => [],
'quuxs' => [],
'quuz' => '2016-01-01T00:00:00+00:00',
'annotatedPropertyWithoutMethod' => 'Yes',
),
$normalizer->normalize($annotatedMock)
);
}

/**
* Tests if AnnotationNormalizer::normalize returns the expected normalized data
* Tests if @see AnnotationNormalizer::normalize returns the expected xml normalized data
* for serialization through the Serializer.
*
* @return void
*/
public function testNormalizeThroughSerializer()
public function testNormalizeThroughXmlSerializer()
{
$annotationReader = new AnnotationReader();
$propertyManipulator = new PropertyManipulator(
PropertyAccess::createPropertyAccessor()
);

$normalizer = new AnnotationNormalizer($annotationReader, Export::class, $propertyManipulator);
$encoder = new XmlEncoder('mock');
$normalizers = [
new DateTimeNormalizer(),
new IterableNormalizer(),
new AnnotationNormalizer($annotationReader, Export::class, $propertyManipulator),
];
$encoders = [new XmlEncoder('mock')];

$serializer = new Serializer(
array($normalizer),
array($encoder)
$normalizers,
$encoders
);

$data = new AnnotatedMock(new AnnotatedMock());

$this->assertStringEqualsFile(
__DIR__.'/../../Resources/xml/annotation_normalizer_result.xml',
__DIR__ . '/../../Resources/xml/annotation_normalizer_result.xml',
$serializer->serialize($data, 'xml')
);
}

/**
* Test if @see AnnotationNormalizer::normalize returns the expected json normalized data
* for serialization through the Serializer.
*
* @return void
*/
public function testNormalizeThroughJsonSerializer()
{
$annotationReader = new AnnotationReader();
$propertyManipulator = new PropertyManipulator(
PropertyAccess::createPropertyAccessor()
);

$normalizers = [
new DateTimeNormalizer(),
new IterableNormalizer(),
new AnnotationNormalizer($annotationReader, Export::class, $propertyManipulator),
];
$encoders = [new JsonEncoder()];

$serializer = new Serializer(
$normalizers,
$encoders
);

$data = new AnnotatedMock(new AnnotatedMock());

$this->assertStringEqualsFile(
__DIR__ . '/../../Resources/json/annotation_normalize_result.json',
$serializer->serialize($data, 'json')
);
}
}
Loading

0 comments on commit 04795b1

Please sign in to comment.