feature #19371 [Serializer] Give access to the context to support* methods (dunglas)
This PR was squashed before being merged into the 3.3-dev branch (closes #19371).
Discussion
----------
[Serializer] Give access to the context to support* methods
| Q | A |
| --- | --- |
| Branch? | master |
| Bug fix? | no (?) |
| New feature? | yes |
| BC breaks? | no |
| Deprecations? | no |
| Tests pass? | yes |
| Fixed tickets | - |
| License | MIT |
| Doc PR | n/a |
This is a current use case to want to access the context form the `supports*` methods. This PR fixes this limitation.
Maybe can it be considered a bug fix?
Commits
-------
6a7a16e517
[Serializer] Give access to the context to support* methods
This commit is contained in:
commit
17b43632b5
@ -22,7 +22,7 @@ use Symfony\Component\Serializer\Exception\RuntimeException;
|
||||
*
|
||||
* @final since version 3.3.
|
||||
*/
|
||||
class ChainDecoder implements DecoderInterface
|
||||
class ChainDecoder implements DecoderInterface /*, ContextAwareDecoderInterface*/
|
||||
{
|
||||
protected $decoders = array();
|
||||
protected $decoderByFormat = array();
|
||||
@ -37,16 +37,18 @@ class ChainDecoder implements DecoderInterface
|
||||
*/
|
||||
final public function decode($data, $format, array $context = array())
|
||||
{
|
||||
return $this->getDecoder($format)->decode($data, $format, $context);
|
||||
return $this->getDecoder($format, $context)->decode($data, $format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsDecoding($format)
|
||||
public function supportsDecoding($format/*, array $context = array()*/)
|
||||
{
|
||||
$context = func_num_args() > 1 ? func_get_arg(1) : array();
|
||||
|
||||
try {
|
||||
$this->getDecoder($format);
|
||||
$this->getDecoder($format, $context);
|
||||
} catch (RuntimeException $e) {
|
||||
return false;
|
||||
}
|
||||
@ -58,12 +60,13 @@ class ChainDecoder implements DecoderInterface
|
||||
* Gets the decoder supporting the format.
|
||||
*
|
||||
* @param string $format
|
||||
* @param array $context
|
||||
*
|
||||
* @return DecoderInterface
|
||||
*
|
||||
* @throws RuntimeException If no decoder is found.
|
||||
*/
|
||||
private function getDecoder($format)
|
||||
private function getDecoder($format, array $context)
|
||||
{
|
||||
if (isset($this->decoderByFormat[$format])
|
||||
&& isset($this->decoders[$this->decoderByFormat[$format]])
|
||||
@ -72,7 +75,7 @@ class ChainDecoder implements DecoderInterface
|
||||
}
|
||||
|
||||
foreach ($this->decoders as $i => $decoder) {
|
||||
if ($decoder->supportsDecoding($format)) {
|
||||
if ($decoder->supportsDecoding($format, $context)) {
|
||||
$this->decoderByFormat[$format] = $i;
|
||||
|
||||
return $decoder;
|
||||
|
@ -22,7 +22,7 @@ use Symfony\Component\Serializer\Exception\RuntimeException;
|
||||
*
|
||||
* @final since version 3.3.
|
||||
*/
|
||||
class ChainEncoder implements EncoderInterface
|
||||
class ChainEncoder implements EncoderInterface /*, ContextAwareEncoderInterface*/
|
||||
{
|
||||
protected $encoders = array();
|
||||
protected $encoderByFormat = array();
|
||||
@ -37,16 +37,18 @@ class ChainEncoder implements EncoderInterface
|
||||
*/
|
||||
final public function encode($data, $format, array $context = array())
|
||||
{
|
||||
return $this->getEncoder($format)->encode($data, $format, $context);
|
||||
return $this->getEncoder($format, $context)->encode($data, $format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsEncoding($format)
|
||||
public function supportsEncoding($format/*, array $context = array()*/)
|
||||
{
|
||||
$context = func_num_args() > 1 ? func_get_arg(1) : array();
|
||||
|
||||
try {
|
||||
$this->getEncoder($format);
|
||||
$this->getEncoder($format, $context);
|
||||
} catch (RuntimeException $e) {
|
||||
return false;
|
||||
}
|
||||
@ -58,19 +60,21 @@ class ChainEncoder implements EncoderInterface
|
||||
* Checks whether the normalization is needed for the given format.
|
||||
*
|
||||
* @param string $format
|
||||
* @param array $context
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function needsNormalization($format)
|
||||
public function needsNormalization($format/*, array $context = array()*/)
|
||||
{
|
||||
$encoder = $this->getEncoder($format);
|
||||
$context = func_num_args() > 1 ? func_get_arg(1) : array();
|
||||
$encoder = $this->getEncoder($format, $context);
|
||||
|
||||
if (!$encoder instanceof NormalizationAwareInterface) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($encoder instanceof self) {
|
||||
return $encoder->needsNormalization($format);
|
||||
return $encoder->needsNormalization($format, $context);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -80,12 +84,13 @@ class ChainEncoder implements EncoderInterface
|
||||
* Gets the encoder supporting the format.
|
||||
*
|
||||
* @param string $format
|
||||
* @param array $context
|
||||
*
|
||||
* @return EncoderInterface
|
||||
*
|
||||
* @throws RuntimeException if no encoder is found
|
||||
*/
|
||||
private function getEncoder($format)
|
||||
private function getEncoder($format, array $context)
|
||||
{
|
||||
if (isset($this->encoderByFormat[$format])
|
||||
&& isset($this->encoders[$this->encoderByFormat[$format]])
|
||||
@ -94,7 +99,7 @@ class ChainEncoder implements EncoderInterface
|
||||
}
|
||||
|
||||
foreach ($this->encoders as $i => $encoder) {
|
||||
if ($encoder->supportsEncoding($format)) {
|
||||
if ($encoder->supportsEncoding($format, $context)) {
|
||||
$this->encoderByFormat[$format] = $i;
|
||||
|
||||
return $encoder;
|
||||
|
@ -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\Encoder;
|
||||
|
||||
/**
|
||||
* Adds the support of an extra $context parameter for the supportsDecoding method.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
interface ContextAwareDecoderInterface extends DecoderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param array $context options that decoders have access to
|
||||
*/
|
||||
public function supportsDecoding($format, array $context = array());
|
||||
}
|
@ -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\Encoder;
|
||||
|
||||
/**
|
||||
* Adds the support of an extra $context parameter for the supportsEncoding method.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
interface ContextAwareEncoderInterface extends EncoderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param array $context options that encoders have access to
|
||||
*/
|
||||
public function supportsEncoding($format, array $context = array());
|
||||
}
|
@ -21,6 +21,8 @@ use Symfony\Component\Serializer\SerializerInterface;
|
||||
* Denormalizes arrays of objects.
|
||||
*
|
||||
* @author Alexander M. Turek <me@derrabus.de>
|
||||
*
|
||||
* @final since version 3.3.
|
||||
*/
|
||||
class ArrayDenormalizer implements DenormalizerInterface, SerializerAwareInterface
|
||||
{
|
||||
@ -64,10 +66,12 @@ class ArrayDenormalizer implements DenormalizerInterface, SerializerAwareInterfa
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsDenormalization($data, $type, $format = null)
|
||||
public function supportsDenormalization($data, $type, $format = null/*, array $context = array()*/)
|
||||
{
|
||||
$context = func_num_args() > 3 ? func_get_arg(3) : array();
|
||||
|
||||
return substr($type, -2) === '[]'
|
||||
&& $this->serializer->supportsDenormalization($data, substr($type, 0, -2), $format);
|
||||
&& $this->serializer->supportsDenormalization($data, substr($type, 0, -2), $format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
* Adds the support of an extra $context parameter for the supportsDenormalization method.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
interface ContextAwareDenormalizerInterface extends DenormalizerInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param array $context options that denormalizers have access to
|
||||
*/
|
||||
public function supportsDenormalization($data, $type, $format = null, array $context = array());
|
||||
}
|
@ -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;
|
||||
|
||||
/**
|
||||
* Adds the support of an extra $context parameter for the supportsNormalization method.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
interface ContextAwareNormalizerInterface extends NormalizerInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param array $context options that normalizers have access to
|
||||
*/
|
||||
public function supportsNormalization($data, $format = null, array $context = array());
|
||||
}
|
@ -138,7 +138,7 @@ class Serializer implements SerializerInterface, NormalizerInterface, Denormaliz
|
||||
public function normalize($data, $format = null, array $context = array())
|
||||
{
|
||||
// If a normalizer supports the given data, use it
|
||||
if ($normalizer = $this->getNormalizer($data, $format)) {
|
||||
if ($normalizer = $this->getNormalizer($data, $format, $context)) {
|
||||
return $normalizer->normalize($data, $format, $context);
|
||||
}
|
||||
|
||||
@ -177,31 +177,58 @@ class Serializer implements SerializerInterface, NormalizerInterface, Denormaliz
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsNormalization($data, $format = null)
|
||||
public function supportsNormalization($data, $format = null/*, array $context = array()*/)
|
||||
{
|
||||
return null !== $this->getNormalizer($data, $format);
|
||||
if (func_num_args() > 2) {
|
||||
$context = func_get_arg(2);
|
||||
} else {
|
||||
if (__CLASS__ !== get_class($this)) {
|
||||
$r = new \ReflectionMethod($this, __FUNCTION__);
|
||||
if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
|
||||
@trigger_error(sprintf('Method %s() will have a third `$context = array()` argument in version 4.0. Not defining it is deprecated since 3.3.', get_class($this), __FUNCTION__), E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
$context = array();
|
||||
}
|
||||
|
||||
return null !== $this->getNormalizer($data, $format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsDenormalization($data, $type, $format = null)
|
||||
public function supportsDenormalization($data, $type, $format = null/*, array $context = array()*/)
|
||||
{
|
||||
return null !== $this->getDenormalizer($data, $type, $format);
|
||||
if (func_num_args() > 3) {
|
||||
$context = func_get_arg(3);
|
||||
} else {
|
||||
if (__CLASS__ !== get_class($this)) {
|
||||
$r = new \ReflectionMethod($this, __FUNCTION__);
|
||||
if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
|
||||
@trigger_error(sprintf('Method %s() will have a fourth `$context = array()` argument in version 4.0. Not defining it is deprecated since 3.3.', get_class($this), __FUNCTION__), E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
$context = array();
|
||||
}
|
||||
|
||||
return null !== $this->getDenormalizer($data, $type, $format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a matching normalizer.
|
||||
*
|
||||
* @param mixed $data Data to get the serializer for
|
||||
* @param string $format format name, present to give the option to normalizers to act differently based on formats
|
||||
* @param mixed $data data to get the serializer for
|
||||
* @param string $format format name, present to give the option to normalizers to act differently based on formats
|
||||
* @param array $context options available to the normalizer
|
||||
*
|
||||
* @return NormalizerInterface|null
|
||||
*/
|
||||
private function getNormalizer($data, $format)
|
||||
private function getNormalizer($data, $format, array $context)
|
||||
{
|
||||
foreach ($this->normalizers as $normalizer) {
|
||||
if ($normalizer instanceof NormalizerInterface && $normalizer->supportsNormalization($data, $format)) {
|
||||
if ($normalizer instanceof NormalizerInterface && $normalizer->supportsNormalization($data, $format, $context)) {
|
||||
return $normalizer;
|
||||
}
|
||||
}
|
||||
@ -210,16 +237,17 @@ class Serializer implements SerializerInterface, NormalizerInterface, Denormaliz
|
||||
/**
|
||||
* Returns a matching denormalizer.
|
||||
*
|
||||
* @param mixed $data data to restore
|
||||
* @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
|
||||
* @param mixed $data data to restore
|
||||
* @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
|
||||
* @param array $context options available to the denormalizer
|
||||
*
|
||||
* @return DenormalizerInterface|null
|
||||
*/
|
||||
private function getDenormalizer($data, $class, $format)
|
||||
private function getDenormalizer($data, $class, $format, array $context)
|
||||
{
|
||||
foreach ($this->normalizers as $normalizer) {
|
||||
if ($normalizer instanceof DenormalizerInterface && $normalizer->supportsDenormalization($data, $class, $format)) {
|
||||
if ($normalizer instanceof DenormalizerInterface && $normalizer->supportsDenormalization($data, $class, $format, $context)) {
|
||||
return $normalizer;
|
||||
}
|
||||
}
|
||||
@ -260,7 +288,7 @@ class Serializer implements SerializerInterface, NormalizerInterface, Denormaliz
|
||||
throw new LogicException('You must register at least one normalizer to be able to denormalize objects.');
|
||||
}
|
||||
|
||||
if ($normalizer = $this->getDenormalizer($data, $class, $format)) {
|
||||
if ($normalizer = $this->getDenormalizer($data, $class, $format, $context)) {
|
||||
return $normalizer->denormalize($data, $class, $format, $context);
|
||||
}
|
||||
|
||||
@ -270,16 +298,42 @@ class Serializer implements SerializerInterface, NormalizerInterface, Denormaliz
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsEncoding($format)
|
||||
public function supportsEncoding($format/*, array $context = array()*/)
|
||||
{
|
||||
return $this->encoder->supportsEncoding($format);
|
||||
if (func_num_args() > 1) {
|
||||
$context = func_get_arg(1);
|
||||
} else {
|
||||
if (__CLASS__ !== get_class($this)) {
|
||||
$r = new \ReflectionMethod($this, __FUNCTION__);
|
||||
if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
|
||||
@trigger_error(sprintf('Method %s() will have a second `$context = array()` argument in version 4.0. Not defining it is deprecated since 3.3.', get_class($this), __FUNCTION__), E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
$context = array();
|
||||
}
|
||||
|
||||
return $this->encoder->supportsEncoding($format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsDecoding($format)
|
||||
public function supportsDecoding($format/*, array $context = array()*/)
|
||||
{
|
||||
return $this->decoder->supportsDecoding($format);
|
||||
if (func_num_args() > 1) {
|
||||
$context = func_get_arg(1);
|
||||
} else {
|
||||
if (__CLASS__ !== get_class($this)) {
|
||||
$r = new \ReflectionMethod($this, __FUNCTION__);
|
||||
if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
|
||||
@trigger_error(sprintf('Method %s() will have a second `$context = array()` argument in version 4.0. Not defining it is deprecated since 3.3.', get_class($this), __FUNCTION__), E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
$context = array();
|
||||
}
|
||||
|
||||
return $this->decoder->supportsDecoding($format, $context);
|
||||
}
|
||||
}
|
||||
|
@ -32,9 +32,10 @@ class ChainDecoderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->decoder1
|
||||
->method('supportsDecoding')
|
||||
->will($this->returnValueMap(array(
|
||||
array(self::FORMAT_1, true),
|
||||
array(self::FORMAT_2, false),
|
||||
array(self::FORMAT_3, false),
|
||||
array(self::FORMAT_1, array(), true),
|
||||
array(self::FORMAT_2, array(), false),
|
||||
array(self::FORMAT_3, array(), false),
|
||||
array(self::FORMAT_3, array('foo' => 'bar'), true),
|
||||
)));
|
||||
|
||||
$this->decoder2 = $this
|
||||
@ -44,9 +45,9 @@ class ChainDecoderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->decoder2
|
||||
->method('supportsDecoding')
|
||||
->will($this->returnValueMap(array(
|
||||
array(self::FORMAT_1, false),
|
||||
array(self::FORMAT_2, true),
|
||||
array(self::FORMAT_3, false),
|
||||
array(self::FORMAT_1, array(), false),
|
||||
array(self::FORMAT_2, array(), true),
|
||||
array(self::FORMAT_3, array(), false),
|
||||
)));
|
||||
|
||||
$this->chainDecoder = new ChainDecoder(array($this->decoder1, $this->decoder2));
|
||||
@ -57,6 +58,7 @@ class ChainDecoderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertTrue($this->chainDecoder->supportsDecoding(self::FORMAT_1));
|
||||
$this->assertTrue($this->chainDecoder->supportsDecoding(self::FORMAT_2));
|
||||
$this->assertFalse($this->chainDecoder->supportsDecoding(self::FORMAT_3));
|
||||
$this->assertTrue($this->chainDecoder->supportsDecoding(self::FORMAT_3, array('foo' => 'bar')));
|
||||
}
|
||||
|
||||
public function testDecode()
|
||||
|
@ -33,9 +33,10 @@ class ChainEncoderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->encoder1
|
||||
->method('supportsEncoding')
|
||||
->will($this->returnValueMap(array(
|
||||
array(self::FORMAT_1, true),
|
||||
array(self::FORMAT_2, false),
|
||||
array(self::FORMAT_3, false),
|
||||
array(self::FORMAT_1, array(), true),
|
||||
array(self::FORMAT_2, array(), false),
|
||||
array(self::FORMAT_3, array(), false),
|
||||
array(self::FORMAT_3, array('foo' => 'bar'), true),
|
||||
)));
|
||||
|
||||
$this->encoder2 = $this
|
||||
@ -45,9 +46,9 @@ class ChainEncoderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->encoder2
|
||||
->method('supportsEncoding')
|
||||
->will($this->returnValueMap(array(
|
||||
array(self::FORMAT_1, false),
|
||||
array(self::FORMAT_2, true),
|
||||
array(self::FORMAT_3, false),
|
||||
array(self::FORMAT_1, array(), false),
|
||||
array(self::FORMAT_2, array(), true),
|
||||
array(self::FORMAT_3, array(), false),
|
||||
)));
|
||||
|
||||
$this->chainEncoder = new ChainEncoder(array($this->encoder1, $this->encoder2));
|
||||
@ -58,6 +59,7 @@ class ChainEncoderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertTrue($this->chainEncoder->supportsEncoding(self::FORMAT_1));
|
||||
$this->assertTrue($this->chainEncoder->supportsEncoding(self::FORMAT_2));
|
||||
$this->assertFalse($this->chainEncoder->supportsEncoding(self::FORMAT_3));
|
||||
$this->assertTrue($this->chainEncoder->supportsEncoding(self::FORMAT_3, array('foo' => 'bar')));
|
||||
}
|
||||
|
||||
public function testEncode()
|
||||
|
Reference in New Issue
Block a user