Navigation Menu

Skip to content

Commit

Permalink
Completly refactor the Serializer Options Pull Request to push contex…
Browse files Browse the repository at this point in the history
…t information directly and avoid state and dependencies between SerializerInterface and encoders/normalizers.
  • Loading branch information
beberlei committed Jan 18, 2013
1 parent ef652e2 commit b6bdb45
Show file tree
Hide file tree
Showing 22 changed files with 119 additions and 160 deletions.
6 changes: 6 additions & 0 deletions UPGRADE-2.2.md
Expand Up @@ -383,3 +383,9 @@
framework:
trusted_proxies: ['127.0.0.1', '10.0.0.1'] # a list of proxy IPs you trust
```

#### Serializer

* All serializer interfaces (Serializer, Normalizer, Encoder) have been extended with an optional ``$context`` array.
This was necessary to allow for more complex use-cases that require context information during the (de)normalization
and en-/decoding steps.
4 changes: 2 additions & 2 deletions src/Symfony/Component/Serializer/Encoder/ChainDecoder.php
Expand Up @@ -34,9 +34,9 @@ public function __construct(array $decoders = array())
/**
* {@inheritdoc}
*/
final public function decode($data, $format)
final public function decode($data, $format, array $context = array())
{
return $this->getDecoder($format)->decode($data, $format);
return $this->getDecoder($format)->decode($data, $format, $context);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Component/Serializer/Encoder/ChainEncoder.php
Expand Up @@ -35,9 +35,9 @@ public function __construct(array $encoders = array())
/**
* {@inheritdoc}
*/
final public function encode($data, $format)
final public function encode($data, $format, array $context = array())
{
return $this->getEncoder($format)->encode($data, $format);
return $this->getEncoder($format)->encode($data, $format, $context);
}

/**
Expand Down
Expand Up @@ -23,10 +23,11 @@ interface DecoderInterface
*
* @param scalar $data Data to decode
* @param string $format Format name
* @param array $context options that decoders have access to.
*
* @return mixed
*/
public function decode($data, $format);
public function decode($data, $format, array $context = array());

/**
* Checks whether the serializer can decode from given format
Expand Down
Expand Up @@ -23,10 +23,11 @@ interface EncoderInterface
*
* @param mixed $data Data to encode
* @param string $format Format name
* @param array $context options that normalizers/encoders have access to.
*
* @return scalar
*/
public function encode($data, $format);
public function encode($data, $format, array $context = array());

/**
* Checks whether the serializer can encode to given format
Expand Down
61 changes: 16 additions & 45 deletions src/Symfony/Component/Serializer/Encoder/JsonDecode.php
Expand Up @@ -11,15 +11,12 @@

namespace Symfony\Component\Serializer\Encoder;

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

/**
* Decodes JSON data
*
* @author Sander Coolen <sander@jibber.nl>
*/
class JsonDecode implements DecoderInterface, SerializerAwareInterface
class JsonDecode implements DecoderInterface
{
private $associative;
private $recursionDepth;
Expand Down Expand Up @@ -52,13 +49,13 @@ public function getLastError()
*
* @return mixed
*/
public function decode($data, $format)
public function decode($data, $format, array $context = array())
{
$context = $this->getContext();
$context = $this->resolveContext($context);

$associative = $context['associative'];
$recursionDepth = $context['recursionDepth'];
$options = $context['options'];
$associative = $context['json_decode_associative'];
$recursionDepth = $context['json_decode_recursion_depth'];
$options = $context['json_decode_options'];

$decodedData = json_decode($data, $associative, $recursionDepth, $options);
$this->lastError = json_last_error();
Expand All @@ -75,45 +72,19 @@ public function supportsDecoding($format)
}

/**
* {@inheritdoc}
* Merge the default options of the Json Decoder with the passed context.
*
* @param array $context
* @return array
*/
public function setSerializer(SerializerInterface $serializer)
private function resolveContext(array $context)
{
$this->serializer = $serializer;
}

private function getContext()
{
$options = array(
'associative' => $this->associative,
'recursionDepth' => $this->recursionDepth,
'options' => 0
$defaultOptions = array(
'json_decode_associative' => $this->associative,
'json_decode_recursion_depth' => $this->recursionDepth,
'json_decode_options' => 0
);

if (!$this->serializer) {
return $options;
}

$options = array(
'associative' => false,
'recursionDepth' => 512,
'options' => 0
);

$context = $this->serializer->getContext();

if (isset($context['associative'])) {
$options['associative'] = $context['associative'];
}

if (isset($context['recursionDepth'])) {
$options['recursionDepth'] = $context['recursionDepth'];
}

if (isset($context['options'])) {
$options['options'] = $context['options'];
}

return $options;
return array_merge($defaultOptions, $context);
}
}
37 changes: 13 additions & 24 deletions src/Symfony/Component/Serializer/Encoder/JsonEncode.php
Expand Up @@ -16,7 +16,7 @@
*
* @author Sander Coolen <sander@jibber.nl>
*/
class JsonEncode extends SerializerAwareEncoder implements EncoderInterface
class JsonEncode implements EncoderInterface
{
private $options ;
private $lastError = JSON_ERROR_NONE;
Expand All @@ -41,16 +41,13 @@ public function getLastError()
/**
* Encodes PHP data to a JSON string
*
* @param mixed $data
* @param string $format
*
* @return string
* {@inheritdoc}
*/
public function encode($data, $format)
public function encode($data, $format, array $context = array())
{
$options = $this->getContext();
$context = $this->resolveContext($context);

$encodedJson = json_encode($data, $options);
$encodedJson = json_encode($data, $context['json_encode_options']);
$this->lastError = json_last_error();

return $encodedJson;
Expand All @@ -64,22 +61,14 @@ public function supportsEncoding($format)
return JsonEncoder::FORMAT === $format;
}

private function getContext()
/**
* Merge default json encode options with context.
*
* @param array $context
* @return array
*/
private function resolveContext(array $context = array())
{
if (!$this->serializer) {
return 0;
}

$context = $this->serializer->getContext();

if (empty($context)) {
$context = array(0);
}

if (!is_array($context)) {
$context = array($context);
}

return array_sum($context);
return array_merge(array('json_encode_options' => $this->options), $context);
}
}
14 changes: 5 additions & 9 deletions src/Symfony/Component/Serializer/Encoder/JsonEncoder.php
Expand Up @@ -16,7 +16,7 @@
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class JsonEncoder extends SerializerAwareEncoder implements EncoderInterface, DecoderInterface
class JsonEncoder implements EncoderInterface, DecoderInterface
{
const FORMAT = 'json';

Expand Down Expand Up @@ -59,21 +59,17 @@ public function getLastDecodingError()
/**
* {@inheritdoc}
*/
public function encode($data, $format)
public function encode($data, $format, array $context = array())
{
$this->encodingImpl->setSerializer($this->serializer);

return $this->encodingImpl->encode($data, self::FORMAT);
return $this->encodingImpl->encode($data, self::FORMAT, $context);
}

/**
* {@inheritdoc}
*/
public function decode($data, $format)
public function decode($data, $format, array $context = array())
{
$this->decodingImpl->setSerializer($this->serializer);

return $this->decodingImpl->decode($data, self::FORMAT);
return $this->decodingImpl->decode($data, self::FORMAT, $context);
}

/**
Expand Down
42 changes: 26 additions & 16 deletions src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
Expand Up @@ -26,24 +26,36 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec
private $format;
private $rootNodeName = 'response';

/**
* Construct new XmlEncoder and allow to change the root node element name.
*
* @param string $rootNodeName
*/
public function __construct($rootNodeName = 'response')
{
$this->rootNodeName = $rootNodeName;
}

/**
* {@inheritdoc}
*/
public function encode($data, $format)
public function encode($data, $format, array $context = array())
{
if ($data instanceof \DOMDocument) {
return $data->saveXML();
}

$xmlRootNodeName = $this->resolveXmlRootName($context);

$this->dom = new \DOMDocument();
$this->format = $format;

if (null !== $data && !is_scalar($data)) {
$root = $this->dom->createElement($this->getRealRootNodeName());
$root = $this->dom->createElement($xmlRootNodeName);
$this->dom->appendChild($root);
$this->buildXml($root, $data);
$this->buildXml($root, $data, $xmlRootNodeName);
} else {
$this->appendNode($this->dom, $data, $this->getRealRootNodeName());
$this->appendNode($this->dom, $data, $xmlRootNodeName);
}

return $this->dom->saveXML();
Expand All @@ -52,7 +64,7 @@ public function encode($data, $format)
/**
* {@inheritdoc}
*/
public function decode($data, $format)
public function decode($data, $format, array $context = array())
{
$internalErrors = libxml_use_internal_errors(true);
$disableEntities = libxml_disable_entity_loader(true);
Expand Down Expand Up @@ -269,12 +281,13 @@ private function parseXml($node)
*
* @param DOMNode $parentNode
* @param array|object $data data
* @param string $xmlRootNodeName
*
* @return Boolean
*
* @throws UnexpectedValueException
*/
private function buildXml($parentNode, $data)
private function buildXml($parentNode, $data, $xmlRootNodeName)
{
$append = true;

Expand Down Expand Up @@ -310,21 +323,24 @@ private function buildXml($parentNode, $data)

return $append;
}

if (is_object($data)) {
$data = $this->serializer->normalize($data, $this->format);
if (null !== $data && !is_scalar($data)) {
return $this->buildXml($parentNode, $data);
return $this->buildXml($parentNode, $data, $xmlRootNodeName);
}

// top level data object was normalized into a scalar
if (!$parentNode->parentNode->parentNode) {
$root = $parentNode->parentNode;
$root->removeChild($parentNode);

return $this->appendNode($root, $data, $this->getRealRootNodeName());
return $this->appendNode($root, $data, $xmlRootNodeName);
}

return $this->appendNode($parentNode, $data, 'data');
}

throw new UnexpectedValueException('An unexpected value could not be serialized: '.var_export($data, true));
}

Expand Down Expand Up @@ -376,7 +392,7 @@ private function needsCdataWrapping($val)
private function selectNodeType($node, $val)
{
if (is_array($val)) {
return $this->buildXml($node, $val);
return $this->buildXml($node, $val, null);
} elseif ($val instanceof \SimpleXMLElement) {
$child = $this->dom->importNode(dom_import_simplexml($val), true);
$node->appendChild($child);
Expand All @@ -403,14 +419,8 @@ private function selectNodeType($node, $val)
/**
* Get real XML root node name, taking serializer options into account.
*/
private function getRealRootNodeName()
private function resolveXmlRootName(array $context = array())
{
if (!$this->serializer) {
return $this->rootNodeName;
}

$context = $this->serializer->getContext();

return isset($context['xml_root_node_name'])
? $context['xml_root_node_name']
: $this->rootNodeName;
Expand Down
Expand Up @@ -19,18 +19,18 @@ class CustomNormalizer extends SerializerAwareNormalizer implements NormalizerIn
/**
* {@inheritdoc}
*/
public function normalize($object, $format = null)
public function normalize($object, $format = null, array $context = array())
{
return $object->normalize($this->serializer, $format);
return $object->normalize($this->serializer, $format, $context);
}

/**
* {@inheritdoc}
*/
public function denormalize($data, $class, $format = null)
public function denormalize($data, $class, $format = null, array $context = array())
{
$object = new $class;
$object->denormalize($this->serializer, $data, $format);
$object->denormalize($this->serializer, $data, $format, $context);

return $object;
}
Expand Down
Expand Up @@ -32,6 +32,7 @@ interface DenormalizableInterface
* @param array|scalar $data The data from which to re-create the object.
* @param string|null $format The format is optionally given to be able to denormalize differently
* based on different input formats.
* @param array $context options for denormalizing
*/
public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null);
public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null, array $context = array());
}

0 comments on commit b6bdb45

Please sign in to comment.