TigerZF
🌐Español

54.2. Uso

54.2.1. Paginación de colecciones de datos

Para paginar elementos en páginas, Zend_Paginator debe disponer de una forma genérica de acceder a esos datos. Por esa razón, todo el acceso a los datos se realiza a través de adaptadores de origen de datos. Varios adaptadores se incluyen con Zend Framework por defecto:

Tabla 54.1. Adaptadores para Zend_Paginator

Adaptador Descripción
Array Usar un array de PHP
DbSelect Usar una instancia de Zend_Db_Select, que devolverá un array
DbTableSelect Usar una instancia de Zend_Db_Table_Select, que devolverá una instancia de Zend_Db_Table_Rowset_Abstract. Esto proporciona información adicional sobre el conjunto de resultados, como los nombres de columnas.
Iterator Usar una instancia de Iterator
Null No usar Zend_Paginator para gestionar la paginación de datos. Aun así, puede aprovechar la funcionalidad de control de paginación.

[Note] Nota

En lugar de seleccionar todas las filas coincidentes de una consulta dada, los adaptadores DbSelect y DbTableSelect recuperan únicamente la cantidad mínima de datos necesaria para mostrar la página actual.

Debido a esto, se genera dinámicamente una segunda consulta para determinar el número total de filas coincidentes. Sin embargo, es posible proporcionar directamente un conteo o una consulta de conteo usted mismo. Consulte el método setRowCount() del adaptador DbSelect para obtener más información.

Para crear una instancia de Zend_Paginator, debe proporcionar un adaptador al constructor:

$paginator = new Zend_Paginator(new Zend_Paginator_Adapter_Array($array));

Por conveniencia, puede aprovechar el método estático factory() para los adaptadores incluidos con Zend Framework:

$paginator = Zend_Paginator::factory($array);
[Note] Nota

En el caso del adaptador Null, en lugar de una colección de datos debe proporcionar un conteo de elementos a su constructor.

Aunque la instancia es técnicamente utilizable en este estado, en su acción de controlador deberá indicar al paginador qué número de página solicitó el usuario. Esto le permite avanzar a través de los datos paginados.

$paginator->setCurrentPageNumber($page);

La forma más sencilla de llevar el control de este valor es a través de una URL. Aunque recomendamos usar un enrutador compatible con Zend_Controller_Router_Interface para gestionar esto, no es un requisito.

A continuación se muestra un ejemplo de ruta que podría usar en un archivo de configuración INI:

routes.example.route = articles/:articleName/:page
routes.example.defaults.controller = articles
routes.example.defaults.action = view
routes.example.defaults.page = 1
routes.example.reqs.articleName = \w+
routes.example.reqs.page = \d+

Con la ruta anterior (y usando los componentes MVC de Zend Framework), podría establecer el número de página actual de esta manera:

$paginator->setCurrentPageNumber($this->_getParam('page'));

Hay otras opciones disponibles; consulte Configuración para más información sobre ellas.

Finalmente, deberá asignar la instancia del paginador a su vista. Si está usando Zend_View con el helper de acción ViewRenderer, lo siguiente funcionará:

$this->view->paginator = $paginator;

54.2.2. El adaptador DbSelect y DbTableSelect

El uso de la mayoría de adaptadores es bastante sencillo. Sin embargo, los adaptadores de base de datos requieren una explicación más detallada respecto a la recuperación y el conteo de los datos desde la base de datos.

Para usar los adaptadores DbSelect y DbTableSelect no es necesario recuperar los datos de antemano desde la base de datos. Ambos adaptadores realizan la recuperación por usted, así como el conteo del total de páginas. Si es necesario realizar trabajo adicional sobre los resultados de la base de datos, el método getItems() del adaptador debe extenderse en su aplicación.

Además, estos adaptadores no obtienen todos los registros de la base de datos para contarlos. En su lugar, los adaptadores manipulan la consulta original para producir la consulta COUNT correspondiente. Paginator ejecuta entonces esa consulta COUNT para obtener el número de filas. Esto requiere un viaje adicional a la base de datos, pero muchas veces es más rápido que obtener un conjunto de resultados completo y usar count(). Especialmente con grandes colecciones de datos.

Los adaptadores de base de datos intentarán construir la consulta más eficiente que se ejecute en prácticamente todas las bases de datos modernas. Sin embargo, dependiendo de su base de datos o incluso de su propia configuración de esquema, puede haber formas más eficientes de obtener un conteo de filas. Para este escenario, los adaptadores de base de datos le permiten establecer una consulta COUNT personalizada. Por ejemplo, si lleva el conteo de publicaciones de blog en una tabla separada, podría lograr una consulta de conteo más rápida con la siguiente configuración:

