alex-kalanis /
restful
| 1 | <?php |
||
| 2 | |||
| 3 | namespace kalanis\Restful\Http; |
||
| 4 | |||
| 5 | |||
| 6 | use kalanis\Restful\Exceptions\InvalidStateException; |
||
| 7 | use kalanis\Restful\Resource\Link; |
||
| 8 | use kalanis\Restful\Utils\RequestFilter; |
||
| 9 | use Nette\Http\IRequest; |
||
| 10 | use Nette\Http\IResponse; |
||
| 11 | use Nette\Http\Response; |
||
| 12 | use Nette\Utils\Paginator; |
||
| 13 | |||
| 14 | |||
| 15 | /** |
||
| 16 | * ResponseFactory |
||
| 17 | * @package kalanis\Restful\Http |
||
| 18 | */ |
||
| 19 | class ResponseFactory |
||
| 20 | { |
||
| 21 | |||
| 22 | /** @var array<string, int> Default response code for each request method */ |
||
| 23 | protected array $defaultCodes = [ |
||
| 24 | IRequest::Get => 200, |
||
| 25 | IRequest::Post => 201, |
||
| 26 | IRequest::Put => 200, |
||
| 27 | IRequest::Head => 200, |
||
| 28 | IRequest::Delete => 200, |
||
| 29 | 'PATCH' => 200, |
||
| 30 | ]; |
||
| 31 | |||
| 32 | private ?IResponse $response = null; |
||
| 33 | |||
| 34 | 1 | public function __construct( |
|
| 35 | private readonly IRequest $request, |
||
| 36 | private readonly RequestFilter $requestFilter, |
||
| 37 | ) |
||
| 38 | { |
||
| 39 | 1 | } |
|
| 40 | |||
| 41 | /** |
||
| 42 | * Set original wrapper response since nette does not support custom response codes |
||
| 43 | */ |
||
| 44 | public function setResponse(IResponse $response): static |
||
| 45 | { |
||
| 46 | 1 | $this->response = $response; |
|
| 47 | 1 | return $this; |
|
| 48 | } |
||
| 49 | |||
| 50 | /** |
||
| 51 | * Create HTTP response |
||
| 52 | * @param int|null $code |
||
| 53 | * @return IResponse |
||
| 54 | */ |
||
| 55 | public function createHttpResponse(?int $code = null): IResponse |
||
| 56 | { |
||
| 57 | 1 | $response = $this->response ?: new Response(); |
|
| 58 | 1 | $response->setCode($this->getCode($code)); |
|
| 59 | |||
| 60 | try { |
||
| 61 | 1 | $response->setHeader('Link', $this->getPaginatorLink()); |
|
| 62 | 1 | $response->setHeader('X-Total-Count', strval(intval($this->getPaginatorTotalCount()))); |
|
| 63 | 1 | } catch (InvalidStateException) { |
|
| 64 | // Don't use paginator |
||
| 65 | } |
||
| 66 | 1 | return $response; |
|
| 67 | } |
||
| 68 | |||
| 69 | /** |
||
| 70 | * Get default status code |
||
| 71 | * @param int|null $code |
||
| 72 | * @return int |
||
| 73 | */ |
||
| 74 | protected function getCode(?int $code = null): int |
||
| 75 | { |
||
| 76 | 1 | if (is_null($code)) { |
|
| 77 | 1 | $code = $this->defaultCodes[$this->request->getMethod()] ?? 200; |
|
| 78 | } |
||
| 79 | 1 | return intval($code); |
|
| 80 | } |
||
| 81 | |||
| 82 | /** |
||
| 83 | * Get paginator next/last link header |
||
| 84 | * @return string |
||
| 85 | */ |
||
| 86 | protected function getPaginatorLink(): string |
||
| 87 | { |
||
| 88 | 1 | $paginator = $this->requestFilter->getPaginator(); |
|
| 89 | |||
| 90 | 1 | $link = $this->getNextPageUrl($paginator); |
|
| 91 | 1 | if ($paginator->getItemCount()) { |
|
|
0 ignored issues
–
show
|
|||
| 92 | 1 | $link .= ', ' . $this->getLastPageUrl($paginator); |
|
| 93 | } |
||
| 94 | 1 | return $link; |
|
| 95 | } |
||
| 96 | |||
| 97 | /** |
||
| 98 | * Get next page URL |
||
| 99 | */ |
||
| 100 | private function getNextPageUrl(Paginator $paginator): Link |
||
| 101 | { |
||
| 102 | 1 | $url = clone $this->request->getUrl(); |
|
| 103 | 1 | parse_str($url->getQuery(), $query); |
|
| 104 | 1 | $paginator->setPage($paginator->getPage() + 1); |
|
| 105 | 1 | $query['offset'] = $paginator->getOffset(); |
|
| 106 | 1 | $query['limit'] = $paginator->getItemsPerPage(); |
|
| 107 | 1 | return new Link($url->withQuery(http_build_query($query)), Link::NEXT); |
|
| 108 | } |
||
| 109 | |||
| 110 | /** |
||
| 111 | * Get last page URL |
||
| 112 | */ |
||
| 113 | private function getLastPageUrl(Paginator $paginator): Link |
||
| 114 | { |
||
| 115 | 1 | $url = clone $this->request->getUrl(); |
|
| 116 | 1 | parse_str($url->getQuery(), $query); |
|
| 117 | 1 | $query['offset'] = $paginator->getLastPage() * $paginator->getItemsPerPage() - $paginator->getItemsPerPage(); |
|
| 118 | 1 | $query['limit'] = $paginator->getItemsPerPage(); |
|
| 119 | 1 | return new Link($url->withQuery(http_build_query($query)), Link::LAST); |
|
| 120 | } |
||
| 121 | |||
| 122 | /** |
||
| 123 | * Get paginator items total count |
||
| 124 | * @return int|null |
||
| 125 | */ |
||
| 126 | protected function getPaginatorTotalCount(): ?int |
||
| 127 | { |
||
| 128 | 1 | $paginator = $this->requestFilter->getPaginator(); |
|
| 129 | 1 | return $paginator->getItemCount() ?: null; |
|
| 130 | } |
||
| 131 | } |
||
| 132 |
In PHP, under loose comparison (like
==, or!=, orswitchconditions), values of different types might be equal.For
integervalues, zero is a special case, in particular the following results might be unexpected: