You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

183 lines
4.7 KiB

<?php
/**
* @see https://github.com/zendframework/zend-diactoros for the canonical source repository
* @copyright Copyright (c) 2015-2018 Zend Technologies USA Inc. (http://www.zend.com)
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
*/
declare(strict_types=1);
namespace Zend\Diactoros\Response;
use Zend\Diactoros\Exception;
use Zend\Diactoros\Response;
use Zend\Diactoros\Stream;
use function is_object;
use function is_resource;
use function json_encode;
use function json_last_error;
use function json_last_error_msg;
use function sprintf;
use const JSON_ERROR_NONE;
/**
* JSON response.
*
* Allows creating a response by passing data to the constructor; by default,
* serializes the data to JSON, sets a status code of 200 and sets the
* Content-Type header to application/json.
*/
class JsonResponse extends Response
{
use InjectContentTypeTrait;
/**
* Default flags for json_encode; value of:
*
* <code>
* JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES
* </code>
*
* @const int
*/
const DEFAULT_JSON_FLAGS = 79;
/**
* @var mixed
*/
private $payload;
/**
* @var int
*/
private $encodingOptions;
/**
* Create a JSON response with the given data.
*
* Default JSON encoding is performed with the following options, which
* produces RFC4627-compliant JSON, capable of embedding into HTML.
*
* - JSON_HEX_TAG
* - JSON_HEX_APOS
* - JSON_HEX_AMP
* - JSON_HEX_QUOT
* - JSON_UNESCAPED_SLASHES
*
* @param mixed $data Data to convert to JSON.
* @param int $status Integer status code for the response; 200 by default.
* @param array $headers Array of headers to use at initialization.
* @param int $encodingOptions JSON encoding options to use.
* @throws Exception\InvalidArgumentException if unable to encode the $data to JSON.
*/
public function __construct(
$data,
int $status = 200,
array $headers = [],
int $encodingOptions = self::DEFAULT_JSON_FLAGS
) {
$this->setPayload($data);
$this->encodingOptions = $encodingOptions;
$json = $this->jsonEncode($data, $this->encodingOptions);
$body = $this->createBodyFromJson($json);
$headers = $this->injectContentType('application/json', $headers);
parent::__construct($body, $status, $headers);
}
/**
* @return mixed
*/
public function getPayload()
{
return $this->payload;
}
/**
* @param mixed $data
*/
public function withPayload($data) : JsonResponse
{
$new = clone $this;
$new->setPayload($data);
return $this->updateBodyFor($new);
}
public function getEncodingOptions() : int
{
return $this->encodingOptions;
}
public function withEncodingOptions(int $encodingOptions) : JsonResponse
{
$new = clone $this;
$new->encodingOptions = $encodingOptions;
return $this->updateBodyFor($new);
}
private function createBodyFromJson(string $json) : Stream
{
$body = new Stream('php://temp', 'wb+');
$body->write($json);
$body->rewind();
return $body;
}
/**
* Encode the provided data to JSON.
*
* @param mixed $data
* @throws Exception\InvalidArgumentException if unable to encode the $data to JSON.
*/
private function jsonEncode($data, int $encodingOptions) : string
{
if (is_resource($data)) {
throw new Exception\InvalidArgumentException('Cannot JSON encode resources');
}
// Clear json_last_error()
json_encode(null);
$json = json_encode($data, $encodingOptions);
if (JSON_ERROR_NONE !== json_last_error()) {
throw new Exception\InvalidArgumentException(sprintf(
'Unable to encode data to JSON in %s: %s',
__CLASS__,
json_last_error_msg()
));
}
return $json;
}
/**
* @param mixed $data
*/
private function setPayload($data) : void
{
if (is_object($data)) {
$data = clone $data;
}
$this->payload = $data;
}
/**
* Update the response body for the given instance.
*
* @param self $toUpdate Instance to update.
* @return JsonResponse Returns a new instance with an updated body.
*/
private function updateBodyFor(JsonResponse $toUpdate) : JsonResponse
{
$json = $this->jsonEncode($toUpdate->payload, $toUpdate->encodingOptions);
$body = $this->createBodyFromJson($json);
return $toUpdate->withBody($body);
}
}