Skip to content

Commit b94e415

Browse files
committed
merged branch beberlei/SerializerOptions (PR #6797)
This PR was merged into the master branch. Commits ------- fcabadf Fix JsonDecode to work on PHP 5.3, update the CHANGELOG.md b6bdb45 Completly refactor the Serializer Options Pull Request to push context information directly and avoid state and dependencies between SerializerInterface and encoders/normalizers. ef652e2 Added context to JsonEncoder eacb7e2 Rename $options to $context, as it makes the intent much more clear. 8854b85 Fix CS issues, removed global options 9c54a4b [Serializer] Allow options to be passed to SerialiizerInterface#serialize and #unserialize. Thsee options are available to all encoders/decoders/normalizers that implement SerializerAwareInterface. Discussion ---------- [2.2] [Serializer] Configurable Serializer Bug fix: no Feature addition: yes Backwards compatibility break: yes Symfony2 tests pass: yes Fixes the following tickets: #4907, #4938 License of the code: MIT Todo: This is an extension of GH-6574 that removes the context state in favor of passing this information around. --------------------------------------------------------------------------- by beberlei at 2013-01-18T13:12:39Z @fabpot @lsmith I think this is how it should work from an OOP/OOD perpesctive, avoiding the context state. This makes for a much cleaner code and dependency graph. --------------------------------------------------------------------------- by lsmith77 at 2013-01-18T14:14:37Z makes sense. anything fancier would lose this components simplicity which IMHO is the main benefit versus JMS serializer. --------------------------------------------------------------------------- by fabpot at 2013-01-18T14:26:25Z Looks very good. :+1: --------------------------------------------------------------------------- by beberlei at 2013-01-18T14:37:32Z I need to fix the failures with the JsonEncoder and then this is good to merge --------------------------------------------------------------------------- by stof at 2013-01-18T14:40:21Z you also need to update the CHANGELOG of the component --------------------------------------------------------------------------- by beberlei at 2013-01-18T23:17:57Z Fixed, only the Redis Profiler problem still failing the Travis builds. Also I updated the CHANGELOG.md. @fabpot Good to merge from my POV --------------------------------------------------------------------------- by stof at 2013-01-18T23:27:59Z @beberlei see #6804 for the Redis profiler issue
2 parents 5562e27 + 5d831f3 commit b94e415

23 files changed

+256
-73
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
CHANGELOG
22
=========
33

4+
2.2.0
5+
-----
6+
7+
* All Serializer, Normalizer and Encoder interfaces have been
8+
modified to include an optional ``$context`` array parameter.
9+
* The XML Root name can now be configured with the ``xml_root_name``
10+
parameter in the context option to the ``XmlEncoder``.
11+
* Options to ``json_encode`` and ``json_decode`` can be passed through
12+
the context options of ``JsonEncode`` and ``JsonDecode`` encoder/decoders.
13+
414
2.1.0
515
-----
616

Encoder/ChainDecoder.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ public function __construct(array $decoders = array())
3434
/**
3535
* {@inheritdoc}
3636
*/
37-
final public function decode($data, $format)
37+
final public function decode($data, $format, array $context = array())
3838
{
39-
return $this->getDecoder($format)->decode($data, $format);
39+
return $this->getDecoder($format)->decode($data, $format, $context);
4040
}
4141

4242
/**

Encoder/ChainEncoder.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ public function __construct(array $encoders = array())
3535
/**
3636
* {@inheritdoc}
3737
*/
38-
final public function encode($data, $format)
38+
final public function encode($data, $format, array $context = array())
3939
{
40-
return $this->getEncoder($format)->encode($data, $format);
40+
return $this->getEncoder($format)->encode($data, $format, $context);
4141
}
4242

4343
/**

Encoder/DecoderInterface.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ interface DecoderInterface
2323
*
2424
* @param scalar $data Data to decode
2525
* @param string $format Format name
26+
* @param array $context options that decoders have access to.
2627
*
2728
* @return mixed
2829
*/
29-
public function decode($data, $format);
30+
public function decode($data, $format, array $context = array());
3031

3132
/**
3233
* Checks whether the serializer can decode from given format

Encoder/EncoderInterface.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ interface EncoderInterface
2323
*
2424
* @param mixed $data Data to encode
2525
* @param string $format Format name
26+
* @param array $context options that normalizers/encoders have access to.
2627
*
2728
* @return scalar
2829
*/
29-
public function encode($data, $format);
30+
public function encode($data, $format, array $context = array());
3031

3132
/**
3233
* Checks whether the serializer can encode to given format

Encoder/JsonDecode.php

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class JsonDecode implements DecoderInterface
2121
private $associative;
2222
private $recursionDepth;
2323
private $lastError = JSON_ERROR_NONE;
24+
protected $serializer;
2425

2526
public function __construct($associative = false, $depth = 512)
2627
{
@@ -48,9 +49,20 @@ public function getLastError()
4849
*
4950
* @return mixed
5051
*/
51-
public function decode($data, $format)
52+
public function decode($data, $format, array $context = array())
5253
{
53-
$decodedData = json_decode($data, $this->associative, $this->recursionDepth);
54+
$context = $this->resolveContext($context);
55+
56+
$associative = $context['json_decode_associative'];
57+
$recursionDepth = $context['json_decode_recursion_depth'];
58+
$options = $context['json_decode_options'];
59+
60+
if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
61+
$decodedData = json_decode($data, $associative, $recursionDepth, $options);
62+
} else {
63+
$decodedData = json_decode($data, $associative, $recursionDepth);
64+
}
65+
5466
$this->lastError = json_last_error();
5567

5668
return $decodedData;
@@ -63,4 +75,21 @@ public function supportsDecoding($format)
6375
{
6476
return JsonEncoder::FORMAT === $format;
6577
}
78+
79+
/**
80+
* Merge the default options of the Json Decoder with the passed context.
81+
*
82+
* @param array $context
83+
* @return array
84+
*/
85+
private function resolveContext(array $context)
86+
{
87+
$defaultOptions = array(
88+
'json_decode_associative' => $this->associative,
89+
'json_decode_recursion_depth' => $this->recursionDepth,
90+
'json_decode_options' => 0
91+
);
92+
93+
return array_merge($defaultOptions, $context);
94+
}
6695
}

