Jaime Neto | desenvolvimento para web

dez/12

29

Zend_Paginator retornando objetos


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! 😀

·

No comments yet.

Leave a Reply

<<

>>

Theme Design by devolux.nh2.me