Added Xmlable and implememt Response->xml()

This commit is contained in:
huangzhhui 2019-07-10 22:12:12 +08:00
parent c6f2853758
commit 80c010ee35
4 changed files with 154 additions and 0 deletions

View File

@ -14,6 +14,7 @@ namespace Hyperf\HttpServer\Contract;
use Hyperf\Utils\Contracts\Arrayable;
use Hyperf\Utils\Contracts\Jsonable;
use Hyperf\Utils\Contracts\Xmlable;
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;
interface ResponseInterface
@ -25,6 +26,14 @@ interface ResponseInterface
*/
public function json($data): PsrResponseInterface;
/**
* Format data to XML and return data with Content-Type:application/xml header.
*
* @param array|Arrayable|Xmlable $data
* @param string $root The name of the root node.
*/
public function xml($data, string $root = 'root'): PsrResponseInterface;
/**
* Format data to a string and return data with Content-Type:text/plain header.
* @param mixed $data

View File

@ -22,10 +22,12 @@ use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Context;
use Hyperf\Utils\Contracts\Arrayable;
use Hyperf\Utils\Contracts\Jsonable;
use Hyperf\Utils\Contracts\Xmlable;
use Hyperf\Utils\Str;
use Hyperf\Utils\Traits\Macroable;
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;
use Psr\Http\Message\StreamInterface;
use SimpleXMLElement;
use Swoole\Http\Response as SwooleResponse;
use function get_class;
@ -72,6 +74,19 @@ class Response extends ServerResponse implements ResponseInterface
->withBody(new SwooleStream($data));
}
/**
* Format data to XML and return data with Content-Type:application/xml header.
*
* @param array|Arrayable|Xmlable $data
*/
public function xml($data, string $root = 'root'): PsrResponseInterface
{
$data = $this->toXml($data, $root);
return $this->getResponse()
->withAddedHeader('content-type', 'application/xml; charset=utf-8')
->withBody(new SwooleStream($data));
}
/**
* Format data to a string and return data with content-type:text/plain header.
*
@ -361,6 +376,41 @@ class Response extends ServerResponse implements ResponseInterface
throw new HttpException('Error encoding response data to JSON.');
}
/**
* @param array|Arrayable|Xmlable $data
* @param null|mixed $parentNode
* @param mixed $root
* @throws HttpException when the data encoding error
*/
protected function toXml($data, $parentNode = null, $root = 'root')
{
if ($data instanceof Xmlable) {
return (string) $data;
}
if ($data instanceof Arrayable) {
$data = $data->toArray();
} else {
$data = (array) $data;
}
if ($parentNode === null) {
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?>' . "<{$root}></{$root}>");
} else {
$xml = $parentNode;
}
foreach ($data as $key => $value) {
if (is_array($value)) {
$this->toXml($value, $xml->addChild($key));
} else {
if (is_numeric($key)) {
$xml->addChild('item' . $key, (string) $value);
} else {
$xml->addChild($key, (string) $value);
}
}
}
return trim($xml->asXML());
}
/**
* Get the response object from context.
*

View File

@ -15,6 +15,8 @@ namespace HyperfTest\HttpServer;
use Hyperf\HttpServer\Response;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Context;
use Hyperf\Utils\Contracts\Arrayable;
use Hyperf\Utils\Contracts\Xmlable;
use Mockery;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
@ -52,4 +54,79 @@ class ResponseTest extends TestCase
$this->assertSame(302, $res->getStatusCode());
$this->assertSame('http://www.baidu.com', $res->getHeaderLine('Location'));
}
public function testToXml()
{
$container = Mockery::mock(ContainerInterface::class);
ApplicationContext::setContainer($container);
$psrResponse = new \Hyperf\HttpMessage\Base\Response();
Context::set(PsrResponseInterface::class, $psrResponse);
$response = new Response();
$reflectionClass = new \ReflectionClass(Response::class);
$reflectionMethod = $reflectionClass->getMethod('toXml');
$reflectionMethod->setAccessible(true);
$expected = '<?xml version="1.0" encoding="utf-8"?>
<root><kstring>string</kstring><kint1>1</kint1><kint0>0</kint0><kfloat>0.12345</kfloat><kfalse/><ktrue>1</ktrue><karray><kstring>string</kstring><kint1>1</kint1><kint0>0</kint0><kfloat>0.12345</kfloat><kfalse/><ktrue>1</ktrue></karray></root>';
// Array
$this->assertSame($expected, $reflectionMethod->invoke($response, [
'kstring' => 'string',
'kint1' => 1,
'kint0' => 0,
'kfloat' => 0.12345,
'kfalse' => false,
'ktrue' => true,
'karray' => [
'kstring' => 'string',
'kint1' => 1,
'kint0' => 0,
'kfloat' => 0.12345,
'kfalse' => false,
'ktrue' => true,
],
]));
// Arrayable
$arrayable = new class() implements Arrayable {
public function toArray(): array
{
return [
'kstring' => 'string',
'kint1' => 1,
'kint0' => 0,
'kfloat' => 0.12345,
'kfalse' => false,
'ktrue' => true,
'karray' => [
'kstring' => 'string',
'kint1' => 1,
'kint0' => 0,
'kfloat' => 0.12345,
'kfalse' => false,
'ktrue' => true,
],
];
}
};
$this->assertSame($expected, $reflectionMethod->invoke($response, $arrayable));
// Xmlable
$xmlable = new class($expected) implements Xmlable {
private $result;
public function __construct($result)
{
$this->result = $result;
}
public function __toString(): string
{
return $this->result;
}
};
$this->assertSame($expected, $reflectionMethod->invoke($response, $xmlable));
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact group@hyperf.io
* @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Utils\Contracts;
interface Xmlable
{
public function __toString(): string;
}