JsonResponseFormatter.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\web;
  8. use Yii;
  9. use yii\base\Component;
  10. use yii\helpers\Json;
  11. /**
  12. * JsonResponseFormatter formats the given data into a JSON or JSONP response content.
  13. *
  14. * It is used by [[Response]] to format response data.
  15. *
  16. * To configure properties like [[encodeOptions]] or [[prettyPrint]], you can configure the `response`
  17. * application component like the following:
  18. *
  19. * ```php
  20. * 'response' => [
  21. * // ...
  22. * 'formatters' => [
  23. * \yii\web\Response::FORMAT_JSON => [
  24. * 'class' => 'yii\web\JsonResponseFormatter',
  25. * 'prettyPrint' => YII_DEBUG, // use "pretty" output in debug mode
  26. * // ...
  27. * ],
  28. * ],
  29. * ],
  30. * ```
  31. *
  32. * @author Qiang Xue <qiang.xue@gmail.com>
  33. * @since 2.0
  34. */
  35. class JsonResponseFormatter extends Component implements ResponseFormatterInterface
  36. {
  37. /**
  38. * JSON Content Type
  39. * @since 2.0.14
  40. */
  41. const CONTENT_TYPE_JSONP = 'application/javascript; charset=UTF-8';
  42. /**
  43. * JSONP Content Type
  44. * @since 2.0.14
  45. */
  46. const CONTENT_TYPE_JSON = 'application/json; charset=UTF-8';
  47. /**
  48. * HAL JSON Content Type
  49. * @since 2.0.14
  50. */
  51. const CONTENT_TYPE_HAL_JSON = 'application/hal+json; charset=UTF-8';
  52. /**
  53. * @var string|null custom value of the `Content-Type` header of the response.
  54. * When equals `null` default content type will be used based on the `useJsonp` property.
  55. * @since 2.0.14
  56. */
  57. public $contentType;
  58. /**
  59. * @var bool whether to use JSONP response format. When this is true, the [[Response::data|response data]]
  60. * must be an array consisting of `data` and `callback` members. The latter should be a JavaScript
  61. * function name while the former will be passed to this function as a parameter.
  62. */
  63. public $useJsonp = false;
  64. /**
  65. * @var int the encoding options passed to [[Json::encode()]]. For more details please refer to
  66. * <https://secure.php.net/manual/en/function.json-encode.php>.
  67. * Default is `JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE`.
  68. * This property has no effect, when [[useJsonp]] is `true`.
  69. * @since 2.0.7
  70. */
  71. public $encodeOptions = 320;
  72. /**
  73. * @var bool whether to format the output in a readable "pretty" format. This can be useful for debugging purpose.
  74. * If this is true, `JSON_PRETTY_PRINT` will be added to [[encodeOptions]].
  75. * Defaults to `false`.
  76. * This property has no effect, when [[useJsonp]] is `true`.
  77. * @since 2.0.7
  78. */
  79. public $prettyPrint = false;
  80. /**
  81. * Formats the specified response.
  82. * @param Response $response the response to be formatted.
  83. */
  84. public function format($response)
  85. {
  86. if ($this->contentType === null) {
  87. $this->contentType = $this->useJsonp
  88. ? self::CONTENT_TYPE_JSONP
  89. : self::CONTENT_TYPE_JSON;
  90. } elseif (strpos($this->contentType, 'charset') === false) {
  91. $this->contentType .= '; charset=UTF-8';
  92. }
  93. $response->getHeaders()->set('Content-Type', $this->contentType);
  94. if ($this->useJsonp) {
  95. $this->formatJsonp($response);
  96. } else {
  97. $this->formatJson($response);
  98. }
  99. }
  100. /**
  101. * Formats response data in JSON format.
  102. * @param Response $response
  103. */
  104. protected function formatJson($response)
  105. {
  106. if ($response->data !== null) {
  107. $options = $this->encodeOptions;
  108. if ($this->prettyPrint) {
  109. $options |= JSON_PRETTY_PRINT;
  110. }
  111. $response->content = Json::encode($response->data, $options);
  112. } elseif ($response->content === null) {
  113. $response->content = 'null';
  114. }
  115. }
  116. /**
  117. * Formats response data in JSONP format.
  118. * @param Response $response
  119. */
  120. protected function formatJsonp($response)
  121. {
  122. if (is_array($response->data)
  123. && isset($response->data['data'], $response->data['callback'])
  124. ) {
  125. $response->content = sprintf(
  126. '%s(%s);',
  127. $response->data['callback'],
  128. Json::htmlEncode($response->data['data'])
  129. );
  130. } elseif ($response->data !== null) {
  131. $response->content = '';
  132. Yii::warning(
  133. "The 'jsonp' response requires that the data be an array consisting of both 'data' and 'callback' elements.",
  134. __METHOD__
  135. );
  136. }
  137. }
  138. }