2016-06-14 5 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, простиралась от столба модели.

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

Смежные вопросы