Encoder/JsonEncode.php

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,13 @@ public function getLastError()
4141
/**
4242
* Encodes PHP data to a JSON string
4343
*
44-
* @param mixed $data
45-
* @param string $format
46-
*
47-
* @return string
44+
* {@inheritdoc}
4845
*/
49-
public function encode($data, $format)
46+
public function encode($data, $format, array $context = array())
5047
{
51-
$encodedJson = json_encode($data, $this->options);
48+
$context = $this->resolveContext($context);
49+
50+
$encodedJson = json_encode($data, $context['json_encode_options']);
5251
$this->lastError = json_last_error();
5352

5453
return $encodedJson;
@@ -61,4 +60,15 @@ public function supportsEncoding($format)
6160
{
6261
return JsonEncoder::FORMAT === $format;
6362
}
63+
64+
/**
65+
* Merge default json encode options with context.
66+
*
67+
* @param array $context
68+
* @return array
69+
*/
70+
private function resolveContext(array $context = array())
71+
{
72+
return array_merge(array('json_encode_options' => $this->options), $context);
73+
}
6474
}

Encoder/JsonEncoder.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,17 @@ public function getLastDecodingError()
5959
/**
6060
* {@inheritdoc}
6161
*/
62-
public function encode($data, $format)
62+
public function encode($data, $format, array $context = array())
6363
{
64-
return $this->encodingImpl->encode($data, self::FORMAT);
64+
return $this->encodingImpl->encode($data, self::FORMAT, $context);
6565
}
6666

6767
/**
6868
* {@inheritdoc}
6969
*/
70-
public function decode($data, $format)
70+
public function decode($data, $format, array $context = array())
7171
{
72-
return $this->decodingImpl->decode($data, self::FORMAT);
72+
return $this->decodingImpl->decode($data, self::FORMAT, $context);
7373
}
7474

