Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -533,15 +533,15 @@ $response = $keyset->page(items: $items)
```json
{
"meta": {
"unread_count": 7,
"per_page": 20,
"has_next": true
"has_next": true,
"unread_count": 7
}
}
```

The supplied entries come first, in the order they were given, and the pagination entries come last. A supplied key that
repeats a pagination key never shadows it, so `withMetadata(metadata: ['per_page' => 99])` leaves `per_page` on the real
The pagination entries come first, and the supplied ones follow in the order they were given. A supplied key that
repeats a pagination key is discarded, so `withMetadata(metadata: ['per_page' => 99])` leaves `per_page` on the real
page size. Calling it more than once accumulates.

## FAQ
Expand Down
13 changes: 7 additions & 6 deletions src/Cursor/Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,20 @@ public function hasNext(): bool
/**
* Returns the cursor page as the JSON:API meta contents.
*
* <p>Any metadata supplied through withMetadata comes first, in the order it was given. The
* pagination contents come last, so a supplied key never shadows them.</p>
* <p>The pagination contents come first. Any metadata supplied through withMetadata follows,
* in the order it was given, and a supplied key that repeats a pagination one is discarded.</p>
*
* @return array<string, mixed> The meta contents, the supplied metadata first, then the
* pagination counts and sizes, then the boolean flags, each by ascending key-name length.
* @return array<string, mixed> The meta contents, the pagination counts and sizes first, then
* the boolean flags, each by ascending key-name length, then the supplied metadata.
*/
public function metadata(): array
{
return [
...$this->extraMetadata,
$pagination = [
'per_page' => $this->pagination->limit(),
'has_next' => $this->hasNext
];

return [...$pagination, ...array_diff_key($this->extraMetadata, $pagination)];
}

/**
Expand Down
13 changes: 7 additions & 6 deletions src/Offset/Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,23 +152,24 @@ public function hasNext(): bool
/**
* Returns the page as the JSON:API meta contents.
*
* <p>Any metadata supplied through withMetadata comes first, in the order it was given. The
* pagination contents come last, so a supplied key never shadows them.</p>
* <p>The pagination contents come first. Any metadata supplied through withMetadata follows,
* in the order it was given, and a supplied key that repeats a pagination one is discarded.</p>
*
* @return array<string, mixed> The meta contents, the supplied metadata first, then the
* pagination counts and sizes, then the boolean flags, each by ascending key-name length.
* @return array<string, mixed> The meta contents, the pagination counts and sizes first, then
* the boolean flags, each by ascending key-name length, then the supplied metadata.
*/
public function metadata(): array
{
return [
...$this->extraMetadata,
$pagination = [
'total' => $this->total->value(),
'per_page' => $this->paging->limit(),
'total_pages' => $this->pageCount->value(),
'current_page' => $this->paging->currentPage(),
'has_next' => $this->paging->hasNext(),
'has_previous' => $this->paging->hasPrevious()
];

return [...$pagination, ...array_diff_key($this->extraMetadata, $pagination)];
}

/**
Expand Down
18 changes: 9 additions & 9 deletions tests/Unit/Cursor/PageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ public function testMapWhenPageCarriesMetadataThenTheCopyKeepsIt(): void
/** @When the items are projected through a transformation */
$mapped = $page->map(transformation: static fn(int $element): int => ($element * 2));

/** @Then the copy keeps the supplied metadata ahead of the pagination contents */
self::assertSame(['unread_count' => 7, 'per_page' => 2, 'has_next' => false], $mapped->metadata());
/** @Then the copy keeps the supplied metadata after the pagination contents */
self::assertSame(['per_page' => 2, 'has_next' => false, 'unread_count' => 7], $mapped->metadata());
}

public function testNavigationWhenNoExtraElementThenHasNoNextPage(): void
Expand Down Expand Up @@ -85,12 +85,12 @@ public function testWithMetadataWhenAppliedTwiceThenBothEntriesAreKept(): void
/** @When metadata is supplied twice */
$counted = $page->withMetadata(metadata: ['unread_count' => 7])->withMetadata(metadata: ['muted_count' => 3]);

/** @Then both entries reach the meta contents, in the order they were supplied */
/** @Then both entries follow the pagination contents, in the order they were supplied */
self::assertSame([
'unread_count' => 7,
'muted_count' => 3,
'per_page' => 2,
'has_next' => false
'has_next' => false,
'unread_count' => 7,
'muted_count' => 3
], $counted->metadata());
}

Expand Down Expand Up @@ -218,13 +218,13 @@ public function testWithMetadataWhenRenderedThenMetaCarriesItAndTheLinkHeaderHol
/** @When rendering the cursor page as a JSON:API response over the notifications base URI */
$response = $page->toResponse(baseUri: '/v1/notifications');

/** @Then the supplied counter renders inside meta, ahead of the pagination contents */
/** @Then the supplied counter renders inside meta, after the pagination contents */
self::assertSame([
'data' => [10, 20],
'meta' => [
'unread_count' => 7,
'per_page' => 2,
'has_next' => true
'has_next' => true,
'unread_count' => 7
],
'links' => [
'self' => '/v1/notifications?page[size]=2',
Expand Down
14 changes: 7 additions & 7 deletions tests/Unit/Offset/PageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,16 @@ public function testWithMetadataWhenAppliedTwiceThenBothEntriesAreKept(): void
/** @When metadata is supplied twice */
$counted = $page->withMetadata(metadata: ['unread_count' => 7])->withMetadata(metadata: ['muted_count' => 3]);

/** @Then both entries reach the meta contents, in the order they were supplied */
/** @Then both entries follow the pagination contents, in the order they were supplied */
self::assertSame([
'unread_count' => 7,
'muted_count' => 3,
'total' => 2,
'per_page' => 20,
'total_pages' => 1,
'current_page' => 1,
'has_next' => false,
'has_previous' => false
'has_previous' => false,
'unread_count' => 7,
'muted_count' => 3
], $counted->metadata());
}

Expand Down Expand Up @@ -335,17 +335,17 @@ public function testWithMetadataWhenRenderedThenMetaCarriesItAndTheLinkHeaderHol
/** @When rendering the page as a JSON:API response over the notifications base URI */
$response = $page->toResponse(baseUri: '/v1/notifications');

/** @Then the supplied counter renders inside meta, ahead of the pagination contents */
/** @Then the supplied counter renders inside meta, after the pagination contents */
self::assertSame([
'data' => ['a', 'b'],
'meta' => [
'unread_count' => 7,
'total' => 2,
'per_page' => 20,
'total_pages' => 1,
'current_page' => 1,
'has_next' => false,
'has_previous' => false
'has_previous' => false,
'unread_count' => 7
],
'links' => [
'self' => '/v1/notifications?page[number]=1&page[size]=20',
Expand Down