-
Notifications
You must be signed in to change notification settings - Fork 1
/
CollectionJsonLdResponse.php
122 lines (104 loc) · 4.18 KB
/
CollectionJsonLdResponse.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<?php
declare(strict_types=1);
namespace YaPro\ApiRationBundle\Response\JsonLd;
use ArrayObject;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use UnexpectedValueException;
class CollectionJsonLdResponse extends JsonResponse
{
public const ITEMS = 'hydra:member';
public const TOTAL_ITEMS = 'hydra:totalItems';
public const DEFAULT_PAGE = 0;
public const ITEMS_PER_PAGE = 10;
public const PAGE_FIELD = 'page';
public const ITEMS_PER_PAGE_FIELD = 'itemsPerPage';
private Request $request;
private int $page = 0;
private int $offset = 0;
private int $limit = 0;
public function __construct(Request $request, int $page = null, int $itemsPerPage = null)
{
parent::__construct(null, Response::HTTP_NOT_FOUND);
$this->request = $request;
$this->page = $this->findPage($page);
$this->limit = $this->findLimit($itemsPerPage);
$this->offset = $this->page * $this->limit;
}
public function findPage(int $page = null): int
{
if ($page !== null) {
return $page;
}
$result = filter_var($this->request->query->get(self::PAGE_FIELD, 0), FILTER_VALIDATE_INT);
// client может указать номер страницы, но значение может быть запредельным:
return $result > 0 ? $result - 1 : 0;
}
public function findLimit(int $itemsPerPage = null): int
{
if ($itemsPerPage !== null) {
return $itemsPerPage;
}
$result = $this->request->query->get(self::ITEMS_PER_PAGE_FIELD, self::ITEMS_PER_PAGE);
$result = filter_var($result, FILTER_VALIDATE_INT);
// client может сам указать кол-во возвращаемых строк, но значение может быть запредельным:
if ($result < 0 || $result > 100) {
return 100;
}
return $result;
}
public function initData(array $items = [], int $totalItems = 0): self
{
if ($this->getContent() !== '{}') {
throw new UnexpectedValueException('Data has already been specified');
}
$this->setData($this->getDataArrayObject($items, $totalItems));
$this->setStatusCode(Response::HTTP_OK);
return $this;
}
public function getRequestPathWithoutPage(): string
{
$getVariables = $this->request->query->all();
unset($getVariables[self::PAGE_FIELD]);
/*
* Функция http_build_query удаляет параметры со значениями null и преобразует true/false в 0 и 1
* Для формирования корректной подписи, требуется рекурсивное преобразование элементов
* Про null - https://secure.php.net/manual/ru/function.http-build-query.php#60523
*/
return $this->request->getPathInfo() . '?' . http_build_query($getVariables) . '&';
}
public function getDataArrayObject(array $items = [], int $totalItems = 0): ArrayObject
{
$result = new ArrayObject([
'@type' => 'hydra:Collection',
self::ITEMS => $items,
self::TOTAL_ITEMS => $totalItems,
]);
if (empty($items)) {
return $result;
}
$urlPath = $this->getRequestPathWithoutPage();
$view = [
'@type' => 'hydra:PartialCollectionView',
'@id' => $urlPath . self::PAGE_FIELD . '=' . $this->page, // текущая
'hydra:first' => $urlPath . self::PAGE_FIELD . '=' . self::DEFAULT_PAGE,
'hydra:last' => $urlPath . self::PAGE_FIELD . '=' . round($totalItems / $this->limit),
'hydra:next' => $urlPath . self::PAGE_FIELD . '=' . ($this->page + 1),
];
$result->offsetSet('hydra:view', $view);
return $result;
}
public function getPage(): int
{
return $this->page;
}
public function getOffset(): int
{
return $this->offset;
}
public function getLimit(): int
{
return $this->limit;
}
}