Yii2: как переопределить класс yii\db\Query, чтобы добавить условия по умолчанию с запросами

Я хочу создать облачное приложение, в котором я храню идентификатор приложения и branch_id в сеансе, и я хочу добавить application_id и branch_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();

person rajwa766    schedule 07.03.2018    source источник
comment
Вы можете изменить этот запрос с помощью 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();   -  person Golub    schedule 07.03.2018
comment
Спасибо за ваш ответ. В приложении более 200 различных типов запросов. Я не могу использовать это в каждом запросе.   -  person rajwa766    schedule 07.03.2018
comment
просто скажите мне, пожалуйста, как я могу переопределить каждый запрос к БД, используя класс ActiveRecord   -  person rajwa766    schedule 07.03.2018
comment
Ответ: вы не можете. Можно переопределить класс Query классом DependencyInjection.   -  person Yupik    schedule 07.03.2018
comment
@Yupik .. как я могу использовать DependencyInjection?   -  person rajwa766    schedule 07.03.2018
comment
comment
Эй, ответ сработал для вас, выберите, если он вам как-то помог. Спасибо   -  person Muhammad Omer Aslam    schedule 14.03.2018
comment
только что обновил ответ, посмотрите, решит ли он проблему @Sajid   -  person Muhammad Omer Aslam    schedule 15.03.2018
comment
эй, @Саджид, я заметил, что ты отозвал свой голос за мой ответ, была ли проблема, с которой ты столкнулся?   -  person Muhammad Omer Aslam    schedule 17.03.2018


Ответы (1)


Ну, один из способов — расширить класс Query и переопределить черты where() from() и select() и изменить пространство имен с yii\db\Query на common\components\Query в целом в моделях, где вы хотите добавить условие. Но помните, что вы несете ответственность за то, чтобы во всех этих таблицах были эти 2 поля (application_id и branch_id) внутри таблиц, где бы вы ни заменяли yii\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 и добавьте следующее,

Примечание. Я добавил условия с жестко закодированными значениями для столбцов, подобных этому [ '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, нам нужно проверить сгенерированный запрос, поэтому мы не выполняем запрос, а используем ->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)

Надеюсь, это поможет вам или кому-то еще, кто ищет такое же решение.

ИЗМЕНИТЬ

Я обновил класс выше и добавил исправление для запросов с использованием соединений, которые выдают ошибку.

Столбец 'company_id' в предложении where неоднозначен

Я добавил первое имя table, доступное в массиве from, поскольку все ваши таблицы имеют имя поля, и добавление условия для первой выбранной таблицы будет работать, поскольку оно будет объединено со следующей таблицей с условием ON. И я удалил переопределение признака select() из класса, так как он нам не понадобится.

person Muhammad Omer Aslam    schedule 09.03.2018
comment
Спасибо за добрый отклик. - person rajwa766; 15.03.2018
comment
Не могли бы вы помочь в том, как я могу удалить двусмысленность в предложении where.waitng для вашего ответа.. - person rajwa766; 15.03.2018
comment
я не мог понять, что вы имели в виду под неоднозначным в предложении where @Sajid, не могли бы вы уточнить, пожалуйста? - person Muhammad Omer Aslam; 15.03.2018
comment
сэр, application_id и branch_id находятся во всех таблицах, все в порядке без соединения. Неоднозначная ошибка повторного запуска запроса на соединение. Это означает, что запрос перепутан с одним и тем же атрибутом в обеих таблицах. ошибка возврата - person rajwa766; 15.03.2018
comment
хм... позвольте мне проверить это с присоединением, и я отвечу @Sajid - person Muhammad Omer Aslam; 15.03.2018
comment
Я думаю, нам нужно переопределить основные файлы поставщиков. Неоднозначная ошибка всегда создает проблему и в обычной модели поиска. - person rajwa766; 15.03.2018
comment
модель поиска не связана с ней, так как это отдельный компонент и будет влиять только на те запросы, которые используют common\components\Query, а не ваши обычные модели поиска. - person Muhammad Omer Aslam; 15.03.2018
comment
я имею в виду, что неоднозначная ошибка возникает, когда мы используем объединение в модели поиска, если какой-либо атрибут имеет такое же имя, для этой ошибки мы просто используем псевдоним ('a') и называем атрибут в одной таблице как a.id. - person rajwa766; 15.03.2018
comment
Выполняемый SQL был следующим: SELECT users_level.display_name AS current_level FROM user INNER JOIN users_level ON user.user_level_id = users_level.id WHERE (user.id = '6691BCEE-EFAF-4862-8C4D-8FC510B7547E') AND (company_id='F9E7025A- 47B1-4D52-A73B-C1D83E0F4DD0') И (branch_id='464C2FFD-B0BD-4C91-B482-34B1F82EEB42') Информация об ошибке: Массив ([0] => 23000 [1] => 1052 [2] => Столбец 'company_id ' в предложении where неоднозначно - person rajwa766; 15.03.2018
comment
я заменил application_id на company_id - person rajwa766; 15.03.2018
comment
Таким образом, в условиях использования join двусмысленность можно устранить, используя имя таблицы вместе с именем поля, и мы можем использовать первую таблицу, доступную в массиве from, я обновлю ответ через мгновение @Sajid - person Muhammad Omer Aslam; 15.03.2018
comment
Сделал это @Мухаммад Омер Аслам. Молодец и большое спасибо - person rajwa766; 16.03.2018
comment
Теперь для всех простых методов поиска я имею в виду find(), я использую этот - person rajwa766; 16.03.2018
comment
общедоступная статическая функция find() { return parent::find()-›where(['=', 'company_id',Yii::$app-›session['company_id']])-›andWhere(['=' ,'branch_id',Yii::$app-›session['branch_id']]); } - person rajwa766; 16.03.2018
comment
во всех других моделях он работает нормально, теперь проблема в том, что когда пользователь подтверждает вход в систему, он возвращает валидацию flase из-за этого статического метода. - person rajwa766; 16.03.2018
comment
я думаю, вам следует добавить отдельный вопрос для проблемы, чтобы проблема была разделена, и должно быть предложено решение, специфичное для этого раздела, добавьте вопрос с соответствующим кодом и просто добавьте сообщение здесь для меня, я посмотрю на это @Sajid - person Muhammad Omer Aslam; 16.03.2018
comment
Я создал вопрос и отметил вас в комментарии. Я точно не знаю, получили ли вы уведомление или нет из-за пространства имен. вот ссылка на вопрос - person rajwa766; 16.03.2018
comment
stackoverflow.com/questions/49317648/ - person rajwa766; 16.03.2018
comment
да я понял @Саджид дай мне немного времени я отвечу там - person Muhammad Omer Aslam; 16.03.2018
comment
спасибо, нет проблем, сэр. Трудно получить помощь в этой рамочной работе. Так что большое спасибо, сэр. - person rajwa766; 16.03.2018