File tree Expand file tree Collapse file tree 7 files changed +44
-7
lines changed Expand file tree Collapse file tree 7 files changed +44
-7
lines changed Original file line number Diff line number Diff line change @@ -47,6 +47,9 @@ class Context
4747 // Links to be returned in the document's links object
4848 public ArrayObject $documentLinks;
4949
50+ // Active JSON:API profile URIs for the current response
51+ public ArrayObject $activeProfiles;
52+
5053 // Get the request method
5154 public function method(): string;
5255
@@ -79,5 +82,8 @@ class Context
7982
8083 // Determine whether a sort field has been requested
8184 public function sortRequested(string $field): bool;
85+
86+ // Activate a JSON:API profile for the current response
87+ public function activateProfile(string $uri): static;
8288}
8389```
Original file line number Diff line number Diff line change @@ -24,6 +24,7 @@ class Context
2424 public ?array $ include = null ;
2525 public ArrayObject $ documentMeta ;
2626 public ArrayObject $ documentLinks ;
27+ public ArrayObject $ activeProfiles ;
2728 public WeakMap $ resourceMeta ;
2829
2930 private ?array $ body ;
@@ -45,6 +46,7 @@ public function __construct(public JsonApi $api, public ServerRequestInterface $
4546
4647 $ this ->documentMeta = new ArrayObject ();
4748 $ this ->documentLinks = new ArrayObject ();
49+ $ this ->activeProfiles = new ArrayObject ();
4850
4951 $ this ->resourceMeta = new WeakMap ();
5052 }
@@ -289,6 +291,13 @@ public function resourceMeta($model, array $meta): static
289291 return $ this ;
290292 }
291293
294+ public function activateProfile (string $ uri ): static
295+ {
296+ $ this ->activeProfiles [$ uri ] = true ;
297+
298+ return $ this ;
299+ }
300+
292301 public function forModel (array $ collections , ?object $ model ): static
293302 {
294303 $ new = clone $ this ;
Original file line number Diff line number Diff line change 33namespace Tobyz \JsonApiServer \Exception \Pagination ;
44
55use Tobyz \JsonApiServer \Exception \BadRequestException ;
6+ use Tobyz \JsonApiServer \Pagination \CursorPagination ;
67
78class MaxPageSizeExceededException extends BadRequestException
89{
@@ -11,9 +12,7 @@ public function __construct(private readonly int $maxSize)
1112 parent ::__construct ('Page size requested is too large ' );
1213
1314 $ this ->meta (['page ' => ['maxSize ' => $ this ->maxSize ]])->links ([
14- 'type ' => [
15- 'https://jsonapi.org/profiles/ethanresnick/cursor-pagination/max-size-exceeded ' ,
16- ],
15+ 'type ' => [CursorPagination::PROFILE_URI . '/max-size-exceeded ' ],
1716 ]);
1817 }
1918}
Original file line number Diff line number Diff line change 33namespace Tobyz \JsonApiServer \Exception \Pagination ;
44
55use Tobyz \JsonApiServer \Exception \BadRequestException ;
6+ use Tobyz \JsonApiServer \Pagination \CursorPagination ;
67
78class RangePaginationNotSupportedException extends BadRequestException
89{
@@ -11,9 +12,7 @@ public function __construct()
1112 parent ::__construct ('Range pagination is not supported ' );
1213
1314 $ this ->links ([
14- 'type ' => [
15- 'https://jsonapi.org/profiles/ethanresnick/cursor-pagination/range-pagination-not-supported ' ,
16- ],
15+ 'type ' => [CursorPagination::PROFILE_URI . '/range-pagination-not-supported ' ],
1716 ]);
1817 }
1918}
Original file line number Diff line number Diff line change @@ -166,6 +166,16 @@ public function handle(Request $request): Response
166166 throw $ e ?? new NotFoundException ();
167167 }
168168
169+ if (count ($ context ->activeProfiles )) {
170+ $ contentType = $ response ->getHeaderLine ('Content-Type ' );
171+
172+ if (str_starts_with ($ contentType , self ::MEDIA_TYPE )) {
173+ $ profileUris = array_keys (array_filter ($ context ->activeProfiles ->getArrayCopy ()));
174+ $ contentType .= '; profile=" ' . implode (' ' , $ profileUris ) . '" ' ;
175+ $ response = $ response ->withHeader ('Content-Type ' , $ contentType );
176+ }
177+ }
178+
169179 return $ response ->withAddedHeader ('Vary ' , 'Accept ' );
170180 }
171181
Original file line number Diff line number Diff line change @@ -13,6 +13,8 @@ class CursorPagination implements Pagination
1313{
1414 use HasSizeParameter;
1515
16+ public const PROFILE_URI = 'https://jsonapi.org/profiles/ethanresnick/cursor-pagination ' ;
17+
1618 public readonly int $ size ;
1719 public readonly ?string $ after ;
1820 public readonly ?string $ before ;
@@ -24,6 +26,8 @@ public function __construct(int $defaultSize = 20, ?int $maxSize = 50)
2426
2527 public function paginate (object $ query , Context $ context ): array
2628 {
29+ $ context ->activateProfile (self ::PROFILE_URI );
30+
2731 $ size = $ this ->getSize ($ context , 'size ' );
2832 $ after = $ this ->getCursor ($ context , 'after ' );
2933 $ before = $ this ->getCursor ($ context , 'before ' );
Original file line number Diff line number Diff line change 44
55use Tobyz \JsonApiServer \Endpoint \Index ;
66use Tobyz \JsonApiServer \Exception \BadRequestException ;
7- use Tobyz \JsonApiServer \JsonApi ;
87use Tobyz \JsonApiServer \Exception \Pagination \MaxPageSizeExceededException ;
98use Tobyz \JsonApiServer \Exception \Pagination \RangePaginationNotSupportedException ;
9+ use Tobyz \JsonApiServer \JsonApi ;
1010use Tobyz \Tests \JsonApiServer \AbstractTestCase ;
1111use Tobyz \Tests \JsonApiServer \MockResource ;
1212
@@ -27,6 +27,16 @@ public function setUp(): void
2727 );
2828 }
2929
30+ public function test_includes_profile_in_content_type (): void
31+ {
32+ $ response = $ this ->api ->handle ($ this ->buildRequest ('GET ' , '/articles ' ));
33+
34+ $ this ->assertEquals (
35+ 'application/vnd.api+json; profile="https://jsonapi.org/profiles/ethanresnick/cursor-pagination" ' ,
36+ $ response ->getHeaderLine ('Content-Type ' ),
37+ );
38+ }
39+
3040 public function test_first_page_includes_expected_links_and_item_cursors (): void
3141 {
3242 $ response = $ this ->api ->handle ($ this ->buildRequest ('GET ' , '/articles ' ));
You can’t perform that action at this time.
0 commit comments