7575
/**

Encoder/XmlEncoder.php

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,36 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec
2626
private $format;
2727
private $rootNodeName = 'response';
2828

29+
/**
30+
* Construct new XmlEncoder and allow to change the root node element name.
31+
*
32+
* @param string $rootNodeName
33+
*/
34+
public function __construct($rootNodeName = 'response')
35+
{
36+
$this->rootNodeName = $rootNodeName;
37+
}
38+
2939
/**
3040
* {@inheritdoc}
3141
*/
32-
public function encode($data, $format)
42+
public function encode($data, $format, array $context = array())
3343
{
3444
if ($data instanceof \DOMDocument) {
3545
return $data->saveXML();
3646
}
3747

48+
$xmlRootNodeName = $this->resolveXmlRootName($context);
49+
3850
$this->dom = new \DOMDocument();
3951
$this->format = $format;
4052

4153
if (null !== $data && !is_scalar($data)) {
42-
$root = $this->dom->createElement($this->rootNodeName);
54+
$root = $this->dom->createElement($xmlRootNodeName);
4355
$this->dom->appendChild($root);
44-
$this->buildXml($root, $data);
56+
$this->buildXml($root, $data, $xmlRootNodeName);
4557
} else {
46-
$this->appendNode($this->dom, $data, $this->rootNodeName);
58+
$this->appendNode($this->dom, $data, $xmlRootNodeName);
4759
}
4860

4961
return $this->dom->saveXML();
@@ -52,7 +64,7 @@ public function encode($data, $format)
5264
/**
5365
* {@inheritdoc}
5466
*/
55-
public function decode($data, $format)
67+
public function decode($data, $format, array $context = array())
5668
{
5769
$internalErrors = libxml_use_internal_errors(true);
5870
$disableEntities = libxml_disable_entity_loader(true);
@@ -269,12 +281,13 @@ private function parseXml($node)
269281
*
270282
* @param DOMNode $parentNode
271283
* @param array|object $data data
284+
* @param string $xmlRootNodeName
272285
*
273286
* @return Boolean
274287
*
275288
* @throws UnexpectedValueException
276289
*/
277-
private function buildXml($parentNode, $data)
290+
private function buildXml($parentNode, $data, $xmlRootNodeName)
278291
{
279292
$append = true;
280293

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

311324
return $append;
312325
}
326+
313327
if (is_object($data)) {
314328
$data = $this->serializer->normalize($data, $this->format);
315329
if (null !== $data && !is_scalar($data)) {
316-
return $this->buildXml($parentNode, $data);
330+
return $this->buildXml($parentNode, $data, $xmlRootNodeName);
317331
}
332+
318333
// top level data object was normalized into a scalar
319334
if (!$parentNode->parentNode->parentNode) {
320335
$root = $parentNode->parentNode;
321336
$root->removeChild($parentNode);
322337

323-
return $this->appendNode($root, $data, $this->rootNodeName);
338+
return $this->appendNode($root, $data, $xmlRootNodeName);
324339
}
325340

326341
return $this->appendNode($parentNode, $data, 'data');
327342
}
343+
328344
throw new UnexpectedValueException('An unexpected value could not be serialized: '.var_export($data, true));
329345
}
330346

@@ -376,7 +392,7 @@ private function needsCdataWrapping($val)
376392
private function selectNodeType($node, $val)
377393
{
378394
if (is_array($val)) {
379-
return $this->buildXml($node, $val);
395+
return $this->buildXml($node, $val, null);
380396
} elseif ($val instanceof \SimpleXMLElement) {
381397
$child = $this->dom->importNode(dom_import_simplexml($val), true);
382398
$node->appendChild($child);
@@ -399,4 +415,15 @@ private function selectNodeType($node, $val)
399415

400416
return true;
401417
}
418+
419+
/**
420+
* Get real XML root node name, taking serializer options into account.
421+
*/
422+
private function resolveXmlRootName(array $context = array())
423+
{
424+
return isset($context['xml_root_node_name'])
425+
? $context['xml_root_node_name']
426+
: $this->rootNodeName;
427+
}
428+
402429
}

Normalizer/CustomNormalizer.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ class CustomNormalizer extends SerializerAwareNormalizer implements NormalizerIn
1919
/**
2020
* {@inheritdoc}
2121
*/
22-
public function normalize($object, $format = null)
22+
public function normalize($object, $format = null, array $context = array())
2323
{
24-
return $object->normalize($this->serializer, $format);
24+
return $object->normalize($this->serializer, $format, $context);
2525
}
2626

2727
/**
2828
* {@inheritdoc}
2929
*/
30-
public function denormalize($data, $class, $format = null)
30+
public function denormalize($data, $class, $format = null, array $context = array())
3131
{
3232
$object = new $class;
33-
$object->denormalize($this->serializer, $data, $format);
33+
$object->denormalize($this->serializer, $data, $format, $context);
3434

3535
return $object;
3636
}

0 commit comments

Comments
 (0)