Added XmlResponseFormatter.

This commit is contained in:
Qiang Xue
2013-06-15 15:19:00 -04:00
parent fa198518e1
commit 5a8e4b648b
5 changed files with 288 additions and 7 deletions

View File

@@ -132,7 +132,7 @@ class Controller extends Component
* the route will start from the application; otherwise, it will start from the parent module of this controller.
* @param string $route the route to be handled, e.g., 'view', 'comment/view', '/admin/comment/view'.
* @param array $params the parameters to be passed to the action.
* @return integer the status code returned by the action execution. 0 means normal, and other values mean abnormal.
* @return mixed the result of the action
* @see runAction
* @see forward
*/

View File

@@ -33,6 +33,12 @@ class Response extends \yii\base\Response
* @var string the response format.
*/
public $format = self::FORMAT_HTML;
/**
* @var array the formatters for converting data into the response content of the specified [[format]].
* The array keys are the format names, and the array values are the corresponding configurations
* for creating the formatter objects.
*/
public $formatters;
/**
* @var string the charset of the text response. If not set, it will use
* the value of [[Application::charset]].
@@ -134,7 +140,9 @@ class Response extends \yii\base\Response
*/
private $_headers;
/**
* Initializes this component.
*/
public function init()
{
if ($this->version === null) {
@@ -157,6 +165,13 @@ class Response extends \yii\base\Response
return $this->_statusCode;
}
/**
* Sets the response status code.
* This method will set the corresponding status text if `$text` is null.
* @param integer $value the status code
* @param string $text the status text. If not set, it will be set automatically based on the status code.
* @throws InvalidParamException if the status code is invalid.
*/
public function setStatusCode($value, $text = null)
{
$this->_statusCode = (int)$value;
@@ -194,9 +209,13 @@ class Response extends \yii\base\Response
$this->clear();
}
/**
* Clears the headers, cookies, content, status code of the response.
*/
public function clear()
{
$this->_headers = null;
$this->_cookies = null;
$this->_statusCode = null;
$this->_content = null;
$this->statusText = null;
@@ -643,8 +662,9 @@ class Response extends \yii\base\Response
* The existing content will be overwritten.
* Depending on the value of [[format]], the data will be properly formatted.
* @param mixed $data the data that needs to be converted into the response content.
* @param string $format the format of the response. The following formats are
* supported by the default implementation:
* @param string $format the format of the response. The [[formatters]] property specifies
* the supported formats and the corresponding formatters. Additionally, the following formats are
* supported if they are not found in [[formatters]]:
*
* - [[FORMAT_RAW]]: the data will be treated as the response content without any conversion.
* No extra HTTP header will be added.
@@ -656,8 +676,8 @@ class Response extends \yii\base\Response
* header will be set as "text/javascript". Note that in this case `$data` must be an array
* with "data" and "callback" elements. The former refers to the actual data to be sent,
* while the latter refers to the name of the JavaScript callback.
* - [[FORMAT_XML]]: the data will be converted into XML format, and the "Content-Type"
* header will be set as "application/xml" if no previous "Content-Type" header is set.
* - [[FORMAT_XML]]: the data will be converted into XML format. Please refer to [[XmlResponseFormatter]]
* for more details.
*/
public function setContent($data, $format = null)
{
@@ -667,8 +687,28 @@ class Response extends \yii\base\Response
$this->_content = $this->formatContent($data, $format);
}
/**
* Formats the given data as the specified format.
* @param mixed $data the data to be formatted.
* @param string $format the format to use.
* @return string the formatting result.
* @throws InvalidParamException if `$format` is not supported
* @throws InvalidConfigException if the formatter for the specified format is invalid
*/
protected function formatContent($data, $format)
{
if (isset($this->formatters[$format])) {
$formatter = $this->formatters[$format];
if (!is_object($formatter)) {
$formatter = Yii::createObject($formatter);
}
if ($formatter instanceof ResponseFormatter) {
return $formatter->format($this, $data);
} else {
throw new InvalidConfigException("The '$format' response formatter is invalid. It must implement the ResponseFormatter interface.");
}
}
switch ($this->format) {
case self::FORMAT_RAW:
return $data;
@@ -686,7 +726,7 @@ class Response extends \yii\base\Response
throw new InvalidParamException("The 'jsonp' response requires that the data be an array consisting of both 'data' and 'callback' elements.");
}
case self::FORMAT_XML:
// todo
return Yii::createObject('yii\web\XmlResponseFormatter')->format($this, $data);
default:
throw new InvalidConfigException("Unsupported response format: $format");
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* ResponseFormatter specifies the interface needed to format data for a Web response object.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
interface ResponseFormatter
{
/**
* Formats the given data for the response.
* @param Response $response the response object that will accept the formatted result
* @param mixed $data the data to be formatted
* @return string the formatted result
*/
function format($response, $data);
}

View File

@@ -0,0 +1,99 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use DOMDocument;
use DOMElement;
use DOMText;
use yii\base\Arrayable;
use yii\base\Component;
use yii\helpers\StringHelper;
/**
* XmlResponseFormatter formats the given data into an XML response content.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class XmlResponseFormatter extends Component implements ResponseFormatter
{
/**
* @var string the Content-Type header for the response
*/
public $contentType = 'application/xml';
/**
* @var string the XML version
*/
public $version = '1.0';
/**
* @var string the XML encoding. If not set, it will use the value of [[Response::charset]].
*/
public $encoding;
/**
* @var string the name of the root element.
*/
public $rootTag = 'response';
/**
* @var string the name of the elements that represent the array elements with numeric keys.
*/
public $itemTag = 'item';
/**
* Formats the given data for the response.
* @param Response $response the response object that will accept the formatted result
* @param mixed $data the data to be formatted
* @return string the formatted result
*/
public function format($response, $data)
{
$response->getHeaders()->set('Content-Type', $this->contentType);
$dom = new DOMDocument($this->version, $this->encoding === null ? $response->charset : $this->encoding);
$root = new DOMElement($this->rootTag);
$dom->appendChild($root);
$this->buildXml($root, $data);
return $dom->saveXML();
}
/**
* @param DOMElement $element
* @param mixed $data
*/
protected function buildXml($element, $data)
{
if (is_object($data)) {
$child = new DOMElement(StringHelper::basename(get_class($data)));
$element->appendChild($child);
if ($data instanceof Arrayable) {
$this->buildXml($child, $data->toArray());
} else {
$array = array();
foreach ($data as $name => $value) {
$array[$name] = $value;
}
$this->buildXml($child, $array);
}
} elseif (is_array($data)) {
foreach ($data as $name => $value) {
if (is_int($name) && is_object($value)) {
$this->buildXml($element, $value);
} elseif (is_array($value) || is_object($value)) {
$child = new DOMElement(is_int($name) ? $this->itemTag : $name);
$element->appendChild($child);
$this->buildXml($child, $value);
} else {
$child = new DOMElement(is_int($name) ? $this->itemTag : $name);
$element->appendChild($child);
$child->appendChild(new DOMText((string)$value));
}
}
} else {
$element->appendChild(new DOMText((string)$data));
}
}
}