Skip to content

Commit bc64683

Browse files
committed
Update json response and stream
1 parent 10dfe2f commit bc64683

File tree

5 files changed

+98
-87
lines changed

5 files changed

+98
-87
lines changed

src/JsonResponse.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace FastForward\Http\Message;
4+
5+
use Nyholm\Psr7\Response;
6+
7+
/**
8+
* @method getBody(): JsonStreamInterface
9+
*/
10+
final class JsonResponse extends Response implements JsonResponseInterface
11+
{
12+
public function __construct(
13+
mixed $payload = [],
14+
StatusCode $status = StatusCode::OK,
15+
) {
16+
parent::__construct(
17+
status: $status->value,
18+
headers: ['Content-Type' => 'application/json; charset=utf-8'],
19+
body: $this->createBody($payload),
20+
reason: $status->reasonPhrase(),
21+
);
22+
}
23+
24+
private function createBody(mixed $payload): JsonStreamInterface
25+
{
26+
return new JsonStream($payload);
27+
}
28+
29+
public function getPayload(): mixed
30+
{
31+
return $this->getBody()->getPayload();
32+
}
33+
34+
public function withPayload(mixed $payload): self
35+
{
36+
return $this->withBody($this->createBody($payload));
37+
}
38+
}

src/JsonResponseInterface.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace FastForward\Http\Message;
4+
5+
use Psr\Http\Message\ResponseInterface;
6+
7+
interface JsonResponseInterface extends ResponseInterface, PayloadAwareInterface
8+
{
9+
}

src/JsonStream.php

