Skip to content

Add PagesInterface::getNbPages()#108

Open
koriym wants to merge 5 commits into
1.xfrom
add-pages-getnbpages
Open

Add PagesInterface::getNbPages()#108
koriym wants to merge 5 commits into
1.xfrom
add-pages-getnbpages

Conversation

@koriym

@koriym koriym commented Jul 4, 2026

Copy link
Copy Markdown
Member

Summary

PagesInterface exposed only the result count via Countable::count(), never the number of pages. Every consumer had to recompute ceil(count / perPage) by hand, duplicating logic that already lives in the underlying Pagerfanta and forcing callers to keep perPage around just for that division.

Changes

  • Add getNbPages(): int to PagesInterface.
  • Implement it in Pages (ceil of count / perPage) and MappedPages (delegation).
  • SqlQuery::getPages() now forwards the perPage it already receives to the Pages constructor, so callers can read the page count directly from the PagesInterface without recomputing it.
  • Update fakes (FakePages, MappedPagesFakePages, FakeEmptyPages) and add testPagerNbPages.

Breaking changes

  • Adds a method to a public interface (PagesInterface::getNbPages).
  • Adds a required constructor argument to the final Pages class (int $perPage).

All in-repo implementers (Pages, MappedPages, and the three test fakes) are updated in this PR.

Verification

  • phpunit: 116 tests, 218 assertions OK
  • phpstan: OK
  • psalm: OK
  • phpcs: blocked by an existing tooling issue on PHP 8.5 (No files were checked); the change mirrors the existing style.

Related

Companion to ray-di/Ray.AuraSqlModule#92, which adds nbPages to the Page value object. Together they let consumers read the page count from either layer without recomputing ceil(count / perPage).

Summary by CodeRabbit

  • New Features
    • Added total page counting via getNbPages, including support for configurable items-per-page.
  • Bug Fixes
    • Page counts now round up correctly and always return a minimum of 1 page, even for empty results.
    • Added validation for items-per-page; invalid values now throw InvalidPerPageException.
  • Tests
    • Expanded coverage for delegation, empty/single/multi-page scenarios, rounding behavior, and items-per-page variations.

PagesInterface exposed only the result count via Countable::count(),
never the number of pages. Every consumer had to recompute
`ceil(count / perPage)` by hand, duplicating logic that already lives
in the underlying Pagerfanta and forcing callers to keep perPage
around just for that division.

Add `getNbPages(): int` to PagesInterface and implement it in Pages
(`ceil` of `count / perPage`) and MappedPages (delegation). SqlQuery
now forwards the perPage it already receives in getPages() to the
Pages constructor, so callers can read the page count directly from
the PagesInterface without recomputing it.

Note: this adds a method to a public interface and a required
constructor argument to the final Pages class.
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@koriym, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 57 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f021088b-1b62-4a32-a5b9-50df4295bb3c

📥 Commits

Reviewing files that changed from the base of the PR and between 37d5dbb and 0ca907c.

📒 Files selected for processing (1)
  • src/Pages.php
📝 Walkthrough

Walkthrough

This PR adds getNbPages(): int across the pages contract and implementations, computes page counts from perPage, passes perPage through query construction, and updates fakes and tests for delegation, validation, and rounding behavior.

Changes

getNbPages Pagination Support

Layer / File(s) Summary
Pagination contract and calculation
src/PagesInterface.php, src/Pages.php, src/Exception/InvalidPerPageException.php
PagesInterface declares getNbPages(): int; Pages validates positive perPage values, memoizes counts, and computes page totals with a minimum of one page.
Query construction and delegation
src/SqlQuery.php, src/MappedPages.php
SqlQuery::getPages() passes perPage into Pages; MappedPages::getNbPages() delegates to its wrapped pages object.
Fakes and pagination validation
tests/Fake/*, tests/MappedPagesTest.php, tests/PagesTest.php, tests/SqlQueryTest.php
Fake implementations satisfy the expanded interface, and tests cover delegation, invalid values, rounding, and empty results.

Estimated code review effort: 2 (Simple) | ~12 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SqlQuery
  participant Pages
  participant MappedPages
  SqlQuery->>Pages: construct with perPage
  MappedPages->>Pages: getNbPages()
  Pages->>Pages: count results and calculate page total
  Pages-->>MappedPages: return page count
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately highlights the main change: adding PagesInterface::getNbPages().
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-pages-getnbpages

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

- MappedPages: test that getNbPages() delegates to the wrapped pages.
- Pages: add perPage=2 cases (exact division and ceil round-up) so
  getNbPages() is covered beyond the perPage=1 smoke test.

119 tests, 221 assertions OK; phpstan and psalm clean.
@koriym
koriym marked this pull request as ready for review July 8, 2026 17:29

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Pages.php`:
- Around line 100-105: The getNbPages method in Pages can divide by zero when
perPage is 0, so add a guard in Pages and its constructor path to prevent
invalid pagination state. Update the Pages constructor to validate or normalize
perPage before it is stored, and make getNbPages return a safe result when
perPage is zero instead of performing the division. Use the existing Pages and
getNbPages symbols to locate the fix, and keep the behavior consistent with how
SqlQuery::getPages() supplies perPage through the pager factory.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eed3fa4c-cb2c-40a0-bcba-0a845ee38e86

📥 Commits

Reviewing files that changed from the base of the PR and between 37e22dd and ca6a484.

📒 Files selected for processing (10)
  • src/MappedPages.php
  • src/Pages.php
  • src/PagesInterface.php
  • src/SqlQuery.php
  • tests/Fake/FakeEmptyPages.php
  • tests/Fake/FakePages.php
  • tests/Fake/MappedPagesFakePages.php
  • tests/MappedPagesTest.php
  • tests/PagesTest.php
  • tests/SqlQueryTest.php

Comment thread src/Pages.php
claude added 3 commits July 9, 2026 04:25
CodeRabbit flagged that Pages::getNbPages() divides by perPage, which
throws DivisionByZeroError if perPage is 0. Pages has a public
constructor and can be instantiated directly, so validate perPage
there instead of relying on callers like SqlQuery::getPages().
- getNbPages() now returns a minimum of 1 for empty result sets,
  matching Pagerfanta's minimumNbPages() so both layers report the
  same page count (the stated goal of pairing this with
  Ray.AuraSqlModule#92).
- Memoize nbResults in Pages so count() and getNbPages() share a
  single COUNT query, as Pagerfanta does. Without this each call
  re-ran the COUNT - or a full fetch for non-rewritable SQL.
- Update FakeEmptyPages, the interface docblock, and add unit and
  integration coverage for both behaviors.
Countable::count() must return int<0, max>. getNbResults() is declared
int<0, max> in Pagerfanta's AdapterInterface, but routing it through
the int|null nbResults property widened it to int. Annotate the
property with the range type to keep the narrowing.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Pages.php`:
- Line 107: Update the memoization expression in Pages::count() so the
ExtendedPdoAdapter::getNbResults() result is clamped to a non-negative integer
before assigning it to nbResults, for example by applying max(0, ...). Preserve
the existing null-coalescing assignment and Countable return behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4c9e8500-f074-44f0-babf-1c79509d440f

📥 Commits

Reviewing files that changed from the base of the PR and between ca9dde9 and 37d5dbb.

📒 Files selected for processing (5)
  • src/Pages.php
  • src/PagesInterface.php
  • tests/Fake/FakeEmptyPages.php
  • tests/PagesTest.php
  • tests/SqlQueryTest.php
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/PagesInterface.php
  • tests/SqlQueryTest.php
  • tests/PagesTest.php

Comment thread src/Pages.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants