【问题标题】:Yii2: How to override the yii\db\Query class to add default conditions with queriesYii2:如何覆盖 yii\db\Query 类以添加查询的默认条件
【发布时间】:2018-03-07 12:51:25
【问题描述】:

我想创建一个基于云的应用程序,我将应用程序 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();

【问题讨论】:

  • 您可以使用 activeQuery 更改该查询并像这样编写 Order::find()->select('SUM(product_order.order_price * product_order.quantity) as return_price') ->innerJoin('product_order', 'product_order.order_id = order.id') ->where(['=', 'order.user_id', $user_id]) ->andWhere(['=', 'order.status', '4']) ->one();
  • 感谢您的回复。应用程序中有超过 200 种不同类型的查询。我不能在每个查询中使用它。
  • 请告诉我如何使用 activeRecord 类覆盖对数据库的每个查询
  • 答案是:你不能。一个选项是通过 DependencyInjection 覆盖 Query
  • @Yupik..我如何使用 DependencyInjection?

标签: yii2 yii2-advanced-app yii-components


【解决方案1】:

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

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

假设我们有一个product 表,其中包含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并添加以下内容,

注意:我为列添加了带有硬编码值的条件 像这样[ 'application_id' => 1 ] , [ 'branch_id' => 1 ]替换 在实际使用之前将它们与会话中的相应变量一起使用 出于测试目的,您可以保持原样。我假设您想要以上两个 要在查询中添加 and 条件的字段。

<?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 表,我们需要检查生成的查询,因此我们不执行查询,而是使用-&gt;createCommand()-&gt;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)

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

编辑

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

where 子句中的“company_id”列不明确

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

【讨论】:

  • 感谢您的友好回应。
  • 您能帮我解决一下 where 子句中的歧义。等待您的回复..
  • 我无法理解你的意思是什么
  • 先生,application_id 和 branch_id 在所有表中都可以,无需连接。连接查询返回模棱两可的错误。这意味着查询与两个表返回错误中的相同属性混淆
  • 我已经创建了问题并在评论中标记了你。由于那里的名称空间,我不知道你是否收到了通知。这是问题链接
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-26
  • 2019-05-09
  • 1970-01-01
  • 2021-08-03
  • 1970-01-01
  • 2012-09-03
  • 1970-01-01
相关资源
最近更新 更多