Skip to content

Commit

Permalink
feature #17545 [Serializer] Add normalizer / denormalizer awarness (j…
Browse files Browse the repository at this point in the history
…oelwurtz)

This PR was merged into the 3.1-dev branch.

Discussion
----------

[Serializer] Add normalizer / denormalizer awarness

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        |

SerializerAwareInterface is not really usable in a decode -> normalize context, as if we need to transform a subproperty with another class, we only have the context of a serialize however the data is already decoded so it will fail.

This interfaces allow a normalizer / denormalizer to have a sub normalization / denormalization process context and not the whole context with serializer.

I have also add a `AwareNormalizer` which is an abstract class implementing the 3 aware interfaces like it was done with the SerializerAwareNormalizer, since it's a standard way to implement this interfaces.

This is needed for #17516, other solution would be to have a RawDecoder which don't decode and return the input as it is, but really not a fan of this solution.

Commits
-------

790fb6e Add normalizer / denormalizer awarness
  • Loading branch information
dunglas committed Feb 22, 2016
2 parents 66a64ae + 790fb6e commit 2f8f9d4
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 15 deletions.
Expand Up @@ -17,14 +17,18 @@
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface;
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerAwareTrait;

/**
* Normalizer implementation.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
abstract class AbstractNormalizer extends SerializerAwareNormalizer implements NormalizerInterface, DenormalizerInterface
abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
{
use SerializerAwareTrait;

const CIRCULAR_REFERENCE_LIMIT = 'circular_reference_limit';
const OBJECT_TO_POPULATE = 'object_to_populate';
const GROUPS = 'groups';
Expand Down
Expand Up @@ -11,11 +11,16 @@

namespace Symfony\Component\Serializer\Normalizer;

use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerAwareTrait;

/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class CustomNormalizer extends SerializerAwareNormalizer implements NormalizerInterface, DenormalizerInterface
class CustomNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
{
use SerializerAwareTrait;

/**
* {@inheritdoc}
*/
Expand Down
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Serializer\Normalizer;

/**
* Class accepting a denormalizer.
*
* @author Joel Wurtz <joel.wurtz@gmail.com>
*/
interface DenormalizerAwareInterface
{
/**
* Sets the owning Denormalizer object.
*
* @param DenormalizerInterface $denormalizer
*/
public function setDenormalizer(DenormalizerInterface $denormalizer);
}
@@ -0,0 +1,35 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Serializer\Normalizer;

/**
* DenormalizerAware trait.
*
* @author Joel Wurtz <joel.wurtz@gmail.com>
*/
trait DenormalizerAwareTrait
{
/**
* @var DenormalizerInterface
*/
protected $denormalizer;

/**
* Sets the Denormalizer.
*
* @param DenormalizerInterface $denormalizer A DenormalizerInterface instance
*/
public function setSerializer(DenormalizerInterface $denormalizer)
{
$this->denormalizer = $denormalizer;
}
}
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Serializer\Normalizer;

/**
* Class accepting a normalizer.
*
* @author Joel Wurtz <joel.wurtz@gmail.com>
*/
interface NormalizerAwareInterface
{
/**
* Sets the owning Normalizer object.
*
* @param NormalizerInterface $normalizer
*/
public function setNormalizer(NormalizerInterface $normalizer);
}
@@ -0,0 +1,35 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Serializer\Normalizer;

/**
* NormalizerAware trait.
*
* @author Joel Wurtz <joel.wurtz@gmail.com>
*/
trait NormalizerAwareTrait
{
/**
* @var NormalizerInterface
*/
protected $normalizer;

/**
* Sets the normalizer.
*
* @param NormalizerInterface $normalizer A NormalizerInterface instance
*/
public function setSerializer(NormalizerInterface $normalizer)
{
$this->normalizer = $normalizer;
}
}
Expand Up @@ -11,26 +11,17 @@

namespace Symfony\Component\Serializer\Normalizer;

use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Serializer\SerializerAwareTrait;
use Symfony\Component\Serializer\SerializerAwareInterface;

/**
* SerializerAware Normalizer implementation.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*
* @deprecated since version 3.1, to be removed in 4.0. Use the SerializerAwareTrait instead.
*/
abstract class SerializerAwareNormalizer implements SerializerAwareInterface
{
/**
* @var SerializerInterface
*/
protected $serializer;

/**
* {@inheritdoc}
*/
public function setSerializer(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
use SerializerAwareTrait;
}
10 changes: 10 additions & 0 deletions src/Symfony/Component/Serializer/Serializer.php
Expand Up @@ -15,6 +15,8 @@
use Symfony\Component\Serializer\Encoder\ChainEncoder;
use Symfony\Component\Serializer\Encoder\EncoderInterface;
use Symfony\Component\Serializer\Encoder\DecoderInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Exception\LogicException;
Expand Down Expand Up @@ -68,6 +70,14 @@ public function __construct(array $normalizers = array(), array $encoders = arra
if ($normalizer instanceof SerializerAwareInterface) {
$normalizer->setSerializer($this);
}

if ($normalizer instanceof DenormalizerAwareInterface) {
$normalizer->setDenormalizer($this);
}

if ($normalizer instanceof NormalizerAwareInterface) {
$normalizer->setNormalizer($this);
}
}
$this->normalizers = $normalizers;

Expand Down
35 changes: 35 additions & 0 deletions src/Symfony/Component/Serializer/SerializerAwareTrait.php
@@ -0,0 +1,35 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Serializer;

/**
* SerializerAware trait.
*
* @author Joel Wurtz <joel.wurtz@gmail.com>
*/
trait SerializerAwareTrait
{
/**
* @var SerializerInterface
*/
protected $serializer;

/**
* Sets the serializer.
*
* @param SerializerInterface $serializer A SerializerInterface instance
*/
public function setSerializer(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
}
24 changes: 24 additions & 0 deletions src/Symfony/Component/Serializer/Tests/SerializerTest.php
Expand Up @@ -12,6 +12,10 @@
namespace Symfony\Component\Serializer\Tests;

use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
use Symfony\Component\Serializer\Serializer;
Expand Down Expand Up @@ -312,6 +316,26 @@ public function testDeserializeArray()
$serializer->deserialize($jsonData, __NAMESPACE__.'\Model[]', 'json')
);
}

public function testNormalizerAware()
{
$normalizerAware = $this->getMock(NormalizerAwareInterface::class);
$normalizerAware->expects($this->once())
->method('setNormalizer')
->with($this->isInstanceOf(NormalizerInterface::class));

new Serializer([$normalizerAware]);
}

public function testDenormalizerAware()
{
$denormalizerAware = $this->getMock(DenormalizerAwareInterface::class);
$denormalizerAware->expects($this->once())
->method('setDenormalizer')
->with($this->isInstanceOf(DenormalizerInterface::class));

new Serializer([$denormalizerAware]);
}
}

class Model
Expand Down

0 comments on commit 2f8f9d4

Please sign in to comment.