[РЕШЕНО] Мозгодробилка с $c->where() в функции prepareQueryBeforeCount в процессоре расширяющем modObjectGetListProcessor

[Убийца — дворецкий]
Проблема была в типе данных по которым производился поиск. Заменил на varchar

Привет, коллеги!
Столкнулся с такой мозголомкой.
Есть процессор, который обрабатывает поиск в менеджере.
На входе ассоциативный массив.
Процессор расширяет modObjectGetListProcessor
В функции prepareQueryBeforeCount я формирую запрос. Формирую where через foreach:
foreach ($query as $k => $v){
    $this->where[$k.':LIKE'] = "%$v%";
}
$c->where($this->where);
Для проверки использую $c->toSql().
Выборка и джойны нас не интересуют — там всё норм, а вот то что происходит по результатам работы метода where() — это весьма интересно, и для меня в какой-то мере загадочно.
Итак.
На входе массив:
[$query] => Array
        (
            [id] => 100
            [city] => 200
            [name] => 300
            [phone] => 400
            [mail] => 500
            [performer] => 600
        )
Я просто поставил циферки в каждое поле поиска.

$this->where выглядит следующим образом:
[$this->where] => Array
        (
            [id:LIKE] => %100%
            [city:LIKE] => %200%
            [name:LIKE] => %300%
            [phone:LIKE] => %400%
            [mail:LIKE] => %500%
            [performer:LIKE] => %600%
        )
И после обработки, в части кода, который сформирован методом where() у нас получается вот что:
WHERE  ( `a`.`id` LIKE 0 AND `a`.`city` LIKE 0 AND `a`.`name` LIKE '%300%' AND `a`.`phone` LIKE 0 AND `a`.`mail` LIKE 0 AND `a`.`performer` LIKE 0 )
ВСЕ значения КРОМЕ name нулевые.
Причем не имеет значения, текст искать или цифры, все поля заполнять или только одно — все значения кроме name постоянно равны 0.
Происходит это если входное значение мы дополняем хотя бы одним знаком "%" при помощи конкатенации. Причем будет это записано как "%$v%" или "%".$v."%" — не важно. Результат всегда одинаковый — все кроме name — нули.
Сначала я думал, что проблема в типе данных, поскольку name — varchar, а остальные — text ( не спрашивайте почему, т.к. приложение разрабатывал не я :) ), но потом мысль эту от себя отогнал, потому что какая разница, если в самом SQL запросе нули.

Кто сталкивался?
Предлагайте куда копнуть.
Задавайте уточняющие вопросы.
Предлагайте эксперименты :)

MODX 2.6.5-pl
PHP 7.2.1
Boris Akimenko
25 июля 2018, 13:22
modx.pro
1 787
0

Комментарии: 19

