diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index bacb623..87ce302 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -60,6 +60,7 @@ Yii Framework 2 Change Log - Enh #12145: Added `beforeCacheResponse` and `afterRestoreResponse` to `yii\filters\PageCache` to be more easily extendable (sergeymakinen) - Enh #12390: Avoid creating queries with false where condition (`0=1`) when fetching relational data (klimov-paul) - Enh #12399: Added `ActiveField::addAriaAttributes` property for `aria-required` and `aria-invalid` attributes rendering (Oxyaction, samdark) +- Enh #12419: Added ability to remove root tag and object tags for `yii\web\XmlResponseFormatter` (mhthnz, samdark) - Enh #12619: Added catch `Throwable` in `yii\base\ErrorHandler::handleException()`, transactions and simlar places where consistency must be kept after exception (rob006, cebe) - Enh #12659: Suggest alternatives when console command was not found (mdmunir, cebe) - Enh #12726: `yii\base\Application::$version` converted to `yii\base\Module::$version` virtual property, allowing to specify version as a PHP callback (klimov-paul) diff --git a/framework/web/XmlResponseFormatter.php b/framework/web/XmlResponseFormatter.php index ec08656..e6ceca1 100644 --- a/framework/web/XmlResponseFormatter.php +++ b/framework/web/XmlResponseFormatter.php @@ -37,7 +37,7 @@ class XmlResponseFormatter extends Component implements ResponseFormatterInterfa */ public $encoding; /** - * @var string the name of the root element. + * @var string the name of the root element. If set to false, null or is empty then no root tag should be added. */ public $rootTag = 'response'; /** @@ -50,7 +50,11 @@ class XmlResponseFormatter extends Component implements ResponseFormatterInterfa * @since 2.0.7 */ public $useTraversableAsArray = true; - + /** + * @var bool if object tags should be added + * @since 2.0.11 + */ + public $objectTags = true; /** * Formats the specified response. @@ -65,9 +69,13 @@ class XmlResponseFormatter extends Component implements ResponseFormatterInterfa $response->getHeaders()->set('Content-Type', $this->contentType); if ($response->data !== null) { $dom = new DOMDocument($this->version, $charset); - $root = new DOMElement($this->rootTag); - $dom->appendChild($root); - $this->buildXml($root, $response->data); + if (!empty($this->rootTag)) { + $root = new DOMElement($this->rootTag); + $dom->appendChild($root); + $this->buildXml($root, $response->data); + } else { + $this->buildXml($dom, $response->data); + } $response->content = $dom->saveXML(); } } @@ -95,8 +103,12 @@ class XmlResponseFormatter extends Component implements ResponseFormatterInterfa } } } elseif (is_object($data)) { - $child = new DOMElement(StringHelper::basename(get_class($data))); - $element->appendChild($child); + if ($this->objectTags) { + $child = new DOMElement(StringHelper::basename(get_class($data))); + $element->appendChild($child); + } else { + $child = $element; + } if ($data instanceof Arrayable) { $this->buildXml($child, $data->toArray()); } else { diff --git a/tests/framework/web/XmlResponseFormatterTest.php b/tests/framework/web/XmlResponseFormatterTest.php index f4f3060..bf544a3 100644 --- a/tests/framework/web/XmlResponseFormatterTest.php +++ b/tests/framework/web/XmlResponseFormatterTest.php @@ -19,11 +19,12 @@ use yiiunit\framework\web\stubs\ModelStub; class XmlResponseFormatterTest extends FormatterTest { /** + * @param array $options * @return XmlResponseFormatter */ - protected function getFormatterInstance() + protected function getFormatterInstance($options = []) { - return new XmlResponseFormatter(); + return new XmlResponseFormatter($options); } private $xmlHead = "\n"; @@ -116,4 +117,38 @@ class XmlResponseFormatterTest extends FormatterTest ] ]); } + + public function testCustomRootTag() + { + $rootTag = 'custom'; + $formatter = $this->getFormatterInstance([ + 'rootTag' => $rootTag, + ]); + + $this->response->data = 1; + $formatter->format($this->response); + $this->assertEquals($this->xmlHead . "<$rootTag>1\n", $this->response->content); + } + + public function testRootTagRemoval() + { + $formatter = $this->getFormatterInstance([ + 'rootTag' => null, + ]); + + $this->response->data = 1; + $formatter->format($this->response); + $this->assertEquals($this->xmlHead . "1\n", $this->response->content); + } + + public function testNoObjectTags() + { + $formatter = $this->getFormatterInstance([ + 'objectTags' => false, + ]); + + $this->response->data = new Post(123, 'abc'); + $formatter->format($this->response); + $this->assertEquals($this->xmlHead . "123abc\n", $this->response->content); + } }