diff --git a/README.md b/README.md
index 678b480..44f0759 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/src/Cursor/Page.php b/src/Cursor/Page.php
index 16bc169..7d6d418 100644
--- a/src/Cursor/Page.php
+++ b/src/Cursor/Page.php
@@ -131,19 +131,20 @@ public function hasNext(): bool
/**
* Returns the cursor page as the JSON:API meta contents.
*
- *
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.
+ * 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.
*
- * @return array 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 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)];
}
/**
diff --git a/src/Offset/Page.php b/src/Offset/Page.php
index 3b905a1..1955f5f 100644
--- a/src/Offset/Page.php
+++ b/src/Offset/Page.php
@@ -152,16 +152,15 @@ public function hasNext(): bool
/**
* Returns the page as the JSON:API meta contents.
*
- * 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.
+ * 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.
*
- * @return array 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 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(),
@@ -169,6 +168,8 @@ public function metadata(): array
'has_next' => $this->paging->hasNext(),
'has_previous' => $this->paging->hasPrevious()
];
+
+ return [...$pagination, ...array_diff_key($this->extraMetadata, $pagination)];
}
/**
diff --git a/tests/Unit/Cursor/PageTest.php b/tests/Unit/Cursor/PageTest.php
index 677b361..d5e47b6 100644
--- a/tests/Unit/Cursor/PageTest.php
+++ b/tests/Unit/Cursor/PageTest.php
@@ -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
@@ -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());
}
@@ -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',
diff --git a/tests/Unit/Offset/PageTest.php b/tests/Unit/Offset/PageTest.php
index 87e5ff7..55a50db 100644
--- a/tests/Unit/Offset/PageTest.php
+++ b/tests/Unit/Offset/PageTest.php
@@ -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());
}
@@ -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',