$adapter = new Zend_Paginator_Adapter_DbSelect($db->select()->from('posts'));
$adapter->setRowCount(
    $db->select()
       ->from(
            'item_counts',
            array(
               Zend_Paginator_Adapter_DbSelect::ROW_COUNT_COLUMN => 'post_count'
            )
         )
);

$paginator = new Zend_Paginator($adapter);

Este enfoque probablemente no le proporcione una gran mejora de rendimiento en colecciones pequeñas y/o consultas select simples. Sin embargo, con consultas complejas y grandes colecciones, un enfoque similar podría proporcionarle un aumento de rendimiento significativo.

54.2.3. Renderización de páginas con scripts de vista

El script de vista se usa para renderizar los elementos de la página (si está usando Zend_Paginator para hacerlo) y mostrar el control de paginación.

Dado que Zend_Paginator implementa la interfaz SPL IteratorAggregate, recorrer sus elementos y mostrarlos es sencillo.

<html>
<body>
<h1>Example</h1>
<?php if (count($this->paginator)): ?>
<ul>
<?php foreach ($this->paginator as $item): ?>
  <li><?php echo $item; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>

<?php echo $this->paginationControl($this->paginator,
                                    'Sliding',
                                    'my_pagination_control.phtml'); ?>
</body>
</html>

Observe la llamada al helper de vista cerca del final. PaginationControl acepta hasta cuatro parámetros: la instancia del paginador, un estilo de desplazamiento, un partial de vista, y un array de parámetros adicionales.

El segundo y tercer parámetro son muy importantes. Mientras que el partial de vista se usa para determinar cómo debe verse el control de paginación, el estilo de desplazamiento se usa para controlar cómo debe comportarse. Suponga que el partial de vista está en el estilo de un control de paginación de búsqueda, como el siguiente:

¿Qué sucede cuando el usuario hace clic en el enlace "siguiente" varias veces? Bueno, podría suceder cualquier cantidad de cosas. El número de página actual podría permanecer en el centro mientras hace clic (como sucede en Yahoo!), o podría avanzar hasta el final del rango de páginas y luego volver a aparecer a la izquierda cuando el usuario haga clic en "siguiente" una vez más. Los números de página incluso podrían expandirse y contraerse mientras el usuario avanza (o "se desplaza") a través de ellos (como en Google).

Hay cuatro estilos de desplazamiento incluidos con Zend Framework:

Tabla 54.2. Estilos de desplazamiento para Zend_Paginator

Estilo de desplazamiento Descripción
All Devuelve todas las páginas. Esto es útil para controles de paginación de menú desplegable con relativamente pocas páginas. En estos casos, se desea tener todas las páginas disponibles para el usuario a la vez.
Elastic Un estilo de desplazamiento al estilo de Google que se expande y se contrae mientras el usuario se desplaza por las páginas.
Jumping A medida que los usuarios se desplazan, el número de página avanza hasta el final de un rango dado, y luego comienza de nuevo al principio del nuevo rango.
Sliding Un estilo de desplazamiento al estilo de Yahoo! que posiciona el número de página actual en el centro del rango de páginas, o lo más cerca posible. Este es el estilo predeterminado.

El cuarto y último parámetro está reservado para un array asociativo opcional de variables adicionales que desee tener disponibles en su partial de vista (disponible mediante $this). Por ejemplo, estos valores podrían incluir parámetros de URL adicionales para los enlaces de paginación.

Estableciendo el partial de vista predeterminado, el estilo de desplazamiento predeterminado, y la instancia de vista, puede eliminar por completo las llamadas a PaginationControl:

Zend_Paginator::setDefaultScrollingStyle('Sliding');
Zend_View_Helper_PaginationControl::setDefaultViewPartial(
    'my_pagination_control.phtml'
);
$paginator->setView($view);

Cuando todos estos valores están establecidos, puede renderizar el control de paginación dentro de su script de vista con una simple sentencia echo:

<?php echo $this->paginator; ?>
[Note] Nota

Por supuesto, es posible usar Zend_Paginator con otros motores de plantillas. Por ejemplo, con Smarty podría hacer lo siguiente:

$smarty->assign('pages', $paginator->getPages());

Podría entonces acceder a los valores del paginador desde una plantilla de esta manera:

