Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit693f9ab

Browse files
connorhunicolas-grekas
authored andcommitted
[Serializer] make XmlEncoder stateless thus reentrant
1 parentc59a5fc commit693f9ab

File tree

6 files changed

+186
-45
lines changed

6 files changed

+186
-45
lines changed

‎src/Symfony/Component/Serializer/Encoder/XmlEncoder.php‎

Lines changed: 35 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
useSymfony\Component\Serializer\SerializerAwareTrait;
1818

1919
/**
20-
* Encodes XML data.
21-
*
2220
* @author Jordi Boggiano <j.boggiano@seld.be>
2321
* @author John Wards <jwards@whiteoctober.co.uk>
2422
* @author Fabian Vogler <fabian@equivalence.ch>
@@ -68,13 +66,6 @@ class XmlEncoder implements EncoderInterface, DecoderInterface, NormalizationAwa
6866
self::TYPE_CAST_ATTRIBUTES =>true,
6967
];
7068

71-
/**
72-
* @var \DOMDocument
73-
*/
74-
private$dom;
75-
private$format;
76-
private$context;
77-
7869
/**
7970
* @param array $defaultContext
8071
*/
@@ -107,19 +98,17 @@ public function encode($data, $format, array $context = [])
10798

10899
$xmlRootNodeName =$context[self::ROOT_NODE_NAME] ??$this->defaultContext[self::ROOT_NODE_NAME];
109100

110-
$this->dom =$this->createDomDocument($context);
111-
$this->format =$format;
112-
$this->context =$context;
101+
$dom =$this->createDomDocument($context);
113102

114103
if (null !==$data && !is_scalar($data)) {
115-
$root =$this->dom->createElement($xmlRootNodeName);
116-
$this->dom->appendChild($root);
117-
$this->buildXml($root,$data,$xmlRootNodeName);
104+
$root =$dom->createElement($xmlRootNodeName);
105+
$dom->appendChild($root);
106+
$this->buildXml($root,$data,$format,$context,$xmlRootNodeName);
118107
}else {
119-
$this->appendNode($this->dom,$data,$xmlRootNodeName);
108+
$this->appendNode($dom,$data,$format,$context,$xmlRootNodeName);
120109
}
121110

122-
return$this->dom->saveXML($ignorePiNode ?$this->dom->documentElement :null);
111+
return$dom->saveXML($ignorePiNode ?$dom->documentElement :null);
123112
}
124113

