файл vendor\yiisoft\yii2\db\Query.php, вопрос по реализации or/andWhere

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
azz
Сообщения: 197
Зарегистрирован: 2016.07.06, 17:20

файл vendor\yiisoft\yii2\db\Query.php, вопрос по реализации or/andWhere

Сообщение azz »

Приветствую. Ковырялся в коде фреймворка, смотрел реализацию методов or|and where в файле vendor\yiisoft\yii2\db\Query.php. Заметил интересный момент. Реализация orWhere и andWhere идентична, за исключением двух строк:

Код: Выделить всё

        } elseif (is_array($this->where) && isset($this->where[0]) && strcasecmp($this->where[0], 'and') === 0) {
            $this->where[] = $condition;
В andWhere как я понимаю, это условие добавляет каждый новый andWhere condition в корень массива $this->where, в то время как в orWhere этого условия нет, и соотв. condition добавляется во вложенные массивы. Решил проверить:

Код: Выделить всё

$z = Objects::find()
    ->andWhere(['id' => 10])
    ->andWhere(['id' => 10])
    ->andWhere(['id' => 10])
    ->andWhere(['id' => 10]);
echo $z->createCommand()->getRawSql();

$z = Objects::find()
    ->orWhere(['id' => 10])
    ->orWhere(['id' => 10])
    ->orWhere(['id' => 10])
    ->orWhere(['id' => 10]);
echo $z->createCommand()->getRawSql();
print_r($this->where):

Код: Выделить всё

[
    0 => 'and'
    1 => [
        'id' => 10
    ]
    2 => [
        'id' => 10
    ]
    3 => [
        'id' => 10
    ]
    4 => [
        'id' => 10
    ]
]
SELECT * FROM `objects` WHERE (`id`=10) AND (`id`=10) AND (`id`=10) AND (`id`=10)

[
    0 => 'or'
    1 => [
        0 => 'or'
        1 => [
            0 => 'or'
            1 => [
                'id' => 10
            ]
            2 => [
                'id' => 10
            ]
        ]
        2 => [
            'id' => 10
        ]
    ]
    2 => [
        'id' => 10
    ]
]

SELECT * FROM `objects` WHERE (((`id`=10) OR (`id`=10)) OR (`id`=10)) OR (`id`=10)
собственно вопрос, почему так?
Nerf
Сообщения: 780
Зарегистрирован: 2015.01.29, 00:37

Re: файл vendor\yiisoft\yii2\db\Query.php, вопрос по реализации or/andWhere

Сообщение Nerf »

Странно. Действительно, по идее

Код: Выделить всё

is_array($this->where) && isset($this->where[0]) && strcasecmp($this->where[0], 'or') === 0
было бы не лишним.
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: файл vendor\yiisoft\yii2\db\Query.php, вопрос по реализации or/andWhere

Сообщение ElisDN »

Для AND скобки и не нужны:

1 AND 2 AND 3 AND 4 AND 5

А для OR необходимы

((1 OR 2) AND 3 OR 4) AND 5

так как без скобок AND "победит".

Поэтому и сделано, что orWhere всегда добавляет скобки (вложенный массив с 'or'), чтобы его следующий andWhere не перебил.
Nerf
Сообщения: 780
Зарегистрирован: 2015.01.29, 00:37

Re: файл vendor\yiisoft\yii2\db\Query.php, вопрос по реализации or/andWhere

Сообщение Nerf »

ElisDN писал(а): 2018.01.11, 13:57 Для AND скобки и не нужны:

1 AND 2 AND 3 AND 4 AND 5

А для OR необходимы

((1 OR 2) AND 3 OR 4) AND 5

так как без скобок AND "победит".

Поэтому и сделано, что orWhere всегда добавляет скобки (вложенный массив с 'or'), чтобы его следующий andWhere не перебил.
Там же проверяется оператор "верхнего уровня", видимо, для красоты итогового запроса. Нет же разницы между (cond1 OR cond2) OR cond3 и cond1 OR cond2 OR cond3 по аналогии...
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: файл vendor\yiisoft\yii2\db\Query.php, вопрос по реализации or/andWhere

Сообщение ElisDN »

Nerf писал(а): 2018.01.11, 19:14 Нет же разницы между (cond1 OR cond2) OR cond3 и cond1 OR cond2 OR cond3 по аналогии...
Разница появляется только при совместных AND и OR. Там уже от перестановки элементов результат меняется.

А так вообще если забыть об orWhere и всегда пользоваться только andWhere, то никаких проблем с порядком определения условий не будет.
Nerf
Сообщения: 780
Зарегистрирован: 2015.01.29, 00:37

Re: файл vendor\yiisoft\yii2\db\Query.php, вопрос по реализации or/andWhere

Сообщение Nerf »

ElisDN писал(а): 2018.01.11, 20:10 Разница появляется только при совместных AND и OR. Там уже от перестановки элементов результат меняется.

А так вообще если забыть об orWhere и всегда пользоваться только andWhere, то никаких проблем с порядком определения условий не будет.
Какая разница появляется? Я специально использовал condX, ничего в результате поменяться не должно от перестановок. Тот же and обернет предыдущие условия, если "сверху" не and.

Если я правильно понял автора, то он видит проблему в том, что orWhere добавляет ненужную вложенность как в массиве where, так и в итоговом запросе. А в andWhere эта ситуация обрабатывается отдельной веткой в if. Мне и самому интересно почему не добавили в orWhere: просто не добавили или какой-то косяк будет?
azz
Сообщения: 197
Зарегистрирован: 2016.07.06, 17:20

Re: файл vendor\yiisoft\yii2\db\Query.php, вопрос по реализации or/andWhere

Сообщение azz »

Nerf писал(а): 2018.01.11, 20:30 Если я правильно понял автора, то он видит проблему в том, что orWhere добавляет ненужную вложенность как в массиве where, так и в итоговом запросе.
Да. Не то что бы это было проблемой, просто хотелось понять причину такого решения.
Ответить