diff --git a/src/Symfony/Component/Serializer/Encoder/ChainDecoder.php b/src/Symfony/Component/Serializer/Encoder/ChainDecoder.php index 1e59c8ad36ddc..a4cc9f67957ea 100644 --- a/src/Symfony/Component/Serializer/Encoder/ChainDecoder.php +++ b/src/Symfony/Component/Serializer/Encoder/ChainDecoder.php @@ -22,7 +22,7 @@ * * @final since version 3.3. */ -class ChainDecoder implements DecoderInterface +class ChainDecoder implements DecoderInterface /*, ContextAwareDecoderInterface*/ { protected $decoders = array(); protected $decoderByFormat = array(); @@ -37,16 +37,18 @@ public function __construct(array $decoders = array()) */ 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 @@ public function supportsDecoding($format) * 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 @@ private function getDecoder($format) } foreach ($this->decoders as $i => $decoder) { - if ($decoder->supportsDecoding($format)) { + if ($decoder->supportsDecoding($format, $context)) { $this->decoderByFormat[$format] = $i; return $decoder; diff --git a/src/Symfony/Component/Serializer/Encoder/ChainEncoder.php b/src/Symfony/Component/Serializer/Encoder/ChainEncoder.php index ca7e71aa3016a..cfd8855bb8150 100644 --- a/src/Symfony/Component/Serializer/Encoder/ChainEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/ChainEncoder.php @@ -22,7 +22,7 @@ * * @final since version 3.3. */ -class ChainEncoder implements EncoderInterface +class ChainEncoder implements EncoderInterface /*, ContextAwareEncoderInterface*/ { protected $encoders = array(); protected $encoderByFormat = array(); @@ -37,16 +37,18 @@ public function __construct(array $encoders = array()) */ 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 @@ public function supportsEncoding($format) * 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 @@ public function needsNormalization($format) * 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 @@ private function getEncoder($format) } foreach ($this->encoders as $i => $encoder) { - if ($encoder->supportsEncoding($format)) { + if ($encoder->supportsEncoding($format, $context)) { $this->encoderByFormat[$format] = $i; return $encoder; diff --git a/src/Symfony/Component/Serializer/Encoder/ContextAwareDecoderInterface.php b/src/Symfony/Component/Serializer/Encoder/ContextAwareDecoderInterface.php new file mode 100644 index 0000000000000..eefea0ecae120 --- /dev/null +++ b/src/Symfony/Component/Serializer/Encoder/ContextAwareDecoderInterface.php @@ -0,0 +1,27 @@ + + * + * 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 + */ +interface ContextAwareDecoderInterface extends DecoderInterface +{ + /** + * {@inheritdoc} + * + * @param array $context options that decoders have access to + */ + public function supportsDecoding($format, array $context = array()); +} diff --git a/src/Symfony/Component/Serializer/Encoder/ContextAwareEncoderInterface.php b/src/Symfony/Component/Serializer/Encoder/ContextAwareEncoderInterface.php new file mode 100644 index 0000000000000..0268df3d8d1cb --- /dev/null +++ b/src/Symfony/Component/Serializer/Encoder/ContextAwareEncoderInterface.php @@ -0,0 +1,27 @@ + + * + * 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 + */ +interface ContextAwareEncoderInterface extends EncoderInterface +{ + /** + * {@inheritdoc} + * + * @param array $context options that encoders have access to + */ + public function supportsEncoding($format, array $context = array()); +} diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 95f3b630dd7f4..6646c0f92b438 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -267,7 +267,7 @@ private function validateAndDenormalize($currentClass, $attribute, $data, $forma throw new LogicException(sprintf('Cannot denormalize attribute "%s" for class "%s" because injected serializer is not a denormalizer', $attribute, $class)); } - if ($this->serializer->supportsDenormalization($data, $class, $format)) { + if ($this->serializer->supportsDenormalization($data, $class, $format, $context)) { return $this->serializer->denormalize($data, $class, $format, $context); } } diff --git a/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php index 7d3d87c510c55..56d27eb7bf20f 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php @@ -21,6 +21,8 @@ * Denormalizes arrays of objects. * * @author Alexander M. Turek + * + * @final since version 3.3. */ class ArrayDenormalizer implements DenormalizerInterface, SerializerAwareInterface { @@ -64,10 +66,12 @@ public function denormalize($data, $class, $format = null, array $context = arra /** * {@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); } /** diff --git a/src/Symfony/Component/Serializer/Normalizer/ContextAwareDenormalizerInterface.php b/src/Symfony/Component/Serializer/Normalizer/ContextAwareDenormalizerInterface.php new file mode 100644 index 0000000000000..f0bb48c5c649e --- /dev/null +++ b/src/Symfony/Component/Serializer/Normalizer/ContextAwareDenormalizerInterface.php @@ -0,0 +1,27 @@ + + * + * 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 + */ +interface ContextAwareDenormalizerInterface extends DenormalizerInterface +{ + /** + * {@inheritdoc} + * + * @param array $context options that denormalizers have access to + */ + public function supportsDenormalization($data, $type, $format = null, array $context = array()); +} diff --git a/src/Symfony/Component/Serializer/Normalizer/ContextAwareNormalizerInterface.php b/src/Symfony/Component/Serializer/Normalizer/ContextAwareNormalizerInterface.php new file mode 100644 index 0000000000000..b6ab05b713af6 --- /dev/null +++ b/src/Symfony/Component/Serializer/Normalizer/ContextAwareNormalizerInterface.php @@ -0,0 +1,27 @@ + + * + * 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 + */ +interface ContextAwareNormalizerInterface extends NormalizerInterface +{ + /** + * {@inheritdoc} + * + * @param array $context options that normalizers have access to + */ + public function supportsNormalization($data, $format = null, array $context = array()); +} diff --git a/src/Symfony/Component/Serializer/Serializer.php b/src/Symfony/Component/Serializer/Serializer.php index c3e35bb0267cc..5c20bf63e6d13 100644 --- a/src/Symfony/Component/Serializer/Serializer.php +++ b/src/Symfony/Component/Serializer/Serializer.php @@ -138,7 +138,7 @@ final public function deserialize($data, $type, $format, array $context = array( 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 @@ public function denormalize($data, $type, $format = null, array $context = array /** * {@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 @@ private function getNormalizer($data, $format) /** * 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 @@ private function denormalizeObject($data, $class, $format, array $context = arra 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 @@ private function denormalizeObject($data, $class, $format, array $context = arra /** * {@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); } } diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/ChainDecoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/ChainDecoderTest.php index a6d3f40f2366d..c07c3d25839a1 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/ChainDecoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/ChainDecoderTest.php @@ -32,9 +32,10 @@ protected function setUp() $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 @@ protected function setUp() $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 @@ public function testSupportsDecoding() $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() diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/ChainEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/ChainEncoderTest.php index 4fc6b25f9b47f..b37789eb9ab2d 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/ChainEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/ChainEncoderTest.php @@ -33,9 +33,10 @@ protected function setUp() $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 @@ protected function setUp() $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 @@ public function testSupportsEncoding() $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()