Commit 3e18479d by Qiang Xue

Fixes issue #545: PageCache doesn't work.

parent f18d6df6
...@@ -22,6 +22,10 @@ class ActionEvent extends Event ...@@ -22,6 +22,10 @@ class ActionEvent extends Event
*/ */
public $action; public $action;
/** /**
* @var mixed the action result. Event handlers may modify this property to change the action result.
*/
public $result;
/**
* @var boolean whether to continue running the action. Event handlers of * @var boolean whether to continue running the action. Event handlers of
* [[Controller::EVENT_BEFORE_ACTION]] may set this property to decide whether * [[Controller::EVENT_BEFORE_ACTION]] may set this property to decide whether
* to continue running the current action. * to continue running the current action.
......
...@@ -57,7 +57,7 @@ class ActionFilter extends Behavior ...@@ -57,7 +57,7 @@ class ActionFilter extends Behavior
public function afterFilter($event) public function afterFilter($event)
{ {
if ($this->isActive($event->action)) { if ($this->isActive($event->action)) {
$this->afterAction($event->action); $this->afterAction($event->action, $event->result);
} }
} }
...@@ -76,8 +76,9 @@ class ActionFilter extends Behavior ...@@ -76,8 +76,9 @@ class ActionFilter extends Behavior
* This method is invoked right after an action is executed. * This method is invoked right after an action is executed.
* You may override this method to do some postprocessing for the action. * You may override this method to do some postprocessing for the action.
* @param Action $action the action just executed. * @param Action $action the action just executed.
* @param mixed $result the action execution result
*/ */
public function afterAction($action) public function afterAction($action, &$result)
{ {
} }
......
...@@ -114,9 +114,9 @@ class Controller extends Component ...@@ -114,9 +114,9 @@ class Controller extends Component
if ($this->module->beforeAction($action)) { if ($this->module->beforeAction($action)) {
if ($this->beforeAction($action)) { if ($this->beforeAction($action)) {
$result = $action->runWithParams($params); $result = $action->runWithParams($params);
$this->afterAction($action); $this->afterAction($action, $result);
} }
$this->module->afterAction($action); $this->module->afterAction($action, $result);
} }
$this->action = $oldAction; $this->action = $oldAction;
return $result; return $result;
...@@ -208,10 +208,13 @@ class Controller extends Component ...@@ -208,10 +208,13 @@ class Controller extends Component
* This method is invoked right after an action is executed. * This method is invoked right after an action is executed.
* You may override this method to do some postprocessing for the action. * You may override this method to do some postprocessing for the action.
* @param Action $action the action just executed. * @param Action $action the action just executed.
* @param mixed $result the action return result.
*/ */
public function afterAction($action) public function afterAction($action, &$result)
{ {
$this->trigger(self::EVENT_AFTER_ACTION, new ActionEvent($action)); $event = new ActionEvent($action);
$event->result = &$result;
$this->trigger(self::EVENT_AFTER_ACTION, $event);
} }
/** /**
......
...@@ -97,12 +97,12 @@ class ErrorHandler extends Component ...@@ -97,12 +97,12 @@ class ErrorHandler extends Component
if ($result instanceof Response) { if ($result instanceof Response) {
$response = $result; $response = $result;
} else { } else {
$response->setContent($result); $response->data = $result;
} }
} elseif ($response->format === \yii\web\Response::FORMAT_HTML) { } elseif ($response->format === \yii\web\Response::FORMAT_HTML) {
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') { if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
// AJAX request // AJAX request
$response->setContent(Yii::$app->renderException($exception)); $response->data = Yii::$app->renderException($exception);
} else { } else {
// if there is an error during error rendering it's useful to // if there is an error during error rendering it's useful to
// display PHP error in debug mode instead of a blank screen // display PHP error in debug mode instead of a blank screen
...@@ -110,22 +110,21 @@ class ErrorHandler extends Component ...@@ -110,22 +110,21 @@ class ErrorHandler extends Component
ini_set('display_errors', 1); ini_set('display_errors', 1);
} }
$file = $useErrorView ? $this->errorView : $this->exceptionView; $file = $useErrorView ? $this->errorView : $this->exceptionView;
$response->setContent($this->renderFile($file, array( $response->data = $this->renderFile($file, array(
'exception' => $exception, 'exception' => $exception,
))); ));
} }
} else { } else {
if ($exception instanceof Exception) { if ($exception instanceof Arrayable) {
$content = $exception->toArray(); $response->data = $exception;
} else { } else {
$content = array( $response->data = array(
'type' => get_class($exception), 'type' => get_class($exception),
'name' => 'Exception', 'name' => 'Exception',
'message' => $exception->getMessage(), 'message' => $exception->getMessage(),
'code' => $exception->getCode(), 'code' => $exception->getCode(),
); );
} }
$response->setContent($content);
} }
if ($exception instanceof HttpException) { if ($exception instanceof HttpException) {
......
...@@ -659,9 +659,12 @@ abstract class Module extends Component ...@@ -659,9 +659,12 @@ abstract class Module extends Component
* This method is invoked right after an action is executed. * This method is invoked right after an action is executed.
* You may override this method to do some postprocessing for the action. * You may override this method to do some postprocessing for the action.
* @param Action $action the action just executed. * @param Action $action the action just executed.
* @param mixed $result the action return result.
*/ */
public function afterAction($action) public function afterAction($action, &$result)
{ {
$this->trigger(self::EVENT_AFTER_ACTION, new ActionEvent($action)); $event = new ActionEvent($action);
$event->result = &$result;
$this->trigger(self::EVENT_AFTER_ACTION, $event);
} }
} }
...@@ -14,12 +14,6 @@ namespace yii\base; ...@@ -14,12 +14,6 @@ namespace yii\base;
class Response extends Component class Response extends Component
{ {
/** /**
* @event ResponseEvent an event that is triggered by [[send()]] before it sends the response to client.
* You may respond to this event to modify the response before it is sent out.
*/
const EVENT_SEND = 'send';
/**
* @var integer the exit status. Exit statuses should be in the range 0 to 254. * @var integer the exit status. Exit statuses should be in the range 0 to 254.
* The status 0 means the program terminates successfully. * The status 0 means the program terminates successfully.
*/ */
...@@ -27,11 +21,8 @@ class Response extends Component ...@@ -27,11 +21,8 @@ class Response extends Component
/** /**
* Sends the response to client. * Sends the response to client.
* This method will trigger the [[EVENT_SEND]] event. Please make sure you call
* the parent implementation first if you override this method.
*/ */
public function send() public function send()
{ {
$this->trigger(self::EVENT_SEND, new ResponseEvent($this));
} }
} }
...@@ -71,7 +71,7 @@ class Application extends \yii\base\Application ...@@ -71,7 +71,7 @@ class Application extends \yii\base\Application
} else { } else {
$response = $this->getResponse(); $response = $this->getResponse();
if ($result !== null) { if ($result !== null) {
$response->setContent($result); $response->data = $result;
} }
return $response; return $response;
} }
......
...@@ -94,16 +94,26 @@ class PageCache extends ActionFilter ...@@ -94,16 +94,26 @@ class PageCache extends ActionFilter
$properties[$name] = $this->$name; $properties[$name] = $this->$name;
} }
$id = $this->varyByRoute ? $action->getUniqueId() : __CLASS__; $id = $this->varyByRoute ? $action->getUniqueId() : __CLASS__;
return $this->view->beginCache($id, $properties); ob_start();
ob_implicit_flush(false);
if ($this->view->beginCache($id, $properties)) {
return true;
} else {
Yii::$app->getResponse()->content = ob_get_clean();
return false;
}
} }
/** /**
* This method is invoked right after an action is executed. * This method is invoked right after an action is executed.
* You may override this method to do some postprocessing for the action. * You may override this method to do some postprocessing for the action.
* @param Action $action the action just executed. * @param Action $action the action just executed.
* @param mixed $result the action execution result
*/ */
public function afterAction($action) public function afterAction($action, &$result)
{ {
echo $result;
$this->view->endCache(); $this->view->endCache();
$result = ob_get_clean();
} }
} }
...@@ -23,6 +23,20 @@ use yii\helpers\StringHelper; ...@@ -23,6 +23,20 @@ use yii\helpers\StringHelper;
*/ */
class Response extends \yii\base\Response class Response extends \yii\base\Response
{ {
/**
* @event ResponseEvent an event that is triggered at the beginning of [[send()]].
*/
const EVENT_BEFORE_SEND = 'beforeSend';
/**
* @event ResponseEvent an event that is triggered at the end of [[send()]].
*/
const EVENT_AFTER_SEND = 'afterSend';
/**
* @event ResponseEvent an event that is triggered right after [[prepare()]] is called in [[send()]].
* You may respond to this event to filter the response content before it is sent to the client.
*/
const EVENT_PREPARE = 'prepare';
const FORMAT_RAW = 'raw'; const FORMAT_RAW = 'raw';
const FORMAT_HTML = 'html'; const FORMAT_HTML = 'html';
const FORMAT_JSON = 'json'; const FORMAT_JSON = 'json';
...@@ -30,16 +44,46 @@ class Response extends \yii\base\Response ...@@ -30,16 +44,46 @@ class Response extends \yii\base\Response
const FORMAT_XML = 'xml'; const FORMAT_XML = 'xml';
/** /**
* @var string the response format. * @var string the response format. This determines how to convert [[data]] into [[content]]
* when the latter is not set. By default, the following formats are supported:
*
* - [[FORMAT_RAW]]: the data will be treated as the response content without any conversion.
* No extra HTTP header will be added.
* - [[FORMAT_HTML]]: the data will be treated as the response content without any conversion.
* The "Content-Type" header will set as "text/html" if it is not set previously.
* - [[FORMAT_JSON]]: the data will be converted into JSON format, and the "Content-Type"
* header will be set as "application/json".
* - [[FORMAT_JSONP]]: the data will be converted into JSONP format, and the "Content-Type"
* 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. Please refer to [[XmlResponseFormatter]]
* for more details.
*
* You may customize the formatting process or support additional formats by configuring [[formatters]].
* @see formatters
*/ */
public $format = self::FORMAT_HTML; public $format = self::FORMAT_HTML;
/** /**
* @var array the formatters for converting data into the response content of the specified [[format]]. * @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 * The array keys are the format names, and the array values are the corresponding configurations
* for creating the formatter objects. * for creating the formatter objects.
* @see format
*/ */
public $formatters; public $formatters;
/** /**
* @var mixed the original response data. When this is not null, it will be converted into [[content]]
* according to [[format]] when the response is being sent out.
* @see content
*/
public $data;
/**
* @var string the response content. When [[data]] is not null, it will be converted into [[content]]
* according to [[format]] when the response is being sent out.
* @see data
*/
public $content;
/**
* @var string the charset of the text response. If not set, it will use * @var string the charset of the text response. If not set, it will use
* the value of [[Application::charset]]. * the value of [[Application::charset]].
*/ */
...@@ -203,9 +247,12 @@ class Response extends \yii\base\Response ...@@ -203,9 +247,12 @@ class Response extends \yii\base\Response
*/ */
public function send() public function send()
{ {
parent::send(); $this->trigger(self::EVENT_BEFORE_SEND, new ResponseEvent($this));
$this->prepare();
$this->trigger(self::EVENT_PREPARE, new ResponseEvent($this));
$this->sendHeaders(); $this->sendHeaders();
$this->sendContent(); $this->sendContent();
$this->trigger(self::EVENT_AFTER_SEND, new ResponseEvent($this));
$this->clear(); $this->clear();
} }
...@@ -217,7 +264,8 @@ class Response extends \yii\base\Response ...@@ -217,7 +264,8 @@ class Response extends \yii\base\Response
$this->_headers = null; $this->_headers = null;
$this->_cookies = null; $this->_cookies = null;
$this->_statusCode = null; $this->_statusCode = null;
$this->_content = null; $this->data = null;
$this->content = null;
$this->statusText = null; $this->statusText = null;
} }
...@@ -271,7 +319,7 @@ class Response extends \yii\base\Response ...@@ -271,7 +319,7 @@ class Response extends \yii\base\Response
*/ */
protected function sendContent() protected function sendContent()
{ {
echo $this->getContent(); echo $this->content;
} }
/** /**
...@@ -322,12 +370,13 @@ class Response extends \yii\base\Response ...@@ -322,12 +370,13 @@ class Response extends \yii\base\Response
if ($begin !=0 || $end != $contentLength - 1) { if ($begin !=0 || $end != $contentLength - 1) {
$this->setStatusCode(206); $this->setStatusCode(206);
$headers->set('Content-Range', "bytes $begin-$end/$contentLength"); $headers->set('Content-Range', "bytes $begin-$end/$contentLength");
$this->setContent(StringHelper::substr($content, $begin, $end - $begin + 1), self::FORMAT_RAW); $this->content = StringHelper::substr($content, $begin, $end - $begin + 1);
} else { } else {
$this->setStatusCode(200); $this->setStatusCode(200);
$this->setContent($content, self::FORMAT_RAW); $this->content = $content;
} }
$this->format = self::FORMAT_RAW;
$this->send(); $this->send();
} }
...@@ -368,7 +417,8 @@ class Response extends \yii\base\Response ...@@ -368,7 +417,8 @@ class Response extends \yii\base\Response
->setDefault('Content-Transfer-Encoding', 'binary') ->setDefault('Content-Transfer-Encoding', 'binary')
->setDefault('Content-Length', $length) ->setDefault('Content-Length', $length)
->setDefault('Content-Disposition', "attachment; filename=\"$attachmentName\""); ->setDefault('Content-Disposition', "attachment; filename=\"$attachmentName\"");
$this->format = self::FORMAT_RAW;
$this->data = $this->content = null;
$this->send(); $this->send();
fseek($handle, $begin); fseek($handle, $begin);
...@@ -647,88 +697,56 @@ class Response extends \yii\base\Response ...@@ -647,88 +697,56 @@ class Response extends \yii\base\Response
return in_array($this->getStatusCode(), array(201, 204, 304)); return in_array($this->getStatusCode(), array(201, 204, 304));
} }
private $_content;
/** /**
* @return string the content of this response * Prepares for sending the response.
*/ * The default implementation will convert [[data]] into [[content]] and set headers accordingly.
public function getContent()
{
return $this->_content;
}
/**
* Sets the content of this 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 [[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.
* - [[FORMAT_HTML]]: the data will be treated as the response content without any conversion.
* The "Content-Type" header will set as "text/html" if it is not set previously.
* - [[FORMAT_JSON]]: the data will be converted into JSON format, and the "Content-Type"
* header will be set as "application/json".
* - [[FORMAT_JSONP]]: the data will be converted into JSONP format, and the "Content-Type"
* 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. Please refer to [[XmlResponseFormatter]]
* for more details.
*/
public function setContent($data, $format = null)
{
if ($format !== null) {
$this->format = $format;
}
$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 InvalidParamException if `$format` is not supported
* @throws InvalidConfigException if the formatter for the specified format is invalid * @throws InvalidConfigException if the formatter for the specified format is invalid
*/ */
protected function formatContent($data, $format) protected function prepare()
{ {
if (isset($this->formatters[$format])) { if ($this->data === null) {
$formatter = $this->formatters[$format]; return;
}
if (isset($this->formatters[$this->format])) {
$formatter = $this->formatters[$this->format];
if (!is_object($formatter)) { if (!is_object($formatter)) {
$formatter = Yii::createObject($formatter); $formatter = Yii::createObject($formatter);
} }
if ($formatter instanceof ResponseFormatter) { if ($formatter instanceof ResponseFormatter) {
return $formatter->format($this, $data); $formatter->format($this);
return;
} else { } else {
throw new InvalidConfigException("The '$format' response formatter is invalid. It must implement the ResponseFormatter interface."); throw new InvalidConfigException("The '{$this->format}' response formatter is invalid. It must implement the ResponseFormatter interface.");
} }
} }
switch ($this->format) { switch ($this->format) {
case self::FORMAT_RAW: case self::FORMAT_RAW:
return $data; $this->content = $this->data;
break;
case self::FORMAT_HTML: case self::FORMAT_HTML:
$this->getHeaders()->setDefault('Content-Type', 'text/html; charset=' . $this->charset); $this->getHeaders()->setDefault('Content-Type', 'text/html; charset=' . $this->charset);
return $data; $this->content = $this->data;
break;
case self::FORMAT_JSON: case self::FORMAT_JSON:
$this->getHeaders()->set('Content-Type', 'application/json'); $this->getHeaders()->set('Content-Type', 'application/json');
return Json::encode($data); $this->content = Json::encode($this->data);
break;
case self::FORMAT_JSONP: case self::FORMAT_JSONP:
$this->getHeaders()->set('Content-Type', 'text/javascript; charset=' . $this->charset); $this->getHeaders()->set('Content-Type', 'text/javascript; charset=' . $this->charset);
if (is_array($data) && isset($data['data'], $data['callback'])) { if (is_array($this->data) && isset($this->data['data'], $this->data['callback'])) {
return sprintf('%s(%s);', $data['callback'], Json::encode($data['data'])); $this->content = sprintf('%s(%s);', $this->data['callback'], Json::encode($this->data['data']));
break;
} else { } else {
throw new InvalidParamException("The 'jsonp' response requires that the data be an array consisting of both 'data' and 'callback' elements."); throw new InvalidParamException("The 'jsonp' response requires that the data be an array consisting of both 'data' and 'callback' elements.");
} }
case self::FORMAT_XML: case self::FORMAT_XML:
return Yii::createObject('yii\web\XmlResponseFormatter')->format($this, $data); $this->content = Yii::createObject(XmlResponseFormatter::className())->format($this);
break;
default: default:
throw new InvalidConfigException("Unsupported response format: $format"); throw new InvalidConfigException("Unsupported response format: {$this->format}");
} }
} }
} }
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
* @license http://www.yiiframework.com/license/ * @license http://www.yiiframework.com/license/
*/ */
namespace yii\base; namespace yii\web;
use yii\base\Event;
/** /**
* ResponseEvent represents the event data for the [[Application::EVENT_RESPONSE]] event. * ResponseEvent represents the event data for the [[Application::EVENT_RESPONSE]] event.
...@@ -21,9 +23,6 @@ class ResponseEvent extends Event ...@@ -21,9 +23,6 @@ class ResponseEvent extends Event
{ {
/** /**
* @var Response the response object associated with this event. * @var Response the response object associated with this event.
* You may modify the content in this response or replace it
* with a new response object. The updated or new response will
* be used as the final out.
*/ */
public $response; public $response;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
namespace yii\web; namespace yii\web;
/** /**
* ResponseFormatter specifies the interface needed to format data for a Web response object. * ResponseFormatter specifies the interface needed to format a response before it is sent out.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
...@@ -16,10 +16,8 @@ namespace yii\web; ...@@ -16,10 +16,8 @@ namespace yii\web;
interface ResponseFormatter interface ResponseFormatter
{ {
/** /**
* Formats the given data for the response. * Formats the specified response.
* @param Response $response the response object that will accept the formatted result * @param Response $response the response to be formatted.
* @param mixed $data the data to be formatted
* @return string the formatted result
*/ */
public function format($response, $data); public function format($response);
} }
...@@ -45,19 +45,17 @@ class XmlResponseFormatter extends Component implements ResponseFormatter ...@@ -45,19 +45,17 @@ class XmlResponseFormatter extends Component implements ResponseFormatter
public $itemTag = 'item'; public $itemTag = 'item';
/** /**
* Formats the given data for the response. * Formats the specified response.
* @param Response $response the response object that will accept the formatted result * @param Response $response the response to be formatted.
* @param mixed $data the data to be formatted
* @return string the formatted result
*/ */
public function format($response, $data) public function format($response)
{ {
$response->getHeaders()->set('Content-Type', $this->contentType); $response->getHeaders()->set('Content-Type', $this->contentType);
$dom = new DOMDocument($this->version, $this->encoding === null ? $response->charset : $this->encoding); $dom = new DOMDocument($this->version, $this->encoding === null ? $response->charset : $this->encoding);
$root = new DOMElement($this->rootTag); $root = new DOMElement($this->rootTag);
$dom->appendChild($root); $dom->appendChild($root);
$this->buildXml($root, $data); $this->buildXml($root, $response->data);
return $dom->saveXML(); $response->content = $dom->saveXML();
} }
/** /**
......
...@@ -45,73 +45,92 @@ class XmlResponseFormatterTest extends \yiiunit\TestCase ...@@ -45,73 +45,92 @@ class XmlResponseFormatterTest extends \yiiunit\TestCase
$this->formatter = new XmlResponseFormatter; $this->formatter = new XmlResponseFormatter;
} }
public function testFormatScalars() /**
* @param mixed $data the data to be formatted
* @param string $xml the expected XML body
* @dataProvider formatScalarDataProvider
*/
public function testFormatScalar($data, $xml)
{ {
$head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; $head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
$this->response->data = $data;
$this->formatter->format($this->response);
$this->assertEquals($head . $xml, $this->response->content);
}
$xml = $head . "<response></response>\n"; public function formatScalarDataProvider()
$this->assertEquals($xml, $this->formatter->format($this->response, null)); {
return array(
$xml = $head . "<response>1</response>\n"; array(null, "<response></response>\n"),
$this->assertEquals($xml, $this->formatter->format($this->response, 1)); array(1, "<response>1</response>\n"),
array('abc', "<response>abc</response>\n"),
$xml = $head . "<response>abc</response>\n"; array(true, "<response>1</response>\n"),
$this->assertEquals($xml, $this->formatter->format($this->response, 'abc')); array("<>", "<response>&lt;&gt;</response>\n"),
);
$xml = $head . "<response>1</response>\n";
$this->assertEquals($xml, $this->formatter->format($this->response, true));
} }
public function testFormatArrays() /**
* @param mixed $data the data to be formatted
* @param string $xml the expected XML body
* @dataProvider formatArrayDataProvider
*/
public function testFormatArrays($data, $xml)
{ {
$head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; $head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
$this->response->data = $data;
$this->formatter->format($this->response);
$this->assertEquals($head . $xml, $this->response->content);
}
$xml = $head . "<response/>\n"; public function formatArrayDataProvider()
$this->assertEquals($xml, $this->formatter->format($this->response, array())); {
return array(
$xml = $head . "<response><item>1</item><item>abc</item></response>\n"; array(array(), "<response/>\n"),
$this->assertEquals($xml, $this->formatter->format($this->response, array(1, 'abc'))); array(array(1, 'abc'), "<response><item>1</item><item>abc</item></response>\n"),
array(array(
$xml = $head . "<response><a>1</a><b>abc</b></response>\n";
$this->assertEquals($xml, $this->formatter->format($this->response, array(
'a' => 1, 'a' => 1,
'b' => 'abc', 'b' => 'abc',
))); ), "<response><a>1</a><b>abc</b></response>\n"),
array(array(
$xml = $head . "<response><item>1</item><item>abc</item><item><item>2</item><item>def</item></item><item>1</item></response>\n";
$this->assertEquals($xml, $this->formatter->format($this->response, array(
1, 1,
'abc', 'abc',
array(2, 'def'), array(2, 'def'),
true, true,
))); ), "<response><item>1</item><item>abc</item><item><item>2</item><item>def</item></item><item>1</item></response>\n"),
array(array(
$xml = $head . "<response><a>1</a><b>abc</b><c><item>2</item><item>def</item></c><item>1</item></response>\n";
$this->assertEquals($xml, $this->formatter->format($this->response, array(
'a' => 1, 'a' => 1,
'b' => 'abc', 'b' => 'abc',
'c' => array(2, 'def'), 'c' => array(2, '<>'),
true, true,
))); ), "<response><a>1</a><b>abc</b><c><item>2</item><item>&lt;&gt;</item></c><item>1</item></response>\n"),
);
} }
public function testFormatObjects() /**
* @param mixed $data the data to be formatted
* @param string $xml the expected XML body
* @dataProvider formatObjectDataProvider
*/
public function testFormatObjects($data, $xml)
{ {
$head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; $head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
$this->response->data = $data;
$this->formatter->format($this->response);
$this->assertEquals($head . $xml, $this->response->content);
}
$xml = $head . "<response><Post><id>123</id><title>abc</title></Post></response>\n"; public function formatObjectDataProvider()
$this->assertEquals($xml, $this->formatter->format($this->response, new Post(123, 'abc'))); {
return array(
$xml = $head . "<response><Post><id>123</id><title>abc</title></Post><Post><id>456</id><title>def</title></Post></response>\n"; array(new Post(123, 'abc'), "<response><Post><id>123</id><title>abc</title></Post></response>\n"),
$this->assertEquals($xml, $this->formatter->format($this->response, array( array(array(
new Post(123, 'abc'), new Post(123, 'abc'),
new Post(456, 'def'), new Post(456, 'def'),
))); ), "<response><Post><id>123</id><title>abc</title></Post><Post><id>456</id><title>def</title></Post></response>\n"),
array(array(
$xml = $head . "<response><Post><id>123</id><title>abc</title></Post><a><Post><id>456</id><title>def</title></Post></a></response>\n"; new Post(123, '<>'),
$this->assertEquals($xml, $this->formatter->format($this->response, array(
new Post(123, 'abc'),
'a' => new Post(456, 'def'), 'a' => new Post(456, 'def'),
))); ), "<response><Post><id>123</id><title>&lt;&gt;</title></Post><a><Post><id>456</id><title>def</title></Post></a></response>\n"),
);
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment