BaseResponse.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-License-Identifier: AGPL-3.0-or-later
  5. */
  6. namespace OC\AppFramework\OCS;
  7. use OCP\AppFramework\Http;
  8. use OCP\AppFramework\Http\DataResponse;
  9. use OCP\AppFramework\Http\Response;
  10. /**
  11. * @psalm-import-type DataResponseType from DataResponse
  12. * @template S of int
  13. * @template-covariant T of DataResponseType
  14. * @template H of array<string, mixed>
  15. * @template-extends Response<int, array<string, mixed>>
  16. */
  17. abstract class BaseResponse extends Response {
  18. /** @var array */
  19. protected $data;
  20. /** @var string */
  21. protected $format;
  22. /** @var ?string */
  23. protected $statusMessage;
  24. /** @var ?int */
  25. protected $itemsCount;
  26. /** @var ?int */
  27. protected $itemsPerPage;
  28. /**
  29. * BaseResponse constructor.
  30. *
  31. * @param DataResponse<S, T, H> $dataResponse
  32. * @param string $format
  33. * @param string|null $statusMessage
  34. * @param int|null $itemsCount
  35. * @param int|null $itemsPerPage
  36. */
  37. public function __construct(DataResponse $dataResponse,
  38. $format = 'xml',
  39. $statusMessage = null,
  40. $itemsCount = null,
  41. $itemsPerPage = null) {
  42. parent::__construct();
  43. $this->format = $format;
  44. $this->statusMessage = $statusMessage;
  45. $this->itemsCount = $itemsCount;
  46. $this->itemsPerPage = $itemsPerPage;
  47. $this->data = $dataResponse->getData();
  48. $this->setHeaders($dataResponse->getHeaders());
  49. $this->setStatus($dataResponse->getStatus());
  50. $this->setETag($dataResponse->getETag());
  51. $this->setLastModified($dataResponse->getLastModified());
  52. $this->setCookies($dataResponse->getCookies());
  53. if ($dataResponse->isThrottled()) {
  54. $throttleMetadata = $dataResponse->getThrottleMetadata();
  55. $this->throttle($throttleMetadata);
  56. }
  57. if ($format === 'json') {
  58. $this->addHeader(
  59. 'Content-Type', 'application/json; charset=utf-8'
  60. );
  61. } else {
  62. $this->addHeader(
  63. 'Content-Type', 'application/xml; charset=utf-8'
  64. );
  65. }
  66. }
  67. /**
  68. * @param array<string,string|int> $meta
  69. * @return string
  70. */
  71. protected function renderResult(array $meta): string {
  72. $status = $this->getStatus();
  73. if ($status === Http::STATUS_NO_CONTENT ||
  74. $status === Http::STATUS_NOT_MODIFIED ||
  75. ($status >= 100 && $status <= 199)) {
  76. // Those status codes are not supposed to have a body:
  77. // https://stackoverflow.com/q/8628725
  78. return '';
  79. }
  80. $response = [
  81. 'ocs' => [
  82. 'meta' => $meta,
  83. 'data' => $this->data,
  84. ],
  85. ];
  86. if ($this->format === 'json') {
  87. return json_encode($response, JSON_HEX_TAG);
  88. }
  89. $writer = new \XMLWriter();
  90. $writer->openMemory();
  91. $writer->setIndent(true);
  92. $writer->startDocument();
  93. $this->toXML($response, $writer);
  94. $writer->endDocument();
  95. return $writer->outputMemory(true);
  96. }
  97. protected function toXML(array $array, \XMLWriter $writer): void {
  98. foreach ($array as $k => $v) {
  99. if ($k === '@attributes' && is_array($v)) {
  100. foreach ($v as $k2 => $v2) {
  101. $writer->writeAttribute($k2, $v2);
  102. }
  103. continue;
  104. }
  105. if (\is_string($k) && str_starts_with($k, '@')) {
  106. $writer->writeAttribute(substr($k, 1), $v);
  107. continue;
  108. }
  109. if (\is_numeric($k)) {
  110. $k = 'element';
  111. }
  112. if ($v instanceof \stdClass) {
  113. $v = [];
  114. }
  115. if ($k === '$comment') {
  116. $writer->writeComment($v);
  117. } elseif (\is_array($v)) {
  118. $writer->startElement($k);
  119. $this->toXML($v, $writer);
  120. $writer->endElement();
  121. } elseif ($v instanceof \JsonSerializable) {
  122. $writer->startElement($k);
  123. $this->toXML($v->jsonSerialize(), $writer);
  124. $writer->endElement();
  125. } else {
  126. $writer->writeElement($k, $v);
  127. }
  128. }
  129. }
  130. public function getOCSStatus() {
  131. return parent::getStatus();
  132. }
  133. }