Paginación

Resumen
Un paginador es un componente que ayuda a dividir una gran cantidad de datos gradualmente. Un ejemplo sería mostrar todos los mensajes de un blog, 5 cada vez. El Paginador de Phalcon acepta parámetros y basado en ellos devuelve la porción correspondiente de todo el conjunto de resultados para que el desarrollador pueda presentar los datos paginados.
<?php
use Phalcon\Paginator\Adapter\NativeArray;
$currentPage = 2;
$paginator = new NativeArray(
[
"data" => [
["id" => 1, "name" => "Artichoke"],
["id" => 2, "name" => "Carrots"],
["id" => 3, "name" => "Beet"],
["id" => 4, "name" => "Lettuce"],
["id" => 5, "name" => ""],
],
"limit" => 2,
"page" => $currentPage,
]
);
$paginate = $paginator->paginate();
El ejemplo anterior usa un vector como fuente, y limita los resultados a 2 registros cada vez. Devolverá los elementos con id 3
y 4
porque page
se ha establecido a 2
.
Adaptadores
Para la fuente de datos, el componente usa adaptadores. Viene con los siguientes adaptadores:
NOTA: Como PDO no soporta cursores desplazables, no debería usarse Phalcon\Paginator\Adapter\Model para paginar un gran número de registros
Métodos
public function __construct(array $config)
Cada adaptador requiere opciones para funcionar correctamente. Estas opciones se pasan como vector clave/valor en el constructor del adaptador.
Los métodos expuestos son:
getLimit()
- int
- Obtiene el límite de filas actual
getRepository(array $properties = null)
- RepositoryInterface
- Obtiene el repositorio actual para la paginación
setCurrentPage(int $page)
- AdapterInterface
- Establece el número de página actual
setLimit(int $limitRows)
- AdapterInterface
- Establece el límite de filas actual
setRepository(RepositoryInterface $repository)
- AdapterInterface
- Establece el repositorio actual para la paginación
Modelo
El adaptador Phalcon\Paginator\Adapter\Model usa un Phalcon\Mvc\Model\Resultset como fuente de datos. Este ese el resultado del método find()
en un modelo.
<?php
use MyApp\Models\Invoices;
use Phalcon\Paginator\Adapter\Model;
$currentPage = 2;
$paginator = new Model(
[
"model" => Invoices::class,
"parameters" => [
"inv_cst_id = :cst_id:",
"bind" => [
"cst_id" => 1
],
"order" => "inv_title"
],
"limit" => 25,
"page" => $currentPage,
]
);
$paginate = $paginator->paginate();
El vector acepta model
para la clase de modelo a usar. Se llamará al método find()
sobre él. Adicionalmente este adaptador puede aceptar parámetros
como el vector que puede usar find()
con todas las condiciones relevantes requeridas.
Vector
Phalcon\Paginator\Adapter\NativeArray acepta un vector PHP como fuente de datos.
<?php
use Phalcon\Paginator\Adapter\NativeArray;
$currentPage = 2;
$paginator = new NativeArray(
[
"data" => [
["id" => 1, "name" => "Artichoke"],
["id" => 2, "name" => "Carrots"],
["id" => 3, "name" => "Beet"],
["id" => 4, "name" => "Lettuce"],
["id" => 5, "name" => ""],
],
"limit" => 2,
"page" => $currentPage,
]
);
$paginate = $paginator->paginate();
Constructor de Consultas
El adaptador Phalcon\Paginator\Adapter\QueryBuilder usa un objeto Phalcon\Mvc\Model\Query\Builder para realizar una consulta PHQL contra la base de datos.
<?php
use MyApp\Models\Invoices;
use Phalcon\Paginator\Adapter\QueryBuilder;
$builder = $this
->modelsManager
->createBuilder()
->columns("inv_id, inv_title")
->from(Invoices::class)
->orderBy("inv_title");
$paginator = new QueryBuilder(
[
"builder" => $builder,
"limit" => 20,
"page" => 1,
]
);
$paginate = $paginator->paginate();
Repositorio
El método paginate()
hace todo el trabajo para paginar los datos. Devuelve un objeto Phalcon\Paginator\Repository que almacena todos los elementos necesarios para la paginación. El objeto expone las siguientes constantes:
PROPERTY_CURRENT_PAGE
= “current”;
PROPERTY_FIRST_PAGE
= “first”;
PROPERTY_ITEMS
= “items”;
PROPERTY_LAST_PAGE
= “last”;
PROPERTY_LIMIT
= “limit”;
PROPERTY_NEXT_PAGE
= “next”;
PROPERTY_PREVIOUS_PAGE
= “previous”;
PROPERTY_TOTAL_ITEMS
= “total_items”;
Métodos
Los métodos expuestos son:
getAliases()
- array
- Obtiene los alias para el repositorio de propiedades
getCurrent()
- int
- Obtiene el número de la página actual
getFirst()
- int
- Obtiene el número de la primera página
getItems()
- mixed
- Obtiene los elementos de la página actual
getLast()
- int
- Obtiene el número de la última página
getLimit()
- int
- Obtiene el límite de filas actual
getNext()
- int
- Obtiene el número de la siguiente página
getPrevious()
- int
- Obtiene el número de la página anterior
getTotalItems()
- int
- Obtiene el número total de elementos
setAliases(array $aliases)
- RepositoryInterface
- Establece los alias para el repositorio de propiedades
setProperties(array $properties)
- RepositoryInterface
- Establece los valores para las propiedades del repositorio
Puede acceder a los datos usando los métodos anteriores o usar las propiedades mágicas como las definidas en las constantes:
<?php
use Phalcon\Paginator\Adapter\NativeArray;
$currentPage = 2;
$paginator = new NativeArray(
[
"data" => [
["id" => 1, "name" => "Artichoke"],
["id" => 2, "name" => "Carrots"],
["id" => 3, "name" => "Beet"],
["id" => 4, "name" => "Lettuce"],
["id" => 5, "name" => ""],
],
"limit" => 2,
"page" => $currentPage,
]
);
$paginate = $paginator->paginate();
echo $paginate->getCurrent(); // 2
echo $paginate->current ; // 2
echo $paginate->getFirst(); // 1
echo $paginate->first; // 1
var_dump($paginate->getItems());
// [
// [
// 'id' => 3
// 'name' => "Beet",
// ],
// [
// 'id' => 4,
// 'name' => "Lettuce",
// ]
// ]
var_dump($paginate->getItems());
echo $paginate->getLast(); // 3
echo $paginate->last; // 3
echo $paginate->getLimit(); // 2
echo $paginate->limit; // 2
echo $paginate->getNext(); // 3
echo $paginate->next; // 3
echo $paginate->getPrevious(); // 1
echo $paginate->previous; // 1
echo $paginate->getTotalItems(); // 5
echo $paginate->total_items; // 5
Alias
Si quiere usar sus propios nombres para cada propiedad mágica que el objeto Repositorio expone, puede usar el método setAliases()
para hacerlo.
<?php
use Phalcon\Paginator\Repository;
use Phalcon\Paginator\Adapter\NativeArray;
$repository = = new Repository();
$repository->setAliases(
[
'myCurrentPage' => $repository::PROPERTY_CURRENT_PAGE,
'myFirstPage' => $repository::PROPERTY_FIRST_PAGE,
'myLastPage' => $repository::PROPERTY_LAST_PAGE,
'myLimit' => $repository::PROPERTY_LIMIT,
'myNextPage' => $repository::PROPERTY_NEXT_PAGE,
'myTotalItems' => $repository::PROPERTY_TOTAL_ITEMS,
]
);
$currentPage = 2;
$paginator = new NativeArray(
[
"data" => [
["id" => 1, "name" => "Artichoke"],
["id" => 2, "name" => "Carrots"],
["id" => 3, "name" => "Beet"],
["id" => 4, "name" => "Lettuce"],
["id" => 5, "name" => ""],
],
"limit" => 2,
"page" => $currentPage,
'repository' => $repository,
]
);
$paginate = $paginator->paginate();
echo $paginate->myCurrentPage; // 2
echo $paginate->myFirstPage; // 1
echo $paginate->myLastPage; // 3
echo $paginate->myLimit; // 2
echo $paginate->myNextPage; // 3
echo $paginate->myTotalItems; // 1
También puede usar su clase repositorio personalizada implementando la interfaz Phalcon\Paginator\RepositoryInterface.
Fábrica (Factory)
Puede usar la clase Fábrica de Paginación para instanciar un nuevo objeto paginador. Los nombres del servicio son:
Nueva Instancia
Un método que puede usar es newInstance()
:
<?php
use MyApp\Models\Invoices;
use Phalcon\Paginator\PaginatorFactory;
$builder = $this
->modelsManager
->createBuilder()
->columns('inv_id, inv_title')
->from(Invoices::class)
->orderBy('name')
;
$options = [
'builder' => $builder,
'limit' => 20,
'page' => 1,
];
$factory = new PaginatorFactory();
$paginator = $factory->newInstance('queryBuilder');
Cargar
Carga la clase Adaptador de Paginador usando la opción adapter
. La configuración pasada puede ser un vector o un objeto Phalcon\Config con las entradas necesarias para que se instancie la clase.
<?php
use MyApp\Models\Invoices;
use Phalcon\Paginator\PaginatorFactory;
$builder = $this
->modelsManager
->createBuilder()
->columns('inv_id, inv_title')
->from(Invoices::class)
->orderBy('inv_title')
;
$options = [
'builder' => $builder,
'limit' => 20,
'page' => 1,
'adapter' => 'queryBuilder',
];
$paginator = (new PaginatorFactory())->load($options);
Un objeto de configuración de ejemplo es:
[paginator]
adapter = queryBuilder
options.limit = 20
options.page = 1
La configuración espera un elemento adapter
para el adaptador relevante y un vector options
con las opciones necesarias para el adaptador.
Excepción
Cualquier excepción lanzada en el componente Paginador será del tipo Phalcon\Paginator\Exception. Puede usar esta excepción para capturar selectivamente sólo las excepciones lanzadas desde este componente.
<?php
use Phalcon\Paginator\Adapter\NativeArray;
use Phalcon\Paginator\Exception;
try {
$currentPage = 2;
$paginator = new NativeArray(
[
"data" => [
["id" => 1, "name" => "Artichoke"],
["id" => 2, "name" => "Carrots"],
["id" => 3, "name" => "Beet"],
["id" => 4, "name" => "Lettuce"],
["id" => 5, "name" => ""],
],
"limit" => -5,
"page" => $currentPage,
]
);
$paginate = $paginator->paginate();
} catch (Exception $ex) {
echo $ex->getMessage();
}
Ejemplos
En el ejemplo anterior, el paginador usará el resultado de una consulta de un modelo como su fuente de datos, y limitará los datos mostrados a 10 registros por página:
Completo
<?php
use MyApp\Models\Invoices;
use Phalcon\Http\Request;
use Phalcon\Mvc\Controller;
use Phalcon\Mvc\View;
use Phalcon\Paginator\Adapter\Model as PaginatorModel;
/**
* @property Request $request
* @property View $view
*/
class InvoicesController extends Controller
{
public function listAction()
{
$currentPage = $this->request->getQuery('page', 'int', 1);
$paginator = new PaginatorModel(
[
'model' => Invoices::class,
'limit' => 10,
'page' => $currentPage,
]
);
$page = $paginator->paginate();
$this->view->setVar('page', $page);
}
}
En el ejemplo anterior $currentPage
contiene un entero, variable proporcionada por el usuario, con la página a mostrar. $paginator->paginate()
devuelve un objeto Phalcon\Paginator\Repository que contiene los datos paginados. Se puede usar para generar la paginación en una vista por ejemplo:
<table>
<tr>
<th>Id</th>
<th>Status</th>
<th>Title</th>
</tr>
<?php foreach ($page->getItems() as $item) { ?>
<tr>
<td><?php echo $item['inv_id']; ?></td>
<td><?php echo ($item['inv_status_flag']) ? 'Paid' : ''; ?></td>
<td><?php echo $item['inv_title']; ?></td>
</tr>
<?php } ?>
</table>
El objeto $page
también contiene datos de navegación:
<a href="/invoices/list">First</a>
<a href="/invoices/list?page=<?= $page->getPrevious(); ?>">Previous</a>
<a href="/invoices/list?page=<?= $page->getNext(); ?>">Next</a>
<a href="/invoices/list?page=<?= $page->getLast(); ?>">Last</a>
<?php echo "Page {$page->getCurrent()} of {$page->getLast()}"; ?>
Fábrica (Factory)
Puede instanciar una clase Paginador usando AdapterFactory
.
Modelo
<?php
use MyApp\Models\Invoices;
use Phalcon\Paginator\PaginatorFactory;
$factory = new PaginatorFactory();
$currentPage = 2;
$options = [
'model' => Invoices::class,
'limit' => 10,
'page' => $currentPage,
];
$paginator = $factory->newInstance('model', $options);
Vector
<?php
use MyApp\Models\Invoices;
use Phalcon\Paginator\PaginatorFactory;
$factory = new PaginatorFactory();
$currentPage = 2;
$options = [
'data' => [
['id' => 1, 'name' => 'Artichoke'],
['id' => 2, 'name' => 'Carrots'],
['id' => 3, 'name' => 'Beet'],
['id' => 4, 'name' => 'Lettuce'],
['id' => 5, 'name' => ''],
],
'limit' => 2,
'page' => $currentPage,
];
$paginator = $factory->newInstance('nativeArray', $options);
<?php
use MyApp\Models\Invoices;
use Phalcon\Paginator\PaginatorFactory;
$factory = new PaginatorFactory();
$currentPage = 2;
$builder = $this
->modelsManager
->createBuilder()
->columns('id, name')
->from('Robots')
->orderBy('name');
$options = [
'builder' => $builder,
'limit' => 20,
'page' => $currentPage,
];
$paginator = $factory->newInstance('queryBuilder', $options);
Clases Individuales
Un ejemplo de fuente de datos que se debe usar para cada adaptador:
Modelo
<?php
use Phalcon\Paginator\Adapter\Model as PaginatorModel;
$currentPage = 2;
$paginator = new PaginatorModel(
[
'model' => Invoices::class,
'limit' => 10,
'page' => $currentPage,
]
);
Vector
<?php
use Phalcon\Paginator\Adapter\NativeArray as PaginatorArray;
$currentPage = 2;
$paginator = new PaginatorArray(
[
'data' => [
['id' => 1, 'name' => 'Artichoke'],
['id' => 2, 'name' => 'Carrots'],
['id' => 3, 'name' => 'Beet'],
['id' => 4, 'name' => 'Lettuce'],
['id' => 5, 'name' => ''],
],
'limit' => 2,
'page' => $currentPage,
]
);
Constructor de Consultas
<?php
use MyApp\Models\Invoices;
use Phalcon\Paginator\Adapter\QueryBuilder as PaginatorQueryBuilder;
$currentPage = 2;
$builder = $this
->modelsManager
->createBuilder()
->columns('id, name')
->from('Robots')
->orderBy('name');
$paginator = new PaginatorQueryBuilder(
[
'builder' => $builder,
'limit' => 20,
'page' => $currentPage,
]
);
Personalizado
Se debe implementar la interfaz Phalcon\Paginator\AdapterInterface para crear sus propios adaptadores de paginador o extender los existentes:
<?php
use Phalcon\Paginator\AdapterInterface as PaginatorInterface;
use Phalcon\Paginator\RepositoryInterface;
class MyPaginator implements PaginatorInterface
{
/**
* Get current rows limit
*/
public function getLimit(): int;
/**
* Returns a slice of the resultset to show in the pagination
*/
public function paginate(): RepositoryInterface;
/**
* Set the current page number
*/
public function setCurrentPage(int $page);
/**
* Set current rows limit
*/
public function setLimit(int $limit);
}