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

Yii2: How to override the yii\db\Query class to add default conditions with queries

我想制作一个基于云的应用程序,我在会话中存储应用程序 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 class 并覆盖特征 where() from()select() 并从 yii\db\Querycommon\components\Query 整体在您要添加条件的模型中。但请记住,您有责任确保所有这些 table 都在 table 中包含这两个字段(application_idbranch_id),无论您在哪里替换 [=19] =] 与 common\components\Query.

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

假设我们有一个 product table 字段 idname,现在考虑以下查询。

$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条件

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

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 table 我们需要检查生成的查询,因此我们不会执行查询,而是使用 ->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)

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

编辑

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

Column 'company_id' in where clause is ambiguous

我已经在 from 数组中添加了第一个可用的 table 名称,因为您所有的 table 都有字段名称,并为第一个选定的 [=76= 添加了条件] 将工作,因为它将与下一个 table 和 ON 条件结合。 我已经从 class 中删除了 select() 特性覆盖,因为我们不需要它。