OutputEndpointData.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <?php
  2. namespace Knuckles\Camel\Output;
  3. use Illuminate\Http\UploadedFile;
  4. use Illuminate\Routing\Route;
  5. use Knuckles\Camel\BaseDTO;
  6. use Knuckles\Camel\Extraction\Metadata;
  7. use Knuckles\Camel\Extraction\ResponseCollection;
  8. use Knuckles\Camel\Extraction\ResponseField;
  9. use Knuckles\Scribe\Extracting\Extractor;
  10. use Knuckles\Scribe\Tools\Utils as u;
  11. class OutputEndpointData extends BaseDTO
  12. {
  13. /**
  14. * @var array<string>
  15. */
  16. public array $httpMethods;
  17. public string $uri;
  18. public Metadata $metadata;
  19. /**
  20. * @var array<string,string>
  21. */
  22. public array $headers = [];
  23. /**
  24. * @var array<string,\Knuckles\Camel\Output\Parameter>
  25. */
  26. public array $urlParameters = [];
  27. /**
  28. * @var array<string,mixed>
  29. */
  30. public array $cleanUrlParameters = [];
  31. /**
  32. * @var array<string,\Knuckles\Camel\Output\Parameter>
  33. */
  34. public array $queryParameters = [];
  35. /**
  36. * @var array<string,mixed>
  37. */
  38. public array $cleanQueryParameters = [];
  39. /**
  40. * @var array<string, \Knuckles\Camel\Output\Parameter>
  41. */
  42. public array $bodyParameters = [];
  43. /**
  44. * @var array<string,mixed>
  45. */
  46. public array $cleanBodyParameters = [];
  47. /**
  48. * @var array<string,\Illuminate\Http\UploadedFile>
  49. */
  50. public array $fileParameters = [];
  51. public ResponseCollection $responses;
  52. /**
  53. * @var array<string,\Knuckles\Camel\Extraction\ResponseField>
  54. */
  55. public array $responseFields = [];
  56. /**
  57. * @var array<string, array>
  58. */
  59. public array $nestedBodyParameters = [];
  60. public ?string $boundUri;
  61. public function __construct(array $parameters = [])
  62. {
  63. // spatie/dto currently doesn't auto-cast nested DTOs like that
  64. $parameters['responses'] = new ResponseCollection($parameters['responses']);
  65. $parameters['bodyParameters'] = array_map(function ($param) {
  66. return new Parameter($param);
  67. }, $parameters['bodyParameters']);
  68. $parameters['queryParameters'] = array_map(function ($param) {
  69. return new Parameter($param);
  70. }, $parameters['queryParameters']);
  71. $parameters['urlParameters'] = array_map(function ($param) {
  72. return new Parameter($param);
  73. }, $parameters['urlParameters']);
  74. $parameters['responseFields'] = array_map(function ($param) {
  75. return new ResponseField($param);
  76. }, $parameters['responseFields']);
  77. parent::__construct($parameters);
  78. $this->cleanBodyParameters = Extractor::cleanParams($this->bodyParameters);
  79. $this->cleanQueryParameters = Extractor::cleanParams($this->queryParameters);
  80. $this->cleanUrlParameters = Extractor::cleanParams($this->urlParameters);
  81. $this->nestedBodyParameters = Extractor::nestArrayAndObjectFields($this->bodyParameters, $this->cleanBodyParameters);
  82. $this->boundUri = u::getUrlWithBoundParameters($this->uri, $this->cleanUrlParameters);
  83. [$files, $regularParameters] = static::getFileParameters($this->cleanBodyParameters);
  84. if (count($files)) {
  85. $this->headers['Content-Type'] = 'multipart/form-data';
  86. }
  87. $this->fileParameters = $files;
  88. $this->cleanBodyParameters = $regularParameters;
  89. }
  90. /**
  91. * @param Route $route
  92. *
  93. * @return array<string>
  94. */
  95. public static function getMethods(Route $route): array
  96. {
  97. $methods = $route->methods();
  98. // Laravel adds an automatic "HEAD" endpoint for each GET request, so we'll strip that out,
  99. // but not if there's only one method (means it was intentional)
  100. if (count($methods) === 1) {
  101. return $methods;
  102. }
  103. return array_diff($methods, ['HEAD']);
  104. }
  105. public static function fromExtractedEndpointArray(array $endpoint): OutputEndpointData
  106. {
  107. return new self($endpoint);
  108. }
  109. public function endpointId(): string
  110. {
  111. return $this->httpMethods[0] . str_replace(['/', '?', '{', '}', ':', '\\', '+', '|'], '-', $this->uri);
  112. }
  113. public function hasResponses(): bool
  114. {
  115. return count($this->responses) > 0;
  116. }
  117. public function hasFiles(): bool
  118. {
  119. return count($this->fileParameters) > 0;
  120. }
  121. public function isArrayBody(): bool
  122. {
  123. return count($this->nestedBodyParameters) === 1
  124. && array_keys($this->nestedBodyParameters)[0] === "[]";
  125. }
  126. public function isGet(): bool
  127. {
  128. return in_array('GET', $this->httpMethods);
  129. }
  130. public function hasHeadersOrQueryOrBodyParams(): bool
  131. {
  132. return !empty($this->headers)
  133. || !empty($this->cleanQueryParameters)
  134. || !empty($this->cleanBodyParameters);
  135. }
  136. public static function getFileParameters(array $parameters): array
  137. {
  138. $files = [];
  139. $regularParameters = [];
  140. foreach ($parameters as $name => $example) {
  141. if ($example instanceof UploadedFile) {
  142. $files[$name] = $example;
  143. } else if (is_array($example)) {
  144. [$subFiles, $subRegulars] = static::getFileParameters($example);
  145. foreach ($subFiles as $subName => $subExample) {
  146. $files[$name][$subName] = $subExample;
  147. }
  148. foreach ($subRegulars as $subName => $subExample) {
  149. $regularParameters[$name][$subName] = $subExample;
  150. }
  151. } else {
  152. $regularParameters[$name] = $example;
  153. }
  154. }
  155. return [$files, $regularParameters];
  156. }
  157. }