Lines changed: 10 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,7 @@
1818
*/
1919
final class JsonStream extends Stream implements JsonStreamInterface
2020
{
21-
/**
22-
* @var resource The underlying stream resource containing the JSON-encoded data.
23-
* This resource MUST be a writable PHP stream.
24-
*/
25-
private $stream;
26-
27-
/**
28-
* @var mixed The original payload data prior to JSON encoding.
29-
* This MAY be any JSON-encodable PHP type, excluding resources.
30-
*/
31-
private mixed $payload;
21+
public const ENCODING_OPTIONS = JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
3222

3323
/**
3424
* Constructs a new JsonStream instance with the provided payload.
@@ -39,11 +29,14 @@ final class JsonStream extends Stream implements JsonStreamInterface
3929
* @param mixed $payload The data to encode as JSON. MUST be JSON-encodable. Resources are explicitly prohibited.
4030
* @param int $encodingOptions Optional JSON encoding flags as defined by {@see json_encode()}. Defaults to 0.
4131
*/
42-
public function __construct(mixed $payload, private int $encodingOptions = 0)
43-
{
44-
$this->setPayload($payload);
32+
public function __construct(
33+
private mixed $payload,
34+
private int $encodingOptions = self::ENCODING_OPTIONS
35+
) {
36+
parent::__construct(fopen('php://temp', 'wb+'));
4537

46-
parent::__construct($this->stream);
38+
$this->write($this->jsonEncode($this->payload, $this->encodingOptions));
39+
$this->rewind();
4740
}
4841

4942
/**
@@ -71,55 +64,13 @@ private function jsonEncode(mixed $data, int $encodingOptions): string
7164
return json_encode($data, $encodingOptions | JSON_THROW_ON_ERROR);
7265
}
7366

74-
/**
75-
* Sets the payload and updates the underlying stream with its JSON-encoded form.
76-
*
77-
* This method SHALL encode the payload as JSON, write it to a temporary stream, and rewind the stream pointer.
78-
* It also retains the original decoded payload for later access.
79-
*
80-
* @param mixed $data The data to encode as JSON. MUST be JSON-encodable.
81-
* @return self The current instance for fluent chaining.
82-
*
83-
* @throws \InvalidArgumentException If the data contains a resource.
84-
* @throws \JsonException If JSON encoding fails.
85-
*/
86-
private function setPayload(mixed $data): self
87-
{
88-
$contents = $this->jsonEncode($data, $this->encodingOptions);
89-
90-
$this->payload = $data;
91-
$this->stream = fopen('php://temp', 'wb+');
92-
93-
$this->write($contents);
94-
$this->rewind();
95-
96-
return $this;
97-
}
98-
99-
/**
100-
* Retrieves the decoded payload previously provided to the stream.
101-
*
102-
* @return mixed The original decoded payload, which MAY be of any JSON-encodable PHP type.
103-
*/
10467
public function getPayload(): mixed
10568
{
10669
return $this->payload;
10770
}
10871

109-
/**
110-
* Returns a new instance with the updated payload encoded as JSON.
111-
*
112-
* This method SHALL NOT modify the current instance. It MUST return a cloned instance with the new payload
113-
* written to its stream.
114-
*
115-
* @param mixed $data The new data to encode as JSON. MUST be JSON-encodable.
116-
* @return self A new instance with the updated JSON payload.
117-
*
118-
* @throws \InvalidArgumentException If the data contains a resource.
119-
* @throws \JsonException If JSON encoding fails.
120-
*/
121-
public function withPayload(mixed $data): self
72+
public function withPayload(mixed $payload): self
12273
{
123-
return (clone $this)->setPayload($data);
74+
return new self($payload);
12475
}
12576
}

src/JsonStreamInterface.php

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,6 @@
1212
*
1313
* @package FastForward\Http\Message
1414
*/
15-
interface JsonStreamInterface extends StreamInterface
15+
interface JsonStreamInterface extends StreamInterface, PayloadAwareInterface
1616
{
17-
/**
18-
* Retrieves the decoded JSON payload from the stream.
19-
*
20-
* This method MUST return the decoded JSON payload as a native PHP type. The returned type MAY vary depending on
21-
* the structure of the JSON content (e.g., array, object, int, float, string, bool, or null).
22-
*
23-
* If the stream does not contain valid JSON, this method SHOULD return null or throw an appropriate exception
24-
* as defined by the implementation.
25-
*
26-
* @return mixed The decoded JSON payload, which MAY be of any type, including array, object, scalar, or null.
27-
*/
28-
public function getPayload(): mixed;
29-
30-
/**
31-
* Returns a new instance with the provided payload encoded as JSON.
32-
*
33-
* This method MUST NOT modify the existing instance; instead, it SHALL return a new instance with the updated
34-
* JSON payload written to the underlying stream.
35-
*
36-
* The provided data MUST be JSON-encodable. If encoding fails, the method MAY throw an exception as defined
37-
* by the implementation.
38-
*
39-
* @param mixed $data The data to encode as JSON and set as the stream's payload. This MAY be of any type
40-
* supported by json_encode.
41-
* @return self A new instance with the updated JSON payload.
42-
*/
43-
public function withPayload(mixed $data): self;
4417
}

src/PayloadAwareInterface.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace FastForward\Http\Message;
4+
5+
use Psr\Http\Message\StreamInterface;
6+
7+
/**
8+
* Interface PayloadAwareInterface
9+
*
10+
* Provide functionality for JSON payload handling.
11+
*
12+
* @package FastForward\Http\Message
13+
*/
14+
interface PayloadAwareInterface
15+
{
16+
/**
17+
* Retrieves the decoded JSON payload from the stream.
18+
*
19+
* This method MUST return the decoded JSON payload as a native PHP type. The returned type MAY vary depending on
20+
* the structure of the JSON content (e.g., array, object, int, float, string, bool, or null).
21+
*
22+
* @return mixed The decoded JSON payload, which MAY be of any type, including array, object, scalar, or null.
23+
*/
24+
public function getPayload(): mixed;
25+
26+
/**
27+
* Returns a new instance with the provided payload encoded as JSON.
28+
*
29+
* This method MUST NOT modify the existing instance; instead, it SHALL return a new instance with the updated
30+
* JSON payload written to the underlying stream.
31+
*
32+
* The provided data MUST be JSON-encodable. If encoding fails, the method MAY throw an exception as defined
33+
* by the implementation.
34+
*
35+
* @param mixed $payload The data to encode as JSON and set as the stream's payload. This MAY be of any type
36+
* supported by json_encode.
37+
* @return self A new instance with the updated JSON payload.
38+
*/
39+
public function withPayload(mixed $payload): self;
40+
}

0 commit comments

Comments
 (0)