【问题标题】:Yii2 data filtering in queriesYii2 查询中的数据过滤
【发布时间】:2016-10-15 14:26:39
【问题描述】:

在我的 Yii2 项目中,我将posts 表链接到categories 表作为多对多 关系(posts_categories 表)。 在我的Post 模型中,我有getByCategory($category_id) 函数,它返回该类别的所有帖子。在控制器中,我有actionCategory,我在其中使用此功能并传递特定类别的所有帖子。我在视图中还有一个 GET 表单,用于通过 GET 参数过滤我的帖子(我需要此值包含在显示的帖子的标题或内容中)。问题是我不知道如何以智能的方式将某些过滤器功能应用于控制器中的 getByCategory 调用。 我的功能码:

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 过滤。你能不能给点建议?谢谢。

【问题讨论】:

    标签: php mysql yii2 filtering


    【解决方案1】:

    对于数据库查询,请使用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 方法添加到Post 模型:

    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'));
    }
    

    【讨论】:

    • 这会返回 ActiveDataProvider,对吧?如果我必须不在 GridView 或 ListView 中显示它怎么办?谢谢
    • 是的,但是如果您使用大型数据集,最好使用 ActiveDataProvider。我已经更新了我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-17
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 2015-09-15
    • 2013-12-13
    相关资源
    最近更新 更多