125114
/**
@@ -242,7 +231,7 @@ public function getRootNodeName()
242231
finalprotectedfunctionappendXMLString(\DOMNode$node,string$val):bool
243232
{
244233
if ('' !==$val) {
245-
$frag =$this->dom->createDocumentFragment();
234+
$frag =$node->ownerDocument->createDocumentFragment();
246235
$frag->appendXML($val);
247236
$node->appendChild($frag);
248237

@@ -254,15 +243,15 @@ final protected function appendXMLString(\DOMNode $node, string $val): bool
254243

255244
finalprotectedfunctionappendText(\DOMNode$node,string$val):bool
256245
{
257-
$nodeText =$this->dom->createTextNode($val);
246+
$nodeText =$node->ownerDocument->createTextNode($val);
258247
$node->appendChild($nodeText);
259248

260249
returntrue;
261250
}
262251

263252
finalprotectedfunctionappendCData(\DOMNode$node,string$val):bool
264253
{
265-
$nodeText =$this->dom->createCDATASection($val);
254+
$nodeText =$node->ownerDocument->createCDATASection($val);
266255
$node->appendChild($nodeText);
267256

268257
returntrue;
@@ -284,7 +273,7 @@ final protected function appendDocumentFragment(\DOMNode $node, $fragment): bool
284273

285274
finalprotectedfunctionappendComment(\DOMNode$node,string$data):bool
286275
{
287-
$node->appendChild($this->dom->createComment($data));
276+
$node->appendChild($node->ownerDocument->createComment($data));
288277

289278
returntrue;
290279
}
@@ -412,22 +401,22 @@ private function parseXmlValue(\DOMNode $node, array $context = [])
412401
*
413402
* @throws NotEncodableValueException
414403
*/
415-
privatefunctionbuildXml(\DOMNode$parentNode,$data,string$xmlRootNodeName =null):bool
404+
privatefunctionbuildXml(\DOMNode$parentNode,$data,string$format,array$context,string$xmlRootNodeName =null):bool
416405
{
417406
$append =true;
418-
$removeEmptyTags =$this->context[self::REMOVE_EMPTY_TAGS] ??$this->defaultContext[self::REMOVE_EMPTY_TAGS] ??false;
419-
$encoderIgnoredNodeTypes =$this->context[self::ENCODER_IGNORED_NODE_TYPES] ??$this->defaultContext[self::ENCODER_IGNORED_NODE_TYPES];
407+
$removeEmptyTags =$context[self::REMOVE_EMPTY_TAGS] ??$this->defaultContext[self::REMOVE_EMPTY_TAGS] ??false;
408+
$encoderIgnoredNodeTypes =$context[self::ENCODER_IGNORED_NODE_TYPES] ??$this->defaultContext[self::ENCODER_IGNORED_NODE_TYPES];
420409

421-
if (\is_array($data) || ($datainstanceof \Traversable && (null ===$this->serializer || !$this->serializer->supportsNormalization($data,$this->format)))) {
410+
if (\is_array($data) || ($datainstanceof \Traversable && (null ===$this->serializer || !$this->serializer->supportsNormalization($data,$format)))) {
422411
foreach ($dataas$key =>$data) {
423412
//Ah this is the magic @ attribute types.
424413
if (str_starts_with($key,'@') &&$this->isElementNameValid($attributeName =substr($key,1))) {
425414
if (!is_scalar($data)) {
426-
$data =$this->serializer->normalize($data,$this->format,$this->context);
415+
$data =$this->serializer->normalize($data,$format,$context);
427416
}
428417
$parentNode->setAttribute($attributeName,$data);
429418
}elseif ('#' ===$key) {
430-
$append =$this->selectNodeType($parentNode,$data);
419+
$append =$this->selectNodeType($parentNode,$data,$format,$context);
431420
}elseif ('#comment' ===$key) {
432421
if (!\in_array(\XML_COMMENT_NODE,$encoderIgnoredNodeTypes,true)) {
433422
$append =$this->appendComment($parentNode,$data);
@@ -441,15 +430,15 @@ private function buildXml(\DOMNode $parentNode, $data, string $xmlRootNodeName =
441430
* From ["item" => [0,1]];.
442431
*/
443432
foreach ($dataas$subData) {
444-
$append =$this->appendNode($parentNode,$subData,$key);
433+
$append =$this->appendNode($parentNode,$subData,$format,$context,$key);
445434
}
446435
}else {
447-
$append =$this->appendNode($parentNode,$data,$key);
436+
$append =$this->appendNode($parentNode,$data,$format,$context,$key);
448437
}
449438
}elseif (is_numeric($key) || !$this->isElementNameValid($key)) {
450-
$append =$this->appendNode($parentNode,$data,'item',$key);
439+
$append =$this->appendNode($parentNode,$data,$format,$context,'item',$key);
451440
}elseif (null !==$data || !$removeEmptyTags) {
452-
$append =$this->appendNode($parentNode,$data,$key);
441+
$append =$this->appendNode($parentNode,$data,$format,$context,$key);
453442
}
454443
}
455444

@@ -461,20 +450,20 @@ private function buildXml(\DOMNode $parentNode, $data, string $xmlRootNodeName =
461450
thrownewBadMethodCallException(sprintf('The serializer needs to be set to allow "%s()" to be used with object data.',__METHOD__));
462451
}
463452

464-
$data =$this->serializer->normalize($data,$this->format,$this->context);
453+
$data =$this->serializer->normalize($data,$format,$context);
465454
if (null !==$data && !is_scalar($data)) {
466-
return$this->buildXml($parentNode,$data,$xmlRootNodeName);
455+
return$this->buildXml($parentNode,$data,$format,$context,$xmlRootNodeName);
467456
}
468457

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

474-
return$this->appendNode($root,$data,$xmlRootNodeName);
463+
return$this->appendNode($root,$data,$format,$context,$xmlRootNodeName);
475464
}
476465

477-
return$this->appendNode($parentNode,$data,'data');
466+
return$this->appendNode($parentNode,$data,$format,$context,'data');
478467
}
479468

480469
thrownewNotEncodableValueException('An unexpected value could not be serialized:'.(!\is_resource($data) ?var_export($data,true) :sprintf('%s resource',get_resource_type($data))));
@@ -485,13 +474,14 @@ private function buildXml(\DOMNode $parentNode, $data, string $xmlRootNodeName =
485474
*
486475
* @param array|object $data
487476
*/
488-
privatefunctionappendNode(\DOMNode$parentNode,$data,string$nodeName,string$key =null):bool
477+
privatefunctionappendNode(\DOMNode$parentNode,$data,string$format,array$context,string$nodeName,string$key =null):bool
489478
{
490-
$node =$this->dom->createElement($nodeName);
479+
$dom =$parentNodeinstanceof \DomDocument ?$parentNode :$parentNode->ownerDocument;
480+
$node =$dom->createElement($nodeName);
491481
if (null !==$key) {
492482
$node->setAttribute('key',$key);
493483
}
494-
$appendNode =$this->selectNodeType($node,$data);
484+
$appendNode =$this->selectNodeType($node,$data,$format,$context);
495485
// we may have decided not to append this node, either in error or if its $nodeName is not valid
496486
if ($appendNode) {
497487
$parentNode->appendChild($node);
@@ -505,32 +495,32 @@ private function appendNode(\DOMNode $parentNode, $data, string $nodeName, strin
505495
*/
506496
privatefunctionneedsCdataWrapping(string$val):bool
507497
{
508-
return0 <preg_match('/[<>&]/',$val);
498+
returnpreg_match('/[<>&]/',$val);
509499
}
510500

511501
/**
512502
* Tests the value being passed and decide what sort of element to create.
513503
*
514504
* @throws NotEncodableValueException
515505
*/
516-
privatefunctionselectNodeType(\DOMNode$node,$val):bool
506+
privatefunctionselectNodeType(\DOMNode$node,$val,string$format,array$context):bool
517507
{
518508
if (\is_array($val)) {
519-
return$this->buildXml($node,$val);
509+
return$this->buildXml($node,$val,$format,$context);
520510
}elseif ($valinstanceof \SimpleXMLElement) {
521-
$child =$this->dom->importNode(dom_import_simplexml($val),true);
511+
$child =$node->ownerDocument->importNode(dom_import_simplexml($val),true);
522512
$node->appendChild($child);
523513
}elseif ($valinstanceof \Traversable) {
524-
$this->buildXml($node,$val);
514+
$this->buildXml($node,$val,$format,$context);
525515
}elseif ($valinstanceof \DOMNode) {
526-
$child =$this->dom->importNode($val,true);
516+
$child =$node->ownerDocument->importNode($val,true);
527517
$node->appendChild($child);
528518
}elseif (\is_object($val)) {
529519
if (null ===$this->serializer) {
530520
thrownewBadMethodCallException(sprintf('The serializer needs to be set to allow "%s()" to be used with object data.',__METHOD__));
531521
}
532522

533-
return$this->selectNodeType($node,$this->serializer->normalize($val,$this->format,$this->context));
523+
return$this->selectNodeType($node,$this->serializer->normalize($val,$format,$context),$format,$context);
534524
}elseif (is_numeric($val)) {
535525
return$this->appendText($node, (string)$val);
536526
}elseif (\is_string($val) &&$this->needsCdataWrapping($val)) {

‎src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
useSymfony\Component\Serializer\Normalizer\NormalizerInterface;
2121
useSymfony\Component\Serializer\Serializer;
2222
useSymfony\Component\Serializer\Tests\Fixtures\Dummy;
23+
useSymfony\Component\Serializer\Tests\Fixtures\EnvelopedMessage;
24+
useSymfony\Component\Serializer\Tests\Fixtures\EnvelopedMessageNormalizer;
25+
useSymfony\Component\Serializer\Tests\Fixtures\EnvelopeNormalizer;
26+
useSymfony\Component\Serializer\Tests\Fixtures\EnvelopeObject;
2327
useSymfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy;
2428
useSymfony\Component\Serializer\Tests\Fixtures\ScalarDummy;
2529

@@ -850,6 +854,23 @@ public function testNotEncodableValueExceptionMessageForAResource()
850854
(newXmlEncoder())->encode(tmpfile(),'xml');
851855
}
852856

857+
publicfunctiontestReentrantXmlEncoder()
858+
{
859+
$envelope =newEnvelopeObject();
860+
$message =newEnvelopedMessage();
861+
$message->text ='Symfony is great';
862+
$envelope->message =$message;
863+
864+
$encoder =$this->createXmlEncoderWithEnvelopeNormalizer();
865+
$expected = <<<'XML'
866+
<?xml version="1.0"?>
867+
<response><message>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxyZXNwb25zZT48dGV4dD5TeW1mb255IGlzIGdyZWF0PC90ZXh0PjwvcmVzcG9uc2U+Cg==</message></response>
868+
869+
XML;
870+
871+
$this->assertSame($expected,$encoder->encode($envelope,'xml'));
872+
}
873+
853874
publicfunctiontestEncodeComment()
854875
{
855876
$expected = <<<'XML'
@@ -921,6 +942,21 @@ private function doTestEncodeWithoutComment(bool $legacy = false)
921942
$this->assertEquals($expected,$encoder->encode($data,'xml'));
922943
}
923944

945+
privatefunctioncreateXmlEncoderWithEnvelopeNormalizer():XmlEncoder
946+
{
947+
$normalizers = [
948+
$envelopeNormalizer =newEnvelopeNormalizer(),
949+
newEnvelopedMessageNormalizer(),
950+
];
951+
952+
$encoder =newXmlEncoder();
953+
$serializer =newSerializer($normalizers, ['xml' =>$encoder]);
954+
$encoder->setSerializer($serializer);
955+
$envelopeNormalizer->setSerializer($serializer);
956+
957+
return$encoder;
958+
}
959+
924960
privatefunctioncreateXmlEncoderWithDateTimeNormalizer():XmlEncoder
925961
{
926962
$encoder =newXmlEncoder();
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\Serializer\Tests\Fixtures;
13+
14+
useSymfony\Component\Serializer\Normalizer\NormalizerInterface;
15+
16+
/**
17+
* @author Karoly Gossler <connor@connor.hu>
18+
*/
19+
class EnvelopeNormalizerimplements NormalizerInterface
20+
{
21+
private$serializer;
22+
23+
publicfunctionnormalize($envelope,$format =null,array$context = [])
24+
{
25+
$xmlContent =$this->serializer->serialize($envelope->message,'xml');
26+
27+
$encodedContent =base64_encode($xmlContent);
28+
29+
return [
30+
'message' =>$encodedContent,
31+
];
32+
}
33+
34+
publicfunctionsupportsNormalization($data,$format =null)
35+
{
36+
return$datainstanceof EnvelopeObject;
37+
}
38+
39+
publicfunctionsetSerializer($serializer)
40+
{
41+
$this->serializer =$serializer;
42+
}
43+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\Serializer\Tests\Fixtures;
13+
14+
/**
15+
* @author Karoly Gossler <connor@connor.hu>
16+
*/
17+
class EnvelopeObject
18+
{
19+
public$message;
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\Serializer\Tests\Fixtures;
13+
14+
/**
15+
* @author Karoly Gossler <connor@connor.hu>
16+
*/
17+
class EnvelopedMessage
18+
{
19+
public$text;
20+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\Serializer\Tests\Fixtures;
13+
14+
useSymfony\Component\Serializer\Normalizer\NormalizerInterface;
15+
16+
/**
17+
* @author Karoly Gossler <connor@connor.hu>
18+
*/
19+
class EnvelopedMessageNormalizerimplements NormalizerInterface
20+
{
21+
publicfunctionnormalize($message,$format =null,array$context = [])
22+
{
23+
return [
24+
'text' =>$message->text,
25+
];
26+
}
27+
28+
publicfunctionsupportsNormalization($data,$format =null)
29+
{
30+
return$datainstanceof EnvelopedMessage;
31+
}
32+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp