2016-06-14 60 views
3

在我的Yii2項目中,我有posts錶鏈接到categories表作爲多對多關係(posts_categories表)。 在我的Post模型中,我有getByCategory($category_id)函數,它返回該類別的所有文章。在控制器中,我有actionCategory,我使用此功能並通過某個類別的所有帖子。我在視圖中也有一個GET表單,用於通過GET參數篩選我的帖子(我需要將此值包含在顯示的帖子的標題或內容中)。問題是我不知道如何以智能的方式將一些過濾器函數應用於控制器中的getByCategory調用。 我的功能代碼:Yii2查詢中的數據過濾

public static function getPostsByCategory($category_id = null) 
{ 
    $posts = Post::find() 
     ->select('posts.*') 
     ->innerJoin('posts_categories', '`posts`.`id` = `posts_categories`.`post_id`') 
     ->where(['posts_categories.category_id' => $category_id]) 
     ->orderBy(['date_create' => SORT_DESC]) 
     ->all(); 
    return $posts; 
} 

控制器動作:

public function actionCategory($id) 
{ 
    $posts = Post::getPostsByCategory($id); 
    return $this->render('index', array('all_posts' => $posts)); 
} 

所有我的想法一樣使用類似的語句:「如果$ _GET不是空的 - 使用一個查詢 - 如果是空的 - 一個又一個」在控制器或在模型中看起來很亂,並導致在其他操作中複製代碼,我還需要$ _GET過濾。你能請一些建議嗎?謝謝。

回答

2

請使用db查詢使用ActiveQuery。這很簡單,更有效。

爲您簡單的,創建

class PostQuery extends \yii\db\ActiveQuery 
{ 
    public function byCategory($id){ 
     $junction_table = '{{%posts_categories}}'; 
     $this 
      ->innerJoin($junction_table, Post::tableName()'.id='.$junction_table.'.post_id') 
      ->where([$junction_table.'.category_id' => $id]); 
    } 

    public function orderByDateCreated($sort_type = SORT_DESC){ 
     return $this 
      ->orderBy(['date_create' => $sort_type]); 
    } 

    /** 
    * @inheritdoc 
    * @return Post[]|array 
    */ 
    public function all($db = null) 
    { 
     return parent::all($db); 
    } 

    /** 
    * @inheritdoc 
    * @return Post|array|null 
    */ 
    public function one($db = null) 
    { 
     return parent::one($db); 
    } 
} 

添加find tethod到樁模型:

public static function find() 
{ 
    return new PostQuery(get_called_class()); 
} 

對於搜索和過濾器使用PostSearch模式,從Post模型擴展。

class PostSearch extends Post 
{ 
    public $category_id; 

    public function rules(){ 
     return [ 
      ['category_id', 'integer'] 
     ]; 
    } 

    public function search($params = []){ 

     $query = Post::find(); 

     $query 
      ->orderByDateCreated(); 

     $dataProvider = new ActiveDataProvider([ 
      'query' => $query 
     ]); 

     if(!($this->load($params) && $this->validate())){ 
      return $dataProvider; 
     } 

     if($this->category_id) 
      $query->byCategory($this->category_id) 

     return $dataProvider; 
    } 
} 

在動作控制器與搜索

public function actionIndex(){ 
    $searchModel = new ArticleSearch(); 

    $dataProvider = $searchModel->search(\Yii::$app->request->post()); //data from filter form 

    return $this->render('index', compact('dataProvider')); 
} 

沒有ActiveDataProvider

public function actionIndex(){ 
    $searchModel = new ArticleSearch(); 

    $query = Post::find(); 

    $query 
     ->orderByDateCreated(); 

    if($searchModel->load(\Yii::$app->request->post()) && $searchModel->validate()){ 
     if($this->category_id) 
      $query->byCategory($this->category_id) 
    } 

    $posts = $query->all(); 

    return $this->render('index', compact('posts')); 
} 
+0

這將返回ActiveDataProvider,對不對?如果我不得不在GridView或ListView中顯示它,該怎麼辦?謝謝 –

+0

是的,但是如果您使用大型數據集,最好使用ActiveDataProvider。我已經更新了我的答案。 – Vitaly