Обзор.

Пагинатор-это компонент, который помогает постепенно разбивать большое количество данных. Примером может быть отображение всех сообщений блога, по 5 за раз. Phalcon Paginator принимает параметры и на их основе возвращает соответствующий срез всего результирующего набора, чтобы разработчик мог представить разбитые на страницы данные.

<?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();

Приведенный выше пример использует массив в качестве источника и ограничивает результаты двумя записями одновременно. Он вернет элементы с идентификаторами 3 и 4, поскольку страница была установлена на 2.

Процесс разбиения на страницы происходит, когда нам нужно постепенно представить большие группы произвольных данных.. Phalcon\Paginator предлагает быстрый и удобный способ разделить эти наборы данных на просматриваемые страницы.

Адаптер данных.

Этот компонент использует адаптеры для инкапсуляции различных источников данных:

АдаптерОписание
Phalcon\Paginator\Adapter\NativeArray Использование массива PHP в качестве исходных данных
Phalcon\Paginator\Adapter\Model Использование объекта Phalcon\Mvc\Model\Resultset в качестве исходных данных. Поскольку PDO не поддерживает прокрутку курсоров, этот адаптер не должен использоваться для разбиения на страницы большого количества записей
Phalcon\Paginator\Adapter\QueryBuilder Использование объекта Phalcon\Mvc\Model\Query\Builder в качестве источника данных

Примечание: поскольку PDO не поддерживает прокручиваемые курсоры, Phalcon\Paginator\Adapter\Model не следует использовать для разбиения на страницы большого количества записей

Методы

public function __construct(array $config)

Каждый адаптер требует опций для правильной работы. Эти параметры передаются в виде массива ключ/значение в конструкторе адаптера.

Методы, которые подвергаются являются:

  • getLimit() - int - Получить текущий лимит строк
  • getRepository(array $properties = null) - RepositoryInterface - Возвращает текущий репозиторий для разбиения на страницы
  • setCurrentPage(int $page) - AdapterInterface - Установить номер текущей страницы
  • setLimit(int $limitRows) - AdapterInterface - Установить ограничение по текущим строкам
  • setRepository(RepositoryInterface $repository) - AdapterInterface - Установить текущий репозиторий для разбиения на страницы

Модель

Адаптер Phalcon\Paginator\Adapter\Model использует Phalcon\Mvc\Model\Resultset как источник данных. Это результат метода find() на модели.

<?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();

The array accepts model for the model class to be used. The method find() will be called on it. Additionally this adapter can accept parameters as the array that find() can use with all the relevant conditionals required.

Массив

Адаптер Phalcon\Paginator\Adapter\NativeArray принимает массив PHP в качестве источника данных.

<?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();

Построитель запросов

Адаптер Phalcon\Paginator\Adapter\QueryBuilder использует объект Phalcon\Mvc\Model\Query\Builder для выполнения запроса PHQL к базе данных.

<?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();

Repository

Метод paginate() выполняет всю работу по разбиению данных на страницы. Он возвращает объект Phalcon\Paginator\Repository , в котором хранятся все необходимые элементы для пагинации. Объект предоставляет следующие константы:

  • 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”;

Методы

Методы, которые подвергаются являются:

  • getAliases() - array - Возвращает псевдонимы для репозитория свойств
  • getCurrent() - int - Возвращает номер текущей страницы
  • getFirst() - int - Получает номер первой страницы
  • getItems() - mixed - Возвращает элементы на текущей странице
  • getLast() - int - Получает номер последней страницы
  • getLimit() - int - Возвращает ограничение по текущим строкам
  • getNext() - int - Получает номер следующей страницы
  • getPrevious() - int - Возвращает номер предыдущей страницы
  • getTotalItems() - int - Возвращает общее количество элементов
  • setAliases(array $aliases) - RepositoryInterface - Задает псевдонимы для репозитория свойств
  • setProperties(array $properties) - RepositoryInterface - Задает значения для свойств репозитория

Вы можете получить доступ к данным с помощью описанных выше методов или использовать магические свойства, определенные в константах:

<?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 

Псевдонимы

Если вы хотите использовать свои собственные имена для каждого магического свойства, которое предоставляет объект репозитория, вы можете использовать метод setAliases() для этого.

<?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

You can also create your custom repository class by implementing the Phalcon\Paginator\RepositoryInterface interface.

Фабрика

Вы можете использовать класс pagination Factory для создания экземпляра нового объекта paginator. Названия служб таковы::

Новые случаи

Один из методов, который вы можете использовать - 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');

Загрузка

Загружает класс адаптера Paginator, используя опцию adapter . Передаваемая конфигурация может быть массивом или объектом Phalcon\Config с необходимыми записями для создания экземпляра класса.

<?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);

Пример объекта конфигурации:

[paginator]
adapter = queryBuilder
options.limit = 20
options.page = 1

Конфигурация ожидает элемент adapter для соответствующего адаптера и массив options с необходимыми опциями для адаптера.

Исключение

Любые исключения, создаваемые в компоненте Paginator, будут иметь тип Phalcon\Paginator\Exception. Это исключение можно использовать для выборочного перехвата исключений, создаваемых только из этого компонента.

<?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();
}

Примеры

В приведенном ниже примере пагинатор использует результат запроса из модели в качестве исходных данных и ограничивает отображаемые данные 10 записями на страницу:

Полный

<?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);
    
    }
}

В приведенном выше примере $currentPage содержит целое число, пользовательскую переменную, для отображения страницы. Функция $paginator->paginate() возвращает объект Phalcon\Paginator\Repository, содержащий разбитые на страницы данные. Он может быть использован для создания разбиения на страницы в представлении, например:

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

Объект $page также содержит навигационные данные:

<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()}"; ?>

Фабрика

Вы можете создать экземпляр класса Paginator с помощью AdapterFactory.

Модель

<?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);

Массив

<?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);

Индивидуальные Классы

Пример исходных данных, которые должны использоваться для каждого адаптера:

Модель

<?php

use Phalcon\Paginator\Adapter\Model as PaginatorModel;

$currentPage = 2;
$paginator   = new PaginatorModel(
    [
       'model'  => Invoices::class,
       'limit' => 10,
       'page'  => $currentPage,
    ]
);

Массив

<?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,
    ]
);

Построитель запросов

<?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,
    ]
);

Собственные адаптеры

Для того, чтобы создавать свои собственные адаптеры пагинатора или расширить уже существующие, должен быть реализован интерфейс Phalcon\Paginator\AdapterInterface :

<?php

use Phalcon\Paginator\AdapterInterface as PaginatorInterface;
use Phalcon\Paginator\RepositoryInterface;

class MyPaginator implements PaginatorInterface
{
    /**
     * Получить текущий лимит строк
     */
    public function getLimit(): int;

    /**
     * Возвращает фрагмент результирующего набора для отображения в разбиении на страницы
     */
    public function paginate(): RepositoryInterface;

    /**
     * Установите номер текущей страницы
     */
    public function setCurrentPage(int $page);

    /**
     * Установить ограничение по текущим строкам
     */
    public function setLimit(int $limit);
}