Магазин на Yii2, часть 10. Добавляем постраничную навигацию

15.05.2019

Теги: Web-разработкаYii2ИнтернетМагазинКаталогТоваровНавигацияПостраничнаяНавигацияПрактикаФреймворк

Сейчас на странице категории показываются все товары этой категории и всех ее потомков. Это подходит для небольшого каталога, но когда товаров много, страница будет очень большой. Давайте добавим постраничную навигацию и используем для этого класс Pagination.

Сначала изменяем метод модели, отвечающий за получение списка товаров категории:

<?php
namespace app\models;

use yii\data\Pagination;
use yii\db\ActiveRecord;

class Category extends ActiveRecord {

    /*...*/

    /**
     * Возвращает массив всех товаров в категории с идентификатором $id
     * и в ее потомках, т.е. в дочерних, дочерних-дочерних и так далее
     */
    public function getCategoryProducts($id) {
        $id = (int)$id;
        // получаем массив идентификаторов всех потомков категории
        $ids = $this->getAllChildIds($id);
        $ids[] = $id;
        // для постаничной навигации получаем только часть товаров
        $query = Product::find()->where(['in', 'category_id', $ids]);
        $pages = new Pagination([
            'totalCount' => $query->count(),
            'pageSize' => 10, // кол-во товаров на странице
        ]);
        $products = $query->offset($pages->offset)
                          ->limit($pages->limit)
                          ->asArray()
                          ->all();
        return [$products, $pages];
    }

    /*...*/
}

Потом изменяем action в контроллере, отвечающий за страницу списка товаров категории:

<?php
namespace app\controllers;

use app\models\Category;
use app\models\Brand;
use app\models\Product;
use Yii;

class CatalogController extends AppController {

    /*...*/

    /**
     * Категория каталога товаров
     */
    public function actionCategory($id) {
        $id = (int)$id;
        $temp = new Category();
        // товары категории
        list($products, $pages) = $temp->getCategoryProducts($id);
        // данные о категории
        $category = $temp->getCategory($id);
        // устанавливаем мета-теги для страницы
        $this->setMetaTags(
            $category->name . ' | ' . Yii::$app->params['shopName'],
            $category->keywords,
            $category->description
        );
        return $this->render(
            'category',
            compact('category', 'products', 'pages')
        );
    }

    /*...*/
}

И последнее — используем виджет LinkPager в view-шаблоне views/catalog/category.php для показа постраничной навигации:

<?php
/*
 * Страница раздела каталога, файл views/catalog/category.php
 */

use app\components\TreeWidget;
use app\components\BrandsWidget;
use yii\helpers\Html;
use yii\helpers\Url;
use yii\widgets\LinkPager;
?>

<section>
    <div class="container">
        <div class="row">
            <div class="col-sm-3">
                <div class="left-sidebar">
                    <h2>Каталог</h2>
                    <div class="category-products">
                        <?= TreeWidget::widget(); ?>
                    </div>

                    <h2>Бренды</h2>
                    <div class="brand-products">
                        <?= BrandsWidget::widget(); ?>
                    </div>
                </div>
            </div>

            <div class="col-sm-9">
                <?php if (!empty($products)): ?>
                    <h2><?= Html::encode($category['name']); ?></h2>
                    <div class="row">
                        <?php foreach ($products as $product): ?>
                            <div class="col-sm-4">
                                <div class="product-wrapper text-center">
                                    <?=
                                    Html::img(
                                        '@web/images/products/medium/'.$product['image'],
                                        ['alt' => $product['name'], 'class' => 'img-responsive']
                                    );
                                    ?>
                                    <h2><?= $product['price']; ?> руб.</h2>
                                    <p>
                                        <a href="<?= Url::to(['catalog/product', 'id' => $product['id']]); ?>">
                                            <?= Html::encode($product['name']); ?>
                                        </a>
                                    </p>
                                    <a href="#" class="btn btn-warning">
                                        <i class="fa fa-shopping-cart"></i>
                                        Добавить в корзину
                                    </a>
                                    <?php
                                    if ($product['new']) { // новинка?
                                        echo Html::img(
                                            '@web/images/home/new.png',
                                            ['alt' => 'Новинка', 'class' => 'new']
                                        );
                                    }
                                    if ($product['sale']) { // распродажа?
                                        echo Html::img(
                                            '@web/images/home/sale.png',
                                            ['alt' => 'Распродажа', 'class' => 'sale']
                                        );
                                    }
                                    ?>
                                </div>
                            </div>
                        <?php endforeach; ?>
                    </div>
                    <?= LinkPager::widget(['pagination' => $pages]); /* постраничная навигация */ ?>
                <?php else: ?>
                    <p>Нет товаров в этой категории.</p>
                <?php endif; ?>
            </div>
        </div>
    </div>
</section>

Сейчас ссылки постраничной навигации имеют вид:

http://server.com/catalog/category/12?page=3&per-page=10

Давайте изменим это, чтобы ссылки имели вид:

http://server.com/catalog/category/12/page/3

Для этого добавим еще пару параметров к настройкам Pagination:

$pages = new Pagination([
    'totalCount' => $query->count(),
    'pageSize' => 10,
    'forcePageParam' => false,
    'pageSizeParam' => false
]);

И еще одно правило для маршрутов в файл config/web.php:

$config = [
    /*...*/
    'components' => [
        /*...*/
        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'rules' => [
                'catalog/category/<id:\d+>/page/<page:\d+>' => 'catalog/category',
                'catalog/category/<id:\d+>' => 'catalog/category',
                'catalog/brand/<id:\d+>' => 'catalog/brand',
            ],
        ],
    ],
    /*...*/
];

Поиск: Web-разработка • Yii2 • Интернет магазин • Каталог товаров • Навигация • Постраничная навигация • Фреймворк • Pagination

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.