Imagine a seguinte situação: você precisa fazer uma consulta numa tabela que tem muitos registros e, portanto, precisa fazer paginação do resultado. Ok até aí, é só criar um Zend_Db_Select
e usar ele como parâmetro para um Zend_Paginator
. Porém, na hora de iterar sobre o getItems()
do paginator, você estará trabalhando com um array
em vez de trabalhar com um objeto da sua classe modelo. O que fazer? Bom… você pode pegar todos os resultados, jogar num foreach
e converter no objeto em questão, correto? Mas pra todo objeto vai ter que fazer isso de forma repetida… E agora?
Eis minha sugestão: Vamos criar um novo adapter para Zend_Paginator
que é uma variação do Zend_Paginator_Adapter_DbSelect
. A diferença é que esse adapter recebe um parâmetro adicional no construtor com o nome da classe modelo que você deseja como retorno na paginação.
class My_Paginator extends Zend_Paginator_Adapter_DbSelect { protected $_modelClass; public function __construct(Zend_Db_Select $select, $className) { if (!class_exists($className)) { throw new Exception("Class '{$className}' not exists"); } else if(!is_subclass_of($className, 'My_Model_Abstract')) { throw new Exception("Class '{$className}' is not subclass " . "of My_Model_Abstract"); } $this->_modelClass = $className; parent::__construct($select); } public function getModelClass() { return $this->_modelClass; } public function getItems($offset, $itemCountPerPage) { $results = parent::getItems($offset, $itemCountPerPage); // É aqui que a mágica acontece. Você pega o resultado padrão do // paginator, e converte para objetos da classe definida no // construtor $items = array(); if ($results) { $modelClass = $this->getModelClass(); foreach ($results as $data) { $item = new $modelClass(); $item->setData($data); $items[$item->getId()] = $item; } } return $items; } } |
Perceba na classe acima, que, para ela funcionar de uma forma genérica, é preciso que a classe definida seja subclasse de My_Model_Abstract
, que poderia ser a base para suas classes modelo. No método getItems()
você pode perceber que essa classe deve implementar pelo menos dois métodos: setData()
e getId()
. Vamos ao código da My_Model_Abstract
, então:
abstract class My_Model_Abstract { protected $_id; public function getId() { return $this->_id; } public function setData(array $data) { foreach($data as $name => $value) { if (property_exists($this, $name)) { $this->$name = $value; } } return $this; } } |
Pronto, agora é só criar suas classes modelo herdando desta que ela deve funcionar com o nosso paginator. Lembrando que essa classe é só uma sugestão, você pode (e deve) alterá-la e melhorá-la para atender suas necessidades. Vamos à utilização agora do paginator:
// Vamos considerar que temos uma classe My_Model_Post que herda de // My_Model_Abstract e que $select é uma instância de Zend_Db_Select $adapter = new My_Paginator($select, 'My_Model_Post'); // Criado o adapter, agora é só passá-lo como parâmetro para o paginator, // e usá-lo normalmente $paginator = new Zend_Paginator($adapter); $paginator->setCurrentPageNumber($this->_getParam('page', 1)); $paginator->setItemCountPerPage(25); $this->view->paginator = $paginator; |
Agora ficou fácil de utilizar o paginator e ainda aproveitar as vantagens de suas classes modelo. Você ainda pode melhorar esse código criando, na classe My_Model_Abstract
(ou na sua classe Db_Table
, caso costume separar as classes modelo das classes de acesso ao banco de dados) um método para retornar o paginator, sem precisar declará-lo no controller
. Enjoy! 😀