用YII實現多重查詢(基於tag)

場景:
有一個飯店表 restaurant,存放全部飯店記錄。我須要一個功能,將飯店按照不一樣的條件進行多重查詢。就象這樣:
 
氛圍:浪漫 / 商務會談 / 茅草屋
菜系:川菜 / 魯菜 / 家常菜...
區域:東區 / 西區 / 南區 / 北區...
 
我點擊一個或多個條目,則下方自動刷出符合條件的飯店來。
例如我點擊了 浪漫、商務會談、魯菜,因爲浪漫、商務會談是同屬於氛圍的,應該認爲用戶想查找的是「或」的關係,無論出現兩者的哪個,都屬於查詢範圍;而魯菜是屬於菜系的,那麼與前兩個條件來講,應該是「與」的關係,即:用戶想查(氛圍==浪漫 || 氛圍==商務會談)&& (菜系==魯菜)的全部飯館的集合。
這裏有一個邏輯上的小別扭:若是我氛圍選了浪漫,菜系不選,那麼是否是要選擇(氛圍==浪漫)&& (菜系==none)嗎?這樣的結果確定爲空。實際上,不選菜系表示對菜系無要求,因此範圍應該是(氛圍==浪漫)&& (菜系==全部)。
 
考慮到這個功能比較常見,打算作一個通用的東西出來
感受這是個難度比較大的功能,來作一下吧。
 
一、創建幾個表:tag_tablename、tag_title、tag_text、tag_refer。其中
tag_tablename - 在這裏只有一條記錄 restaurant,但未來可能會有其它的,如article、user等
tag_title - 這是大的分類,分別爲氛圍、菜系、區域,每一條的tablename_id爲1,即restaurant
tag_text - 這是具體的tag,如浪漫、川菜、魯菜、東區。。等等
tag_refer - 這是一個多對多的表,它記錄了restaurant表中的記錄與tag_text表中的記錄的多對多的對應關係
 
二、建立 Model。這裏,TagTablename裏實現了tag_titles,TagTitle裏面實現了tag_texts。
 
三、寫實現的類 CAnjoTag
    // 生成:
    //     氛圍:浪漫 / 商務會談 / 茅草屋...
    //     菜系:川菜 / 魯菜 / 家常菜...
    //     區域:東區 / 西區 / 南區 / 北區...
    // 這樣的樣式,而且最好能接受點擊,而且最好在點擊後調用ajax更新下面的查詢結果
    public static function tag_list($tablename, $options=array()) {
        $r='  <ul class="select">';
         。。。
        return $r;
    }

 

這裏面的具體實現就不貼出來了,主要是一步步生成html代碼,顯示前面的那些內容,並接受點擊,點擊一次選擇,再次點擊則取消選擇。點擊會觸發一個javascript函數,它回調另外一個javascript函數,用以 Ajax 方式更新查詢區域的內容。
 
而後,這樣調用和更新ajax獲取的內容
<?php echo CAnjoTag::tag_list('Restaurant', array('click_callback'=>'tag_clicked')); ?>
<script>
function tag_clicked(ids)
{
  // console.log(ids);
  $('#rest-grid').load('?r=rest/ajaxAction&action=rest_query', {tagtext_ids: ids});
}
</script>
 
在RestController中這樣實現:
    public function actionAjaxAction($action)
    {
        $r='';
        switch ($action)
        {
            case 'rest_query':
                $ids=Yii::app()->request->getParam('tagtext_ids');
                if (substr($ids, -1)==',') $ids=substr($ids, 0, -1); //刪除結尾的 ,
                $ids=trim($ids);
                if ($ids!='')
                {
                    $cond="id in (select record_id from {{tag_refer}} where tag_text_id in ($ids))";
                    $criteria = new CDbCriteria;
                    $criteria->condition=$cond;

                    $count = Restaurant::model()->count($criteria);
                    $pager = new CPagination($count);
                    $pageSize=10;
                    $pager->params = array('tagtext_ids'=>$ids, 'action'=>'rest_query');//分頁中添加其餘參數
                    $pager->pageSize=$pageSize;
                    $pager->applyLimit($criteria);
                    $dataProvider=new CActiveDataProvider('Restaurant', array(
                        'criteria'=>$criteria,
                        'sort'=>array(
                            'defaultOrder'=>'id desc',
                        ),
                        'pagination'=>$pager,
                    ));
                    $this->renderPartial('_query_result', array('dataProvider'=>$dataProvider));
                    die();
                }
                break;
        }

        echo $r;
    }
 
四、ajax換頁問題
調試ajax換頁時費了很大勁。老是作不到按Ajax方式顯示下一頁,一點頁碼的連接就跳到新頁上了。看一下console的錯誤信息,不能ajax調用的緣由是在 jquery.yiigridview.js 中,出現了錯誤:
$.param.querystring is not a function
 
網上解釋說:這個錯誤會致使你不管怎麼選擇filter,都不會發送請求道cintroll去取數據,解決辦法就是,不管在什麼地方調用jquery,最好使用Yii的registe來註冊,而不要使用<script>來引入.
 
<?php Yii::app ()->clientScript->registerCoreScript ( 'jquery' ); ?>
但bootstrap提示,
Uncaught Error: Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3
因而找到 Yii的核心script所在的位置:
D:\xampp\htdocs\yii-1.1.14.f0fee9_201505\framework\web\js\source
 
這個jquery.js 是1.8.3的,我複製了一個1.11.3的進來,一切正常了。
 
這個jquery的問題,真的要改變習慣了。之前也會由於jquery的屢次引用而形成相似的這種莫名其妙的錯誤,試着改變jquery的位置或顯式地引用一下它,有時也能解決,但終歸不是正途。
(另:看了 jquery.yiigridview.js的源碼,原來是Yii的做者寫的。真牛~前端也很強嘛)
 
5. 待改進:
在actionAjaxAction中,$cond="id in (select record_id from {{tag_refer}} where tag_text_id in ($ids))"; 這個寫法是不嚴謹的。它把全部的條件都當作「或」來處理了,沒有實現前面分析的結論。這是小問題,之後再細細實現。
 
另外一個是,在飯店信息的修改界面,我須要調用 CAnjoTag 的另外一個方法,顯示飯店的相關tag屬性並能夠修改。這一樣是個人初衷之一,下一步會去作。
相關文章
相關標籤/搜索