首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

Yii2 + Sphinx + Ajax 實作即時搜尋分頁完整範例

     編輯:PHP 綜合知識

專案背景

電商後台需支援商品關鍵字全文搜尋、價格區間篩選、Ajax 無重整分頁。技術棧:Yii 2.0、Sphinx Search、Pjax/Ajax 分頁。

核心元件

  • SphinxClient:連接 Sphinx searchd(port 9312),執行全文檢索。
  • Yii Pagination:根據搜尋回傳的 ID 列表,在 MySQL 二次查詢完整商品資料並分頁。
  • Ajax 區塊更新:點擊分頁連結時攔截請求,局部刷新商品列表。

控制器完整代碼

<?php
namespace backend\controllers;

use Yii;
use yii\web\Controller;
use yii\data\Pagination;
use SphinxClient;
use backend\models\Goods;

class SouController extends Controller
{
    public function actionIndex()
    {
        $sou = Yii::$app->request->get('sou', '');
        $p1  = Yii::$app->request->get('p1', '');
        $p2  = Yii::$app->request->get('p2', '');

        // 1. Sphinx 搜尋
        $cl = new SphinxClient();
        $cl->SetServer('127.0.0.1', 9312);
        $cl->SetConnectTimeout(3);
        $cl->SetArrayResult(true);

        if ($sou) {
            $cl->SetMatchMode(SPH_MATCH_ANY); // 任一關鍵字
        } else {
            $cl->SetMatchMode(SPH_MATCH_FULLSCAN); // 全掃描
        }

        // 價格區間過濾(屬性需在索引定義為 int)
        if ($p1 && $p2) {
            $cl->SetFilterRange('price', (int)$p1, (int)$p2);
        }

        $res = $cl->Query($sou, 'mysql_goods');
        if (!$res || empty($res['matches'])) {
            $ids = [];
        } else {
            $ids = array_column($res['matches'], 'id');
        }

        // 2. MySQL 二次查詢取完整欄位
        $query = Goods::find()->where(['id' => $ids]);
        $countQuery = clone $query;
        $pages = new Pagination([
            'totalCount' => $countQuery->count(),
            'defaultPageSize' => 3,
        ]);

        $models = $query->offset($pages->offset)
                        ->limit($pages->limit)
                        ->all();

        // 3. 關鍵字高亮(簡易版)
        foreach ($models as $k => $v) {
            $models[$k]['goods_name'] = str_replace(
                $sou,
                "$sou",
                $v['goods_name']
            );
        }

        return $this->render('index', [
            'res'  => $models,
            'pages' => $pages,
            'sou'  => $sou,
            'p1'   => $p1,
            'p2'   => $p2,
        ]);
    }
}
?>

視圖層:搜尋表單 + 列表 + Ajax 分頁

<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\widgets\LinkPager;

$form = ActiveForm::begin([
    'action' => ['sou/index'],
    'method' => 'get',
]) ?>

<center>
<div id="list">
    商品名稱: <input type="text" name="sou" value="<?= Html::encode($sou) ?>">
    價格區間: <input type="text" name="p1" value="<?= Html::encode($p1) ?>">---
                <input type="text" name="p2" value="<?= Html::encode($p2) ?>">
    <input type="submit" value="搜尋">

    <table border="1" style="width:500px;">
        <tr><th>ID</th><th>商品名稱</th><th>商品價格</th></tr>
        <?php foreach ($res as $v): ?>
        <tr>
            <td><?= $v['id'] ?></td>
            <td><?= $v['goods_name'] ?></td>
            <td><?= $v['price'] ?></td>
        </tr>
        <?php endforeach; ?>
    </table>

    <!-- 分頁 -->
    <?= LinkPager::widget(['pagination' => $pages]) ?>
</div>
</center>

<?php ActiveForm::end() ?>

<?php $this->beginBlock('ajax_pager') ?>
$(document).on('click', '.pagination a', function(e) {
    e.preventDefault();
    var href = $(this).attr('href');
    $.post(href, function(html) {
        $('#list').html(html);
    });
});
<?php $this->endBlock();
$this->registerJs($this->blocks['ajax_pager'], \yii\web\View::POS_END); ?>

關鍵細節說明

  1. Sphinx 只回傳 ID,減少網路傳輸;MySQL 再按 ID 取完整欄位,確保資料一致性。
  2. SetMatchMode:SPH_MATCH_ANY 適合關鍵字搜尋;SPH_MATCH_FULLSCAN 配合屬性過濾(如價格)可實現無關鍵字的篩選。
  3. Ajax 分頁:攔截 .pagination a 點擊,用 $.post 取回整個 #list 區塊 HTML 直接替換,保持搜尋條件與高亮狀態。
  4. XSS 防護:視圖中使用 Html::encode() 輸出使用者輸入;高亮替換僅針對可信關鍵字,實務上建議用 HtmlPurifier。

擴充建議

  • 加入 Sphinx 即時索引(RT Index)支援新增商品秒級可搜尋。
  • 分頁改用 yii\widgets\Pjax 獲得瀏覽器歷史支援與 SEO 友善。
  • 搜尋建議(Autocomplete)可另建 Sphinx 索引或用 Redis 熱門關鍵字前綴匹配。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved