Skip to content

Commit d73cbef

Browse files
authored
feat: add ability to add custom query parameters to requests (#20)
1 parent 5bbe800 commit d73cbef

File tree

8 files changed

+93
-7
lines changed

8 files changed

+93
-7
lines changed

docs/03-collections.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ These collections will allow you to add, remove or get values by key, getting al
2222
| mergeCollection(SimpleCollectionInterface $collection, bool $overwrite = true) | self | Merges the given collection into the current one. If overwrite is set to true (default) existing values are overwritten by the new values, otherwise they will be ignored. |
2323
| set(string $key, mixed $value) | self | Set a key-value-pair into the collection. |
2424
| remove(string $key) | self | Remove an element by key from the collection. |
25+
| pull(string $key, mixed $defaultValue = null) | self | Get an element by key from the collection and remove it afterwards. |
2526

2627
*****
2728

docs/07-requests.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
|--------------------------------------------------------------------------------------------------------|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
99
| method() | string | The http method of this request |
1010
| uri() | Psr\Http\Message\UriInterface | The request uri |
11+
| customQueryParameters() | KeyValueCollectionInterface | Custom, not by the protocol required query parameters |
1112
| headers() | KeyValueCollectionInterface | Request headers. Can be changed. |
1213
| type() | string | Requested resource type |
1314
| id() | string|null | Requested resource id, if present |

src/Model/Request/Request.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Request implements RequestInterface
3030
private KeyValueCollectionInterface $sorting;
3131
private KeyValueCollectionInterface $pagination;
3232
private ?DocumentInterface $document;
33+
private KeyValueCollectionInterface $customQueryParameters;
3334

3435
/** @var RequestInterface[] */
3536
private array $subRequests = [];
@@ -134,15 +135,15 @@ private function parseUriQuery(string $uriQuery): void
134135
throw new BadRequestException('Invalid include parameter given!');
135136
}
136137

137-
$this->includes = explode(',', $query->getRequired('include'));
138+
$this->includes = explode(',', $query->pull('include'));
138139
}
139140

140141
$this->fields = [];
141142
if ($query->has('fields')) {
142143
if (!is_array($query->getRequired('fields'))) {
143144
throw new BadRequestException('Invalid fields parameter given!');
144145
}
145-
foreach ((array)$query->getRequired('fields') as $type => $fields) {
146+
foreach ((array)$query->pull('fields') as $type => $fields) {
146147
foreach (explode(',', $fields) as $field) {
147148
$this->fields[$type][] = $field;
148149
}
@@ -151,9 +152,9 @@ private function parseUriQuery(string $uriQuery): void
151152

152153
$filter = [];
153154
if ($query->has('filter')) {
154-
$filter = $query->getRequired('filter');
155+
$filter = $query->pull('filter');
155156
if (is_string($filter)) {
156-
$filter = json_decode($query->getRequired('filter'), true);
157+
$filter = json_decode($filter, true);
157158
}
158159
if (!is_array($filter)) {
159160
throw new BadRequestException('Invalid filter parameter given!');
@@ -167,7 +168,7 @@ private function parseUriQuery(string $uriQuery): void
167168
if (!is_array($query->getRequired('page'))) {
168169
throw new BadRequestException('Invalid page parameter given!');
169170
}
170-
$pagination = (array) $query->getRequired('page');
171+
$pagination = (array) $query->pull('page');
171172
}
172173

173174
$this->pagination = new KeyValueCollection($pagination);
@@ -177,7 +178,7 @@ private function parseUriQuery(string $uriQuery): void
177178
if (!is_string($query->getRequired('sort'))) {
178179
throw new BadRequestException('Invalid sort parameter given!');
179180
}
180-
foreach (explode(',', $query->getRequired('sort')) as $field) {
181+
foreach (explode(',', $query->pull('sort')) as $field) {
181182
$direction = self::ORDER_ASC;
182183
if (str_starts_with($field, '-')) {
183184
$field = substr($field, 1);
@@ -188,6 +189,7 @@ private function parseUriQuery(string $uriQuery): void
188189
}
189190

190191
$this->sorting = new KeyValueCollection($sorting);
192+
$this->customQueryParameters = $query;
191193
}
192194

193195
public function method(): string
@@ -201,6 +203,11 @@ public function uri(): UriInterface
201203
return $this->uri;
202204
}
203205

206+
public function customQueryParameters(): KeyValueCollectionInterface
207+
{
208+
return $this->customQueryParameters;
209+
}
210+
204211
/**
205212
* Contains all request headers
206213
*/
@@ -407,7 +414,7 @@ private function updateUriQuery(): void
407414
'filter' => $this->filter->all(),
408415
'include' => implode(',', $this->includes),
409416
'fields' => $fields
410-
];
417+
] + $this->customQueryParameters->all();
411418

412419
// Remove empty query params.
413420
$query = array_filter($query);

src/Model/Request/RequestInterface.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public function method(): string;
1818

1919
public function uri(): UriInterface;
2020

21+
/**
22+
* Custom, not by the protocol required query parameters
23+
*/
24+
public function customQueryParameters(): KeyValueCollectionInterface;
25+
2126
/**
2227
* Contains all request headers.
2328
*/

src/Support/Collection/KeyValueCollection.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,11 @@ public function remove(string $key): KeyValueCollectionInterface
9797

9898
return $this;
9999
}
100+
101+
public function pull(string $key, mixed $defaultValue = null): mixed
102+
{
103+
$value = $this->get($key, $defaultValue);
104+
$this->remove($key);
105+
return $value;
106+
}
100107
}

