Skip to content

Commit dff269a

Browse files
authored
Refactoring object formatting in XmlDataResponseFormatter (#50)
1 parent 09e13af commit dff269a

File tree

3 files changed

+144
-137
lines changed

3 files changed

+144
-137
lines changed

src/Formatter/XmlDataInterface.php

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\DataResponse\Formatter;
6+
7+
/**
8+
* XmlFormatDataInterface provides methods for formatting objects {@see XmlDataResponseFormatter} as XML data.
9+
*/
10+
interface XmlDataInterface
11+
{
12+
/**
13+
* Returns a valid XML tag name {@see https://www.w3.org/TR/REC-xml/#NT-NameStartChar}
14+
* to use when formatting an object as XML.
15+
*
16+
* @return string The XML tag name.
17+
*/
18+
public function xmlTagName(): string;
19+
20+
/**
21+
* Returns an array of data to format as XML.
22+
*
23+
* The data can be any scalar values, instances of `XmlDataInterface`,
24+
* and arrays of any nesting consisting of the above values.
25+
*
26+
* @return array The data to format as XML.
27+
*/
28+
public function xmlData(): array;
29+
}

src/Formatter/XmlDataResponseFormatter.php

+12-39
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@
99
use DOMException;
1010
use DOMText;
1111
use Psr\Http\Message\ResponseInterface;
12-
use Traversable;
12+
use RuntimeException;
1313
use Yiisoft\DataResponse\ResponseContentTrait;
1414
use Yiisoft\Strings\NumericHelper;
15-
use Yiisoft\Strings\StringHelper;
1615
use Yiisoft\DataResponse\DataResponse;
1716
use Yiisoft\DataResponse\DataResponseFormatterInterface;
1817

@@ -21,8 +20,7 @@
2120
use function is_float;
2221
use function is_int;
2322
use function is_object;
24-
use function iterator_to_array;
25-
use function strpos;
23+
use function sprintf;
2624

2725
final class XmlDataResponseFormatter implements DataResponseFormatterInterface
2826
{
@@ -51,12 +49,6 @@ final class XmlDataResponseFormatter implements DataResponseFormatterInterface
5149
*/
5250
private string $rootTag = 'response';
5351

54-
/**
55-
* @var bool If true, the object tags will be formed from the class names,
56-
* otherwise the {@see DEFAULT_ITEM_TAG_NAME} value will be used.
57-
*/
58-
private bool $useObjectTags = true;
59-
6052
public function format(DataResponse $dataResponse): ResponseInterface
6153
{
6254
if ($dataResponse->hasData()) {
@@ -106,21 +98,6 @@ public function withRootTag(string $rootTag): self
10698
return $new;
10799
}
108100

109-
/**
110-
* Returns a new instance with the specified value, whether to use class names as tags or not.
111-
*
112-
* @param bool $useObjectTags If true, the object tags will be formed from the class names,
113-
* otherwise the {@see DEFAULT_ITEM_TAG_NAME} value will be used. Default is true.
114-
*
115-
* @return self
116-
*/
117-
public function withUseObjectTags(bool $useObjectTags): self
118-
{
119-
$new = clone $this;
120-
$new->useObjectTags = $useObjectTags;
121-
return $new;
122-
}
123-
124101
/**
125102
* Builds the data to use in XML.
126103
*
@@ -134,12 +111,11 @@ private function buildXml(DOMDocument $dom, $element, $data): void
134111
return;
135112
}
136113

137-
if (is_array($data) || $data instanceof Traversable) {
138-
$data = $data instanceof Traversable ? iterator_to_array($data) : $data;
114+
if (is_array($data)) {
139115
$dataSize = count($data);
140116

141117
foreach ($data as $name => $value) {
142-
if (is_int($name) && is_object($value) && !($value instanceof Traversable)) {
118+
if (is_int($name) && is_object($value)) {
143119
$this->buildObject($dom, $element, $value, $dataSize > 1 ? $name : null);
144120
continue;
145121
}
@@ -181,25 +157,22 @@ private function buildXml(DOMDocument $dom, $element, $data): void
181157
*/
182158
private function buildObject(DOMDocument $dom, $element, object $object, int $key = null): void
183159
{
184-
if ($this->useObjectTags) {
185-
$class = get_class($object);
186-
$class = strpos($class, 'class@anonymous') === false ? StringHelper::baseName($class) : 'AnonymousClass';
160+
if (!($object instanceof XmlDataInterface)) {
161+
throw new RuntimeException(sprintf(
162+
'The "%s" object must implement the "%s" interface.',
163+
get_class($object),
164+
XmlDataInterface::class,
165+
));
187166
}
188167

189-
$child = $this->safeCreateDomElement($dom, $class ?? self::DEFAULT_ITEM_TAG_NAME);
168+
$child = $this->safeCreateDomElement($dom, $object->xmlTagName());
190169

191170
if ($key !== null) {
192171
$child->setAttribute(self::KEY_ATTRIBUTE_NAME, (string) $key);
193172
}
194173

195174
$element->appendChild($child);
196-
$array = [];
197-
198-
foreach ($object as $property => $value) {
199-
$array[$property] = $value;
200-
}
201-
202-
$this->buildXml($dom, $child, $array);
175+
$this->buildXml($dom, $child, $object->xmlData());
203176
}
204177

205178
/**

0 commit comments

Comments
 (0)