Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: readme #35

Merged
merged 1 commit into from
Apr 4, 2024
Merged
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
90 changes: 54 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
# Rekapager

Rekapager is a pagination library for PHP, supporting both offset-based and
keyset-based pagination.

Full documentation is available at [rekalogika.dev/rekapager](https://rekalogika.dev/rekapager)
keyset-based pagination (also called cursor-based pagination).

## Keyset Pagination
## Keyset Pagination (or Cursor-Based Pagination)

Keyset pagination is a method of pagination that uses the last row of the
current page as an anchor for the next page. This method is more efficient than
offset pagination because it leverages the index, and does not require the
database to scan all rows from the beginning to reach the desired page.
current page as an anchor for the next page. This method has these advantages
compared to the traditional offset-based pagination:

* It is more efficient because it leverages the index. It does not require the
database to scan all rows from the beginning to reach the desired page.
* It is more resilient to data changes. The data will not drift when rows are
inserted or deleted.

### Identifying Pages

Instead of using page numbers, a page identifier object is used to reference a
page. This identifier is encoded into a string and passed as a single query
Expand All @@ -19,16 +21,23 @@ parameter.
Because it requires only a single query parameter, it works similarly on the
surface with offset pagination. Migrating from offset pagination to keyset
pagination will be straightforward. The difference is that instead of having
page numbers in the URL, we'll be getting an 'ugly' string.
page numbers in the URL, we'll be getting an 'ugly' identifier, which is opaque
to the user, but meaningful to the application.

It also easily allows us to keep the pagination job separate from the filtering
and sorting logic. The library does not require a specific way to filter or sort
your data.

### Queries

This library supports queries with multiple sort columns.

The required query for performing keyset pagination is complex, especially if
more than one column is used for sorting. This library handles that task
automatically. The only requirement is that the query needs to have a
deterministic sort order. Queries with multiple sort columns are supported.
deterministic sort order.

### Bidirectional Navigation and Page Skipping

Bidirectional navigation is supported. The user will be able to navigate forward
and backward from the current page. It also supports offset seeking, allowing
Expand All @@ -41,11 +50,15 @@ In the user interface, the pager will look like a regular pagination control:

The page number is informational only, and carried over from the start page.

### Jumping to the Last Page

Seeking to the last page is possible. And with keyset pagination, it will be as
fast as seeking to the first page:

![last page](https://rekalogika.dev/rekapager/last-without-count.png)

### Page Numbers and Counting

Negative page numbers shown above indicate the page numbers from the end. The
last page is -1, the second to last is -2, and so on. It is done this way
because by default the pager does not fetch the total count from the underlying
Expand Down Expand Up @@ -75,13 +88,18 @@ is not allowed to navigate to it:

![page limit](https://rekalogika.dev/rekapager/limit.png)

This feature prevents denials of service, either maliciously or accidentally. In
most cases, a real user won't have a good reason for accessing page 56267264,
but doing so can cause a denial of service to the web server, application, and
the database.
### Secure by Default

By not counting by default, and limiting pages in offset pagination, the library
is secure by default. It prevents denials of service, either maliciously or
accidentally. In most cases, a real user won't have a good reason for accessing
page 56267264, but doing so can cause a denial of service to the web server,
application, and the database.

For interoperability, the library supports using any of the existing Pagerfanta
adapters, as well as adapting a Pagerfanta instance into an
### Pagerfanta Interoperability

For interoperability, the library supports offset pagination using any of the
existing Pagerfanta adapters, as well as adapting a Pagerfanta instance into an
`OffsetPageableInterface` instance.

## Supported Underlying Data Types
Expand All @@ -107,8 +125,8 @@ use Rekalogika\Rekapager\Keyset\KeysetPageable;
/** @var EntityRepository $postRepository */
$queryBuilder = $postRepository
->createQueryBuilder('p')
->where('p.setName = :setName')
->setParameter('setName', $setName)
->where('p.group = :group')
->setParameter('group', $group)
->addOrderBy('p.date', 'DESC')
->addOrderBy('p.title', 'ASC')
->addOrderBy('p.id', 'ASC');
Expand Down Expand Up @@ -175,28 +193,32 @@ integration provided by `rekalogika/rekapager-bundle`.
{# Outputs the item from the current page #}

<table class="table">
<tr>
<th>ID</th>
<th>Title</th>
<th>Date</th>
<th>Content</th>
</tr>
{% for post in pager.currentPage %}
<thead>
<tr>
<td>{{ post.id }}</td>
<td>{{ post.title }}</td>
<td>{{ post.date|date('Y-m-d') }}</td>
<td>{{ post.content }}</td>
<th>ID</th>
<th>Title</th>
<th>Date</th>
<th>Content</th>
</tr>
{% endfor %}
</thead>
<tbody {{ rekapager_infinite_scrolling_content() }}>
{% for post in pager.currentPage %}
<tr>
<td>{{ post.id }}</td>
<td>{{ post.title }}</td>
<td>{{ post.date|date('Y-m-d') }}</td>
<td>{{ post.content }}</td>
</tr>
{% endfor %}
</tbody>
</table>

{# Render the pager #}

{{ rekapager(pager) }}
```

### Batch Processing
## Batch Processing

A `PageableInterface` object can also be used for batch processing a large
amount of underlying data. The example below demonstrates how to do batch
Expand Down Expand Up @@ -237,10 +259,6 @@ Then access the demo at [http://localhost:8187](http://localhost:8187).
* [PagerWave](https://gitlab.com/pagerwave/PagerWave)
* [fast-doctrine-paginator](https://github.com/mentionapp/fast-doctrine-paginator)

## Documentation

[rekalogika.dev/rekapager](https://rekalogika.dev/rekapager)

## License

MIT
Expand Down
Loading