src/Support/Collection/KeyValueCollectionInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,6 @@ public function mergeCollection(
2929
public function set(string $key, mixed $value): KeyValueCollectionInterface;
3030

3131
public function remove(string $key): KeyValueCollectionInterface;
32+
33+
public function pull(string $key, mixed $defaultValue = null): mixed;
3234
}

tests/Model/Request/RequestTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,41 @@ public function testCreateFromHttpRequest(): void
9595
$this->assertEquals($requestBody, $request->document());
9696
}
9797

98+
public function providesUriWithQueryParameters(): \Generator
99+
{
100+
// '?include=tests,tests.user&fields[user]=username,birthday&page[offset]=0&page[limit]=10&sort=-createdAt&filter[test]=test,test2'
101+
yield ['', [], [], [], []];
102+
yield ['?page[offset]=1&page[limit]=10', ['offset' => 1, 'limit' => 10], [], [], []];
103+
yield ['?sort=-createdAt', [], ['createdAt' => 'desc'], [], []];
104+
yield ['?filter[test]=test,test2', [], [], ['test' => 'test,test2'], []];
105+
yield ['?key1=value1&key2=value2', [], [], [], ['key1' => 'value1', 'key2' => 'value2']];
106+
yield [
107+
'?page[offset]=1&page[limit]=10&sort=-createdAt&filter[test]=test,test2&key1=value1&key2=value2',
108+
['offset' => 1, 'limit' => 10],
109+
['createdAt' => 'desc'],
110+
['test' => 'test,test2'],
111+
['key1' => 'value1', 'key2' => 'value2']
112+
];
113+
114+
}
115+
116+
/**
117+
* @dataProvider providesUriWithQueryParameters
118+
*/
119+
public function testConstructionWithQueryParameters(
120+
string $queryString,
121+
array $page,
122+
array $sort,
123+
array $filter,
124+
array $custom
125+
): void {
126+
$request = new Request('GET', new Uri('/index.php/example' . $queryString), null);
127+
$this->assertEquals($page, $request->pagination()->all(), '$page does not match');
128+
$this->assertEquals($sort, $request->sorting()->all(), '$sort does not match');
129+
$this->assertEquals($filter, $request->filter()->all(), '$filter does not match');
130+
$this->assertEquals($custom, $request->customQueryParameters()->all(), '$custom does not match');
131+
}
132+
98133
public function testRequestInvalidType(): void
99134
{
100135
$this->expectException(BadRequestException::class);
@@ -285,4 +320,23 @@ public function testPersistingOfRuntimeChanges(): void
285320
self::assertArrayHasKey($fieldType, $queryParameters['fields']);
286321
self::assertStringContainsString($fieldName, $queryParameters['fields'][$fieldType]);
287322
}
323+
324+
public function testCustomQueryParameters(): void
325+
{
326+
$request = new Request(
327+
'GET',
328+
new Uri('/index.php/api/examples/example-1'),
329+
null,
330+
'api'
331+
);
332+
333+
$queryKey = $this->faker()->word();
334+
$queryValue = $this->faker()->word();
335+
336+
$request->customQueryParameters()->set($queryKey, $queryValue);
337+
parse_str($request->uri()->getQuery(), $requestQuery);
338+
339+
self::assertArrayHasKey($queryKey, $requestQuery);
340+
self::assertEquals($queryValue, $requestQuery[$queryKey]);
341+
}
288342
}

tests/Support/Collection/KeyValueCollectionTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,13 @@ public function testRemoveInvalid(): void
214214

215215
self::assertTrue($collection->has('test'));
216216
}
217+
218+
public function testPull(): void
219+
{
220+
$collection = new KeyValueCollection(['key' => 'value']);
221+
$value = $collection->pull('key');
222+
223+
self::assertEquals('value', $value);
224+
self::assertFalse($collection->has('key'));
225+
}
217226
}

0 commit comments

Comments
 (0)