This document summarizes Jurriën Stutterheim's presentation on advanced usage of Zend_Paginator. It introduces Zend_Paginator and describes how it can paginate arrays, iterators, database queries, and domain models. It provides examples of using Zend_Paginator with databases by executing count queries and fetching only the needed rows. It also discusses using filters to construct domain objects and how Zend_Paginator supports batch processing and Zend_Entity.
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Advanced Usage of Zend_Paginator
1. Advanced Usage of
Zend_Paginator
The Dutch PHP BBQ 2009
Jurriën Stutterheim
2. About Me
• ZF user since ZF 0.2
• ZF contributor since 2007
• Author and co-author of Zend_Paginator
and Zend_Feed_Reader
3. This Presentation
• Short Introduction to Zend_Paginator
• Zend_Paginator & Relational Databases
• Zend_Paginator & Domain Models
• Alternative use-cases
4. Short Introduction
“Zend_Paginator is a flexible
component for paginating
collections of data and
presenting that data to users.”
- Zend Framework Reference Guide
5. Primary Design Goals
• Paginate arbitrary data, not just relational databases
• Fetch only the results that need to be displayed
• Do not force users to adhere to only one way of
displaying data or rendering pagination controls
• Loosely couple Zend_Paginator to other Zend
Framework components so that users who wish to
use it independently of Zend_View, Zend_Db, etc.
can do so
- Zend Framework Reference Guide
6. Simple Example
// Create a Paginator that will paginate an
// array with the values 1 to 100
$paginator = new Zend_Paginator(
new Zend_Paginator_Adapter_Array(range(1, 100))
);
$paginator->setItemCountPerPage(10);
$paginator->setCurrentPageNumber(3);
// Echoes numbers 21 to 30
foreach ($paginator as $item) {
echo $item;
}
// This assumes the view helper has been setup
echo $paginator
7. Available Adapters
Out of the box Zend_Paginator supports:
• arrays
• Iterators
• Zend_Db_Select
• Zend_Db_Table_Select
8. Paginator & Database
• The total number of items is needed to
calculate the number of pages
• A count-query is executed to determine
the total number of items the original
query would retrieve
• Paginator only fetches the rows for the
current page
9. The Count Query
The COUNT query for
SELECT * FROM huge_table
is
SELECT COUNT(1) AS
zend_paginator_row_count FROM huge_table
In order to fetch the rows for the current
page:
SELECT * FROM huge_table LIMIT 20, 10
10. Complex Queries
In case of more complex queries, subqueries
are used instead. Original query:
SELECT *, MAX(rating) AS highest_rating FROM publications
WHERE publication_year > 2006
GROUP BY category, publication_year, author
HAVING highest_rating > 3
Count query:
SELECT COUNT(1) AS zend_paginator_row_count FROM (
SELECT *, MAX(rating) AS highest_rating FROM publications
WHERE publication_year > 2006
GROUP BY category, publication_year, author
HAVING highest_rating > 3
)
11. Custom Queries
It’s also possible to use a custom COUNT
query:
// $select contains the query from the last example
$adapter = new Zend_Paginator_Adapter_DbTableSelect($select);
$adapter->setRowCount(
$db->select()->from('publication_counts', array(
Zend_Paginator_Adapter_DbSelect::ROW_COUNT_COLUMN =>
'highest_rating_count'
))
);
$paginator = new Zend_Paginator($adapter);
12. Fixed Page Count
You can specify a fixed page count. No COUNT
query is executed in this case:
// This table has tens of thousands of records
$table = new Zend_Db_Table('publications');
$select = $table->select()->order('rating DESC');
$adapter = new Zend_Paginator_Adapter_DbTableSelect($select);
$adapter->setRowCount(500);
$paginator = new Zend_Paginator($adapter);
13. Paginator & Domain
Models
• When using a domain model you don’t
want to pass database rows to your view,
but rather use them to construct domain
objects.
• You do however wish to keep the Paginator
features at your disposal.
• Zend_Paginator supports this using filters.
14. Filters
• Filter the result from the adapter
• Need to implement Zend_Filter_Interface
• Can be chained if required
• Zend_Filter_Callback allows you to easily
reuse existing models to construct domain
objects
15. Example
class MyObject {
// Snip...
public static function factory($rows) {
$objects = array();
foreach ($rows as $row) {
$objects[] = new MyObject($row);
}
return $objects;
}
public function getFoo() {
return 'foo';
}
}
// $select is a Zend_Db_Table_Select object
$paginator = new Zend_Paginator(
new Zend_Paginator_Adapter_DbTableSelect($select)
);
$paginator->setFilter(new Zend_Filter_Callback(
array('MyObject', 'factory'))
);
foreach ($paginator as $item) {
echo $item->getFoo(); // echoes foo
}
17. Batch Processing
• For example, rebuilding a
Zend_Search_Lucene search index using a
large amount data from a database
• Each page contains a relatively large
number of items
• Main advantage is limited memory usage
because not all rows are loaded into
memory at once
18. Batch Example
public function rebuild()
{
$paginator = new Zend_Paginator(
new Zend_Paginator_Adapter_DbTableSelect($this->getSelect())
);
$paginator->setCacheEnabled(false);
// Batch size is 500 records per page/batch
$paginator->setItemCountPerPage(500);
$searchIndex = $this->getSearchIndex();
for ($i = 1; $i <= $paginator->count(); $i++) {
$items = $paginator->getItemsByPage($i);
foreach ($items as $item) {
$searchIndex->addPublication($item);
}
}
}
19. Zend_Entity
• Is a data mapper implementation for ZF
• Currently under heavy development
• Uses Zend_Paginator_AdapterAggregate
• Is used to load subsets of data from the
datasource to improve performance and
memory consumption