Issues (40)

php-src/Http/ResponseFactory.php (1 issue)

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
Bug Best Practice introduced by
The expression $paginator->getItemCount() of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
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