XmlFormatter.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\httpclient;
  8. use DOMDocument;
  9. use DOMElement;
  10. use DOMText;
  11. use SimpleXMLElement;
  12. use yii\base\Arrayable;
  13. use yii\base\Object;
  14. use Yii;
  15. use yii\helpers\StringHelper;
  16. /**
  17. * XmlFormatter formats HTTP message as XML.
  18. *
  19. * @author Paul Klimov <klimov.paul@gmail.com>
  20. * @since 2.0
  21. */
  22. class XmlFormatter extends Object implements FormatterInterface
  23. {
  24. /**
  25. * @var string the Content-Type header for the response
  26. */
  27. public $contentType = 'application/xml';
  28. /**
  29. * @var string the XML version
  30. */
  31. public $version = '1.0';
  32. /**
  33. * @var string the XML encoding. If not set, it will use the value of [[\yii\base\Application::charset]].
  34. */
  35. public $encoding;
  36. /**
  37. * @var string the name of the root element.
  38. */
  39. public $rootTag = 'request';
  40. /**
  41. * @var string the name of the elements that represent the array elements with numeric keys.
  42. * @since 2.0.1
  43. */
  44. public $itemTag = 'item';
  45. /**
  46. * @var bool whether to interpret objects implementing the [[\Traversable]] interface as arrays.
  47. * Defaults to `true`.
  48. * @since 2.0.1
  49. */
  50. public $useTraversableAsArray = true;
  51. /**
  52. * @inheritdoc
  53. */
  54. public function format(Request $request)
  55. {
  56. $contentType = $this->contentType;
  57. $charset = $this->encoding === null ? Yii::$app->charset : $this->encoding;
  58. if (stripos($contentType, 'charset') === false) {
  59. $contentType .= '; charset=' . $charset;
  60. }
  61. $request->getHeaders()->set('Content-Type', $contentType);
  62. $data = $request->getData();
  63. if ($data !== null) {
  64. if ($data instanceof DOMDocument) {
  65. $content = $data->saveXML();
  66. } elseif ($data instanceof SimpleXMLElement) {
  67. $content = $data->saveXML();
  68. } else {
  69. $dom = new DOMDocument($this->version, $charset);
  70. $root = new DOMElement($this->rootTag);
  71. $dom->appendChild($root);
  72. $this->buildXml($root, $data);
  73. $content = $dom->saveXML();
  74. }
  75. $request->setContent($content);
  76. }
  77. return $request;
  78. }
  79. /**
  80. * @param DOMElement $element
  81. * @param mixed $data
  82. */
  83. protected function buildXml($element, $data)
  84. {
  85. if (is_array($data) ||
  86. ($data instanceof \Traversable && $this->useTraversableAsArray && !$data instanceof Arrayable)
  87. ) {
  88. foreach ($data as $name => $value) {
  89. if (is_int($name) && is_object($value)) {
  90. $this->buildXml($element, $value);
  91. } elseif (is_array($value) || is_object($value)) {
  92. $child = new DOMElement(is_int($name) ? $this->itemTag : $name);
  93. $element->appendChild($child);
  94. $this->buildXml($child, $value);
  95. } else {
  96. $child = new DOMElement(is_int($name) ? $this->itemTag : $name);
  97. $element->appendChild($child);
  98. $child->appendChild(new DOMText((string) $value));
  99. }
  100. }
  101. } elseif (is_object($data)) {
  102. $child = new DOMElement(StringHelper::basename(get_class($data)));
  103. $element->appendChild($child);
  104. if ($data instanceof Arrayable) {
  105. $this->buildXml($child, $data->toArray());
  106. } else {
  107. $array = [];
  108. foreach ($data as $name => $value) {
  109. $array[$name] = $value;
  110. }
  111. $this->buildXml($child, $array);
  112. }
  113. } else {
  114. $element->appendChild(new DOMText((string) $data));
  115. }
  116. }
  117. }