Skip to content

Commit 9edc949

Browse files
committed
Add self link to Index endpoint document
1 parent fb2c76a commit 9edc949

File tree

7 files changed

+57
-62
lines changed

7 files changed

+57
-62
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ and this project adheres to
2424
- Add `JsonApi::setTranslator()` method for providing custom translator
2525
implementations
2626
- Add `Context::translate()` method for accessing the translation system
27+
- Add `Context::currentUrl()` method for building the current URL with query
28+
parameter overrides
29+
- Add `self` link to `Index` endpoint document
2730
- Add `Id` field class for customizing resource ID behavior, including type
2831
constraints, client-generated IDs via `writableOnCreate()`, and validation
2932
- Add `linkageMeta()` method to relationship fields for adding meta to resource
@@ -39,6 +42,11 @@ and this project adheres to
3942
- Improve OpenAPI schema generation to properly handle ID field constraints and
4043
avoid redundant properties
4144

45+
### Removed
46+
47+
- Remove `Pagination\Concerns\BuildsUrls` trait (replaced by
48+
`Context::currentUrl()`)
49+
4250
## [1.0.0-beta.6] - 2025-10-02
4351

4452
### ⚠️ Breaking Changes

docs/context.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ class Context
5959
// Translate a message using the API's translator
6060
public function translate(string $key, array $replacements = []): string;
6161

62+
// Get the URL of the current request, optionally with query parameter overrides
63+
public function currentUrl(array $queryParams = []): string;
64+
6265
// Get the parsed JSON:API payload
6366
public function body(): ?array;
6467

src/Context.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,29 @@ public function path(): string
8181
);
8282
}
8383

84+
/**
85+
* Get the URL of the current request, optionally with query parameter overrides.
86+
*/
87+
public function currentUrl(array $queryParams = []): string
88+
{
89+
$queryParams = array_replace_recursive($this->request->getQueryParams(), $queryParams);
90+
91+
if (isset($queryParams['filter'])) {
92+
foreach ($queryParams['filter'] as &$v) {
93+
$v = $v === null ? '' : $v;
94+
}
95+
}
96+
97+
ksort($queryParams);
98+
99+
$queryString = http_build_query($queryParams, '', '&', PHP_QUERY_RFC3986);
100+
101+
return $this->api->basePath .
102+
'/' .
103+
$this->path() .
104+
($queryString ? '?' . $queryString : '');
105+
}
106+
84107
/**
85108
* Get the parsed JSON:API payload.
86109
*/

src/Endpoint/Index.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,11 @@ public function handle(Context $context): ?Response
9191
$this->pagination,
9292
);
9393

94-
return json_api_response($this->buildResourceDocument($models, $context));
94+
$document = $this->buildResourceDocument($models, $context);
95+
96+
$document['links']['self'] ??= $context->currentUrl();
97+
98+
return json_api_response($document);
9599
}
96100

97101
public function getOpenApiPaths(Collection $collection, JsonApi $api): array

src/Pagination/Concerns/BuildsUrls.php

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/Pagination/CursorPagination.php

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@
66
use Tobyz\JsonApiServer\Context;
77
use Tobyz\JsonApiServer\Exception\BadRequestException;
88
use Tobyz\JsonApiServer\Exception\Sourceable;
9-
use Tobyz\JsonApiServer\Pagination\Concerns\BuildsUrls;
109
use Tobyz\JsonApiServer\Pagination\Concerns\HasSizeParameter;
1110
use Tobyz\JsonApiServer\Resource\CursorPaginatable;
1211

1312
class CursorPagination implements Pagination
1413
{
15-
use BuildsUrls;
1614
use HasSizeParameter;
1715

1816
public readonly int $size;
@@ -51,27 +49,21 @@ public function paginate(object $query, Context $context): array
5149
}
5250

5351
if ($page->results && !$page->isFirstPage) {
54-
$context->documentLinks['prev'] = $this->buildUrl(
55-
[
56-
'page' => [
57-
'after' => null,
58-
'before' => $collection->itemCursor($page->results[0], $query, $context),
59-
],
52+
$context->documentLinks['prev'] = $context->currentUrl([
53+
'page' => [
54+
'after' => null,
55+
'before' => $collection->itemCursor($page->results[0], $query, $context),
6056
],
61-
$context,
62-
);
57+
]);
6358
}
6459

6560
if ($page->results && !$page->isLastPage) {
66-
$context->documentLinks['next'] = $this->buildUrl(
67-
[
68-
'page' => [
69-
'before' => null,
70-
'after' => $collection->itemCursor(end($page->results), $query, $context),
71-
],
61+
$context->documentLinks['next'] = $context->currentUrl([
62+
'page' => [
63+
'before' => null,
64+
'after' => $collection->itemCursor(end($page->results), $query, $context),
7265
],
73-
$context,
74-
);
66+
]);
7567
}
7668

7769
return $page->results;

src/Pagination/OffsetPagination.php

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,12 @@
55
use RuntimeException;
66
use Tobyz\JsonApiServer\Context;
77
use Tobyz\JsonApiServer\Exception\BadRequestException;
8-
use Tobyz\JsonApiServer\Pagination\Concerns\BuildsUrls;
98
use Tobyz\JsonApiServer\Pagination\Concerns\HasSizeParameter;
109
use Tobyz\JsonApiServer\Resource\Paginatable;
1110

1211
class OffsetPagination implements Pagination
1312
{
1413
use HasSizeParameter;
15-
use BuildsUrls;
1614

1715
public function __construct(int $defaultLimit = 20, ?int $maxLimit = 50)
1816
{
@@ -35,10 +33,7 @@ public function paginate(object $query, Context $context): array
3533
$page = $collection->paginate($query, $offset, $limit, $context);
3634

3735
if ($page->isFirstPage !== true && $offset > 0) {
38-
$context->documentLinks['first'] = $this->buildUrl(
39-
['page' => ['offset' => null]],
40-
$context,
41-
);
36+
$context->documentLinks['first'] = $context->currentUrl(['page' => ['offset' => null]]);
4237

4338
$prevOffset = $offset - $limit;
4439

@@ -48,23 +43,21 @@ public function paginate(object $query, Context $context): array
4843
$params = ['page' => ['offset' => max(0, $prevOffset) ?: null]];
4944
}
5045

51-
$context->documentLinks['prev'] = $this->buildUrl($params, $context);
46+
$context->documentLinks['prev'] = $context->currentUrl($params);
5247
}
5348

5449
$total = $context->documentMeta['page']['total'] ?? null;
5550

5651
if ($total !== null && $limit && $offset + $limit < $total) {
57-
$context->documentLinks['last'] = $this->buildUrl(
58-
['page' => ['offset' => floor(($total - 1) / $limit) * $limit ?: null]],
59-
$context,
60-
);
52+
$context->documentLinks['last'] = $context->currentUrl([
53+
'page' => ['offset' => floor(($total - 1) / $limit) * $limit ?: null],
54+
]);
6155
}
6256

6357
if (!$page->isLastPage) {
64-
$context->documentLinks['next'] = $this->buildUrl(
65-
['page' => ['offset' => $offset + $limit]],
66-
$context,
67-
);
58+
$context->documentLinks['next'] = $context->currentUrl([
59+
'page' => ['offset' => $offset + $limit],
60+
]);
6861
}
6962

7063
return $page->results;

0 commit comments

Comments
 (0)