• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

voku / httpful / 25187974306

30 Apr 2026 08:34PM UTC coverage: 90.483% (+0.6%) from 89.902%
25187974306

push

github

web-flow
Merge pull request #26 from voku/php8

[+]: PHP 8.0+ rework

368 of 407 new or added lines in 7 files covered. (90.42%)

1 existing line in 1 file now uncovered.

2548 of 2816 relevant lines covered (90.48%)

49.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.81
/src/Httpful/Handlers/XmlMimeHandler.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Httpful\Handlers;
6

7
use Httpful\Exception\XmlParseException;
8

9
/**
10
 * Mime Type: application/xml
11
 */
12
class XmlMimeHandler extends DefaultMimeHandler
13
{
14
    /**
15
     * @var string xml namespace to use with simple_load_string
16
     */
17
    private $namespace;
18

19
    /**
20
     * @var int see http://www.php.net/manual/en/libxml.constants.php
21
     */
22
    private $libxml_opts;
23

24
    /**
25
     * @param array<string, mixed> $conf sets configuration options
26
     */
27
    public function __construct(array $conf = [])
28
    {
29
        parent::__construct($conf);
23✔
30

31
        $this->namespace = $conf['namespace'] ?? '';
23✔
32
        $this->libxml_opts = $conf['libxml_opts'] ?? 0;
23✔
33
    }
34

35
    /**
36
     * @param string $body
37
     *
38
     * @return \SimpleXMLElement|null
39
     */
40
    public function parse($body)
41
    {
42
        $body = $this->stripBom($body);
7✔
43
        if (empty($body)) {
7✔
44
            return null;
2✔
45
        }
46

47
        $parsed = \simplexml_load_string($body, \SimpleXMLElement::class, $this->libxml_opts, $this->namespace);
5✔
48
        if ($parsed === false) {
5✔
49
            throw new XmlParseException('Unable to parse response as XML: ' . $body);
1✔
50
        }
51

52
        return $parsed;
4✔
53
    }
54

55
    /** @noinspection PhpMissingParentCallCommonInspection */
56

57
    /**
58
     * @param mixed $payload
59
     *
60
     * @return false|string
61
     */
62
    public function serialize($payload)
63
    {
64
        /** @noinspection PhpUnusedLocalVariableInspection */
65
        list($_, $dom) = $this->_future_serializeAsXml($payload);
2✔
66

67
        /* @var \DOMDocument $dom */
68

69
        return $dom->saveXML();
2✔
70
    }
71

72
    /**
73
     * @param mixed $payload
74
     *
75
     * @return string
76
     */
77
    public function serialize_clean($payload): string
78
    {
79
        $xml = new \XMLWriter();
2✔
80
        $xml->openMemory();
2✔
81
        $xml->startDocument('1.0', 'UTF-8');
2✔
82
        $this->serialize_node($xml, $payload);
2✔
83

84
        return $xml->outputMemory(true);
2✔
85
    }
86

87
    /**
88
     * @param \XMLWriter $xmlw
89
     * @param mixed      $node to serialize
90
     *
91
     * @return void
92
     */
93
    public function serialize_node(&$xmlw, $node)
94
    {
95
        if (!\is_array($node)) {
6✔
96
            $xmlw->text($node);
6✔
97
        } else {
98
            foreach ($node as $k => $v) {
4✔
99
                $xmlw->startElement($k);
4✔
100
                $this->serialize_node($xmlw, $v);
4✔
101
                $xmlw->endElement();
4✔
102
            }
103
        }
104
    }
105

106
    /**
107
     * @param mixed        $value
108
     * @param \DOMElement  $parent
109
     * @param \DOMDocument $dom
110
     *
111
     * @return array{0:\DOMElement,1:\DOMDocument}
112
     */
113
    private function _future_serializeArrayAsXml(&$value, \DOMElement $parent, \DOMDocument $dom): array
114
    {
115
        foreach ($value as $k => &$v) {
2✔
116
            $n = $k;
2✔
117
            if (\is_numeric($k)) {
2✔
118
                $n = "child-{$n}";
×
119
            }
120

121
            $el = $this->_future_createElement($dom, (string) $n);
2✔
122
            $parent->appendChild($el);
2✔
123
            $this->_future_serializeAsXml($v, $el, $dom);
2✔
124
        }
125

126
        return [$parent, $dom];
2✔
127
    }
128

129
    /**
130
     * @param mixed             $value
131
     * @param \DOMNode|null     $node
132
     * @param \DOMDocument|null $dom
133
     *
134
     * @return array{0:\DOMNode,1:\DOMDocument}
135
     */
136
    private function _future_serializeAsXml(
137
        &$value,
138
        ?\DOMNode $node = null,
139
        ?\DOMDocument $dom = null
140
    ): array {
141
        if (!$dom) {
2✔
142
            $dom = new \DOMDocument();
2✔
143
        }
144

145
        if (!$node) {
2✔
146
            if (!\is_object($value)) {
2✔
147
                $node = $this->_future_createElement($dom, 'response');
2✔
148
                $dom->appendChild($node);
2✔
149
            } else {
150
                $node = $dom; // is it correct, that we use the "dom" as "node"?
×
151
            }
152
        }
153

154
        if (\is_object($value)) {
2✔
NEW
155
            $objNode = $this->_future_createElement($dom, \get_class($value));
×
156
            $node->appendChild($objNode);
×
157
            $this->_future_serializeObjectAsXml($value, $objNode, $dom);
×
158
        } elseif (\is_array($value)) {
2✔
159
            $arrNode = $this->_future_createElement($dom, 'array');
2✔
160
            $node->appendChild($arrNode);
2✔
161
            $this->_future_serializeArrayAsXml($value, $arrNode, $dom);
2✔
162
        } elseif ((bool) $value === $value) {
2✔
163
            $node->appendChild($dom->createTextNode($value ? 'TRUE' : 'FALSE'));
×
164
        } else {
165
            $node->appendChild($dom->createTextNode($value));
2✔
166
        }
167

168
        return [$node, $dom];
2✔
169
    }
170

171
    /**
172
     * @throws \RuntimeException
173
     */
174
    private function _future_createElement(\DOMDocument $dom, string $name): \DOMElement
175
    {
176
        $node = $dom->createElement($name);
2✔
177

178
        if ($node === false) {
2✔
NEW
179
            throw new \RuntimeException('Unable to create DOM element: ' . $name);
×
180
        }
181

182
        return $node;
2✔
183
    }
184

185
    /**
186
     * @param mixed        $value
187
     * @param \DOMElement  $parent
188
     * @param \DOMDocument $dom
189
     *
190
     * @return array{0:\DOMElement,1:\DOMDocument}
191
     */
192
    private function _future_serializeObjectAsXml(&$value, \DOMElement $parent, \DOMDocument $dom): array
193
    {
194
        $refl = new \ReflectionObject($value);
×
195
        foreach ($refl->getProperties() as $pr) {
×
196
            if (!$pr->isPrivate()) {
×
NEW
197
                $el = $this->_future_createElement($dom, $pr->getName());
×
198
                $parent->appendChild($el);
×
199
                $value = $pr->getValue($value);
×
200
                $this->_future_serializeAsXml($value, $el, $dom);
×
201
            }
202
        }
203

204
        return [$parent, $dom];
×
205
    }
206
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc