Yii2:如何覆盖 yii\db\Query 类以添加查询的默认条件

标签 yii2 yii2-advanced-app yii-components

我想创建一个基于云的应用程序,在 session 中存储应用程序 ID 和 branch_id,并且我想添加 application_idbranch_id 到每个数据库查询。

很简单,我使用覆盖find()

    public static function find()
{
    return parent::find()->where([]);
}

但问题是我如何重写这样的查询

  $total_return_price = (new Query())
            ->select('SUM(product_order.order_price * product_order.quantity) as return_price')
            ->from('order')
            ->innerJoin('product_order', 'product_order.order_id = order.id')
            ->where(['=', 'order.user_id', $user_id])
            ->andWhere(['=', 'order.status', '4'])
            ->one();

最佳答案

一种方法是扩展 Query类并覆盖特征 where() from()select()并从 yii\db\Query 更改命名空间至common\components\Query总体而言,在您想要添加条件的模型中。但请记住,您有责任确保所有这些表在替换 application_id 的表内都具有这两个字段( branch_idyii\db\Query )。与 common\components\Query .

为什么要覆盖 where() from()select() ?您可以使用以下格式编写查询。

假设我们有一个 product包含字段 id 的表和name ,现在考虑以下查询。

$q->from ( '{{product}}' )
        ->all ();

$q->select ( '*' )
        ->from ( '{{product}}' )
        ->all ();

$q->from ( '{{product}}' )
        ->where ( [ 'name' => '' ] )
        ->all ();

$q->from ( '{{product}}' )
        ->andWhere ( [ 'name' => '' ] )
        ->all ();

$q->select ( '*' )
        ->from ( '{{product}}' )
        ->where ( [ 'IN' , 'id' , [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 89 , 0 ] ] )
        ->andwhere ( [ 'name' => '' ] )
        ->all ();


$q->select ( '*' )
        ->from ( '{{product}}' )
        ->where ( [ 'and' ,
        [ 'IN' , 'id' , [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 89 , 0 ] ] ,
        [ 'name' => '' ]
        ] )
        ->all();

上面将生成以下 SQL 查询

SELECT * FROM `product` 
SELECT * FROM `product` 
SELECT * FROM `product` WHERE (`name`='') 
SELECT * FROM `product` WHERE (`name`='')
SELECT * FROM `product` WHERE (`id` IN (1, 2, 3, 4, 5, 6, 7, 89, 0)) AND (`name`='')
SELECT * FROM `product` WHERE (`id` IN (1, 2, 3, 4, 5, 6, 7, 89, 0)) AND (`name`='')

所以你需要添加上面所有默认带有两个where条件的查询

创建文件名Query common/components 并添加以下内容,

Note: I have added conditions with hardcoded values for the columns like this [ 'application_id' => 1 ] , [ 'branch_id' => 1 ] replace them with the respective variables from the session before actually using it for testing purpose you can keep as is.I assume that you want the above two fields to be added with an and condition in the query.

<?php

namespace common\components;

use yii\db\Query as BaseQuery;

class Query extends BaseQuery {

    /**
     * 
     * @param type $condition
     * @param type $params
     * @return $this
     */
    public function where( $condition , $params = array() ) {
        parent::where ( $condition , $params );

        $defaultConditionEmpty = !isset ( $this->where[$this->from[0] . '.company_id'] );

        if ( $defaultConditionEmpty ) {
            if ( is_array ( $this->where ) && isset ( $this->where[0] ) && strcasecmp ( $this->where[0] , 'and' ) === 0 ) {
                $this->where = array_merge ( $this->where , [ [ $this->from[0] . '.company_id' => 1 ] , [ $this->from[0] . '.branch_id' => 1 ] ] );
            } else {
                $this->where = [ 'and' , $this->where , [ $this->from[0] . '.company_id' => 1 ] , [ $this->from[0] . '.branch_id' => 1 ] ];
            }
        }
        return $this;
    }

    /**
     * 
     * @param type $tables
     * @return $this
     */
    public function from( $tables ) {
        parent::from ( $tables );
        $this->addDefaultWhereCondition ();

        return $this;
    }

    /**
     * Private method to add the default where clause 
     */
    private function addDefaultWhereCondition() {
        if ( $this->from !== null ) {

            $this->where = [ 'and' ,
                [ $this->from[0] . '.company_id' => 1 ] , [ $this->from[0] . '.branch_id' => 1 ]
            ];
        }
    }

}

现在要测试它,请在 SiteController 中创建一个测试操作像下面一样并访问它

public function actionTest() {
        $q = new \common\components\Query();

        echo $q->from ( '{{product}}' )->createCommand ()->rawSql;
        echo "<br>";
        echo $q->select ( '*' )->from ( '{{product}}' )->createCommand ()->rawSql;
        echo "<br/>";
        echo $q->from ( '{{product}}' )->where ( [ 'name' => '' ] )->createCommand ()->rawSql;
        echo "<br>";
        echo $q->from ( '{{product}}' )->andWhere ( [ 'name' => '' ] )->createCommand ()->rawSql;
        echo "<br>";
        echo $q->select ( '*' )->from ( '{{product}}' )->where ( [ 'IN' , 'id' , [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 89 , 0 ] ] )->andwhere ( [ 'name' => '' ] )->createCommand ()->rawSql;

        echo "<br />";
        echo $q->select ( '*' )->from ( '{{product}}' )
                ->where ( [ 'and' ,
                    [ 'IN' , 'id' , [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 89 , 0 ] ] ,
                    [ 'name' => '' ]
                ] )
                ->createCommand ()->rawSql;
        return;
    }

不用担心 product表我们需要检查生成的查询,因此我们不执行查询而是使用 ->createCommand()->rawSql打印构建的查询。因此,访问上述操作,它现在应该打印您的查询,并添加了如下所示的两列

SELECT * FROM `product` WHERE (`application_id`=1) AND (`branch_id`=1)
SELECT * FROM `product` WHERE (`application_id`=1) AND (`branch_id`=1)
SELECT * FROM `product` WHERE (`name`='') AND (`application_id`=1) AND (`branch_id`=1)
SELECT * FROM `product` WHERE (`application_id`=1) AND (`branch_id`=1) AND (`name`='')
SELECT * FROM `product` WHERE (`id` IN (1, 2, 3, 4, 5, 6, 7, 89, 0)) AND (`application_id`=1) AND (`branch_id`=1) AND (`name`='')
SELECT * FROM `product` WHERE (`id` IN (1, 2, 3, 4, 5, 6, 7, 89, 0)) AND (`name`='') AND (`application_id`=1) AND (`branch_id`=1)

希望对您或正在寻找相同解决方案的其他人有所帮助

编辑

我更新了上面的类,并使用联接添加了对查询的修复,这会引发错误

Column 'company_id' in where clause is ambiguous

我添加了第一个 table名称可在 from 中找到数组,因为所有表都有字段名称,并且添加第一个选定表的条件将起作用,因为它将与下一个表使用 ON 连接健康)状况。 我已经删除了 select()从类中覆盖特征,因为我们不需要它。

关于Yii2:如何覆盖 yii\db\Query 类以添加查询的默认条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49152429/

相关文章:

activerecord - Yii 2 : how to build search query using ActiveRecord between 2 tables?

php - 具有共享 session 的 Yii2 高级应用程序不会在 session 超时时自动登录

php - Yii2 paypal支付集成

php - 如何在 Yii 2 中读取 excel 文件并显示数据?

php - yii2 中每个页面标题中的登录表单

yii - 如何禁用 CGridView 中列的排序?

yii2 - 如何在模块中创建控制台命令?

yii2 中的 JavaScript 没有响应

yii2 - 使用表达式 Yii2 选择字符串被检测为列

javascript - 依赖下拉多个 .onchange