{$pages->pageCount}

54.2.3.1. Ejemplos de controles de paginación

Los siguientes ejemplos de controles de paginación esperamos que le ayuden a comenzar:

Paginación de búsqueda:

<!--
See http://developer.yahoo.com/ypatterns/pattern.php?pattern=searchpagination
-->

<?php if ($this->pageCount): ?>
<div class="paginationControl">
<!-- Previous page link -->
<?php if (isset($this->previous)): ?>
  <a href="<?php echo $this->url(array('page' => $this->previous)); ?>">
    &lt; Previous
  </a> |
<?php else: ?>
  <span class="disabled">&lt; Previous</span> |
<?php endif; ?>

<!-- Numbered page links -->
<?php foreach ($this->pagesInRange as $page): ?>
  <?php if ($page != $this->current): ?>
    <a href="<?php echo $this->url(array('page' => $page)); ?>">
        <?php echo $page; ?>
    </a> |
  <?php else: ?>
    <?php echo $page; ?> |
  <?php endif; ?>
<?php endforeach; ?>

<!-- Next page link -->
<?php if (isset($this->next)): ?>
  <a href="<?php echo $this->url(array('page' => $this->next)); ?>">
    Next &gt;
  </a>
<?php else: ?>
  <span class="disabled">Next &gt;</span>
<?php endif; ?>
</div>
<?php endif; ?>

Paginación de elementos:

<!--
See http://developer.yahoo.com/ypatterns/pattern.php?pattern=itempagination
-->

<?php if ($this->pageCount): ?>
<div class="paginationControl">
<?php echo $this->firstItemNumber; ?> - <?php echo $this->lastItemNumber; ?>
of <?php echo $this->totalItemCount; ?>

<!-- First page link -->
<?php if (isset($this->previous)): ?>
  <a href="<?php echo $this->url(array('page' => $this->first)); ?>">
    First
  </a> |
<?php else: ?>
  <span class="disabled">First</span> |
<?php endif; ?>

<!-- Previous page link -->
<?php if (isset($this->previous)): ?>
  <a href="<?php echo $this->url(array('page' => $this->previous)); ?>">
    &lt; Previous
  </a> |
<?php else: ?>
  <span class="disabled">&lt; Previous</span> |
<?php endif; ?>

<!-- Next page link -->
<?php if (isset($this->next)): ?>
  <a href="<?php echo $this->url(array('page' => $this->next)); ?>">
    Next &gt;
  </a> |
<?php else: ?>
  <span class="disabled">Next &gt;</span> |
<?php endif; ?>

<!-- Last page link -->
<?php if (isset($this->next)): ?>
  <a href="<?php echo $this->url(array('page' => $this->last)); ?>">
    Last
  </a>
<?php else: ?>
  <span class="disabled">Last</span>
<?php endif; ?>

</div>
<?php endif; ?>

Paginación desplegable:

<?php if ($this->pageCount): ?>
<select id="paginationControl" size="1">
<?php foreach ($this->pagesInRange as $page): ?>
  <?php $selected = ($page == $this->current) ? ' selected="selected"' : ''; ?>
  <option value="<?php
        echo $this->url(array('page' => $page));?>"<?php echo $selected ?>>
    <?php echo $page; ?>
  </option>
<?php endforeach; ?>
</select>
<?php endif; ?>

<script type="text/javascript"
     src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.2/prototype.js">
</script>
<script type="text/javascript">
$('paginationControl').observe('change', function() {
    window.location = this.options[this.selectedIndex].value;
})
</script>

54.2.3.2. Listado de propiedades

Las siguientes opciones están disponibles para los partials de vista de control de paginación:

Tabla 54.3. Propiedades disponibles para los partials de vista

Propiedad Tipo Descripción
first integer Número de la primera página (por ejemplo, 1)
firstItemNumber integer Número absoluto del primer elemento de esta página
firstPageInRange integer Primera página en el rango devuelto por el estilo de desplazamiento
current integer Número de página actual
currentItemCount integer Número de elementos en esta página
itemCountPerPage integer Número máximo de elementos disponibles por página
last integer Número de la última página
lastItemNumber integer Número absoluto del último elemento de esta página
lastPageInRange integer Última página en el rango devuelto por el estilo de desplazamiento
next integer Número de la página siguiente
pageCount integer Número de páginas
pagesInRange array Array de páginas devuelto por el estilo de desplazamiento
previous integer Número de la página anterior
totalItemCount integer Número total de elementos