Upload
norm2782
View
3.664
Download
0
Embed Size (px)
Citation preview
Advanced Usage of Zend_Paginator
The Dutch PHP BBQ 2009Jurriën Stutterheim
About Me
• ZF user since ZF 0.2
• ZF contributor since 2007
• Author and co-author of Zend_Paginator and Zend_Feed_Reader
This Presentation
• Short Introduction to Zend_Paginator
• Zend_Paginator & Relational Databases
• Zend_Paginator & Domain Models
• Alternative use-cases
“Zend_Paginator is a flexible component for paginating collections of data and presenting that data to users.”- Zend Framework Reference Guide
Short Introduction
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
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(2);// Echoes numbers 21 to 30foreach ($paginator as $item) {
echo $item;}// This assumes the view helper has been setupecho $paginator
Available Adapters
Out of the box Zend_Paginator supports:
• arrays
• Iterators
• Zend_Db_Select
• Zend_Db_Table_Select
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
The Count Query
The COUNT query forSELECT * FROM huge_table
isSELECT 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
Complex QueriesIn case of more complex queries, subqueries are used instead. Original query:SELECT *, MAX(rating) AS highest_rating FROM publicationsWHERE publication_year > 2006GROUP BY category, publication_year, authorHAVING 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)
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);
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);
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.
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
Exampleclass 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}
Alternative Use-cases
• Batch Processing
• Zend_Entity
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
Batch Examplepublic 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); } }}
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
Finished!
foreach ($questions as $question) {
$question->answer();
}
$this->bbq(); // \o/