Наумов Алексей
25 июля 2018, 14:14
1
0
А
$this->where
нормальный формируется?
М.б. его кто-то еще ухитряется поменять? Попробуй другую переменную, локальную использовать.
    Boris Akimenko
    25 июля 2018, 14:46
    0
    [$this->where] => Array
    (
    [id:LIKE] => %100%
    [city:LIKE] => %200%
    [name:LIKE] => %300%
    [phone:LIKE] => %400%
    [mail:LIKE] => %500%
    [performer:LIKE] => %600%
    )
      Boris Akimenko
      25 июля 2018, 14:49
      0
      Не. С этой штукой всё четко.
      Там как раз фишка в работе where()
      Если в цикле убрать "%", то в выходном SQL все значения правильные. Но тогда запрос SQL будет не корректным, потому что для поиска надо чтобы были "%"
        Володя
        25 июля 2018, 19:57
        0
        В функции prepareQueryBeforeCount я формирую запрос. Формирую where через foreach:
        если у вас prepareQueryBeforeCount, то почему
        $this->where

        а не
        $c->where
        на худой конец
        $this->query['where']
          Boris Akimenko
          25 июля 2018, 20:14
          0
          $this->where
          Это переменная я еезадал вначале скрипта.
          В нее я пишу массив значений, чтобы потом скопом их указать в
          $c->where($this->where);
          Даже если я сразу
          $c->where([$k=>$v])
          укажу в цикле, результат будет такой же.
      Сергей Шлоков
      25 июля 2018, 16:49
      0
      Случаем, типы полей не integer?
        Boris Akimenko
        25 июля 2018, 20:20
        0
        Я пробовал перевести одно из полей в varchar, но эффект нулевой.
        Очистил кэш и папку с кэшнм до кучи :)
        Но результата нет.
        Может, есть еще какое заклинание?
          Сергей Шлоков
          25 июля 2018, 20:22
          +1
          Править надо схему модели, а не таблицу в mySql. Надо всем этим полям указать phptype=«string».
            Boris Akimenko
            25 июля 2018, 22:02
            0
            Спасибо, Сергей!
            Я всё так и сделал, но есть один нюанс. Реализация, как я говорил, не моя и там оказалось несколько CMP с очень похожими названиями и в БД таблицы тоже с похожими названиями и схожей структурой таблиц. То есть столбцы с одинаковыми названиями.
            Так вот в таблице я поменял в которой надо, а файл .map.inc.php менял другой :)
            Ну, теперь в обоих CMP будет всё как надо.
              Сергей Шлоков
              25 июля 2018, 22:26
              +1
              «Спешат, спешат, а на спасибо и времени нет»


              П.С. Где мой плюс? :)
                Boris Akimenko
                25 июля 2018, 23:24
                0
                Я еще и коммент не туда залепил :)
                Стрелку апнул ;)
                И еще раз, мерси боку!
        Сергей Шлоков
        25 июля 2018, 19:02
        1
        +1
        Сначала я думал, что проблема в типе данных
        Именно. Фишка старого доброго (как говорит Иван Климчук) xPDO. Так что решение только одно — править схему.
          Володя
          25 июля 2018, 19:46
          0
          Можно же просто прописать нужный запрос в
          $this->query['where']
            Boris Akimenko
            25 июля 2018, 20:17
            0
            Я из
            $this->query
            беру значения для цикла.
            Можешь рассказать подробнее, что ты имеешь в виду?
              Володя
              26 июля 2018, 09:26
              0
              ты делаешь
              $c->where($this->where);
              что делает метод where ?

              он всего лишь пишет в массив $this->query['where'] условия. Я тебе и предлагал туда записать условия напрямую в виде sql
                Володя
                26 июля 2018, 09:34
                +2
                И после обработки, в части кода, который сформирован методом where() у нас получается вот что:
                WHERE  ( `a`.`id` LIKE 0 AND `a`.`city` LIKE 0 AND `a`.`name` LIKE '%300%' AND `a`.`phone` LIKE 0 AND `a`.`mail` LIKE 0 AND `a`.`performer` LIKE 0 )
                Для проверки использую $c->toSql().
                в данном случае toSql не вариант для проверки, поясню на примере

                первый запрос
                $c = $modx->newQuery('modResource');
                $c->select('id');
                
                $c->where(array(
                    'id:LIKE' => '%10%',
                ));
                $c->prepare();
                
                $total = $modx->getCount('modResource', $c);
                print_r($c->toSQL() . PHP_EOL);
                print_r($total . PHP_EOL);
                даст нам
                SELECT `id` FROM `modx_site_content` AS `modResource` WHERE `modResource`.`id` LIKE 0 
                2
                как видим запрос типа кривой, но результат выдал 2. Странно да? Уже повод задуматься…

                Давай выполним второй запрос, минуя метод where
                $c = $modx->newQuery('modResource');
                $c->select('id');
                
                $c->query['where'][] = new xPDOQueryCondition(array(
                    'sql'         => '`modResource`.`id` LIKE \'%10%\'',
                    'conjunction' => 'AND',
                ));
                $c->prepare();
                
                $total = $modx->getCount('modResource', $c);
                print_r($c->toSQL() . PHP_EOL);
                print_r($total . PHP_EOL);

                результат
                SELECT `id` FROM `modx_site_content` AS `modResource` WHERE `modResource`.`id` LIKE '%10%' 
                2

                Итог: в первом и втором запросе мы получили нужный результат. Так в чем же дело?
                Фишка старого доброго (как говорит Иван Климчук) xPDO
                ps. Вообщем не факт что твоя ошибка была в этом месте… совсем не факт. Просто при toSQL
                выполняется parseBindings что приводит запрос к такому виду…
                  Boris Akimenko
                  27 июля 2018, 11:44
                  0
                  Володя, спасибо!
                  Это очень ценная информация!
                  В итоге я еще обнаружил, что почти все поля по которым происходил поиск в схеме имели вместо 'phptype' => 'string', 'phptype' => 'text'
                  Я вообще теряюсь в догадках, как у заказчика это всё работало раньше, при таких косяках в коде.
                  Дело в том, что сайт был заражен и его как-то кто-то починил, после чего перестала работать система учета. Хоть заново всё пиши.
          Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
          19