1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace LaravelUi5\OData\Http;
6:
7: use LaravelUi5\OData\Exception\ProtocolException;
8: use Symfony\Component\HttpFoundation\StreamedResponse;
9: use Throwable;
10:
11: /**
12: * OData HTTP response — supports both streamed and buffered output
13: * with OData error handling.
14: *
15: * @link https://docs.oasis-open.org/odata/odata/v4.01/os/part1-protocol/odata-v4.01-os-part1-protocol.html#_Toc31358909
16: */
17: class ODataResponse extends StreamedResponse
18: {
19: protected bool $streaming = true;
20:
21: public ?Throwable $exception = null;
22:
23: public function __construct(?callable $callback = null, int $status = 200, array $headers = [])
24: {
25: parent::__construct($callback, $status, $headers);
26:
27: $this->streaming = config('odata.streaming', true);
28: }
29:
30: public function sendContent(): static
31: {
32: if ($this->streaming) {
33: $this->headers->set('trailer', 'odata-error');
34: }
35:
36: return $this->streaming ? $this->sendContentStreamed() : $this->sendContentBuffered();
37: }
38:
39: private function sendContentStreamed(): static
40: {
41: try {
42: parent::sendContent();
43: } catch (ProtocolException $e) {
44: flush();
45: ob_flush();
46: echo 'OData-error: ' . json_encode($e->toError(), JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
47: }
48:
49: return $this;
50: }
51:
52: /**
53: * @throws Throwable
54: */
55: private function sendContentBuffered(): static
56: {
57: try {
58: ob_start();
59: parent::sendContent();
60: echo ob_get_clean();
61: } catch (ProtocolException $e) {
62: ob_end_clean();
63: $response = $e->toResponse();
64: $this->setStatusCode($response->getStatusCode());
65: $this->headers->replace($response->headers->all());
66: $response->sendHeaders();
67: $response->sendContentBuffered();
68: return $response;
69: } catch (Throwable $t) {
70: ob_end_clean();
71: throw $t;
72: }
73:
74: return $this;
75: }
76:
77: public function withException(Throwable $e): static
78: {
79: $this->exception = $e;
80:
81: return $this;
82: }
83: }
84: