[РЕШЕНО] Мозгодробилка с $c->where() в функции prepareQueryBeforeCount в процессоре расширяющем modObjectGetListProcessor
        [Убийца — дворецкий]
Проблема была в типе данных по которым производился поиск. Заменил на varchar
Привет, коллеги!
Столкнулся с такой мозголомкой.
Есть процессор, который обрабатывает поиск в менеджере.
На входе ассоциативный массив.
Процессор расширяет modObjectGetListProcessor
В функции prepareQueryBeforeCount я формирую запрос. Формирую where через foreach:
Выборка и джойны нас не интересуют — там всё норм, а вот то что происходит по результатам работы метода where() — это весьма интересно, и для меня в какой-то мере загадочно.
Итак.
На входе массив:
$this->where выглядит следующим образом:
Причем не имеет значения, текст искать или цифры, все поля заполнять или только одно — все значения кроме name постоянно равны 0.
Происходит это если входное значение мы дополняем хотя бы одним знаком "%" при помощи конкатенации. Причем будет это записано как "%$v%" или "%".$v."%" — не важно. Результат всегда одинаковый — все кроме name — нули.
Сначала я думал, что проблема в типе данных, поскольку name — varchar, а остальные — text ( не спрашивайте почему, т.к. приложение разрабатывал не я :) ), но потом мысль эту от себя отогнал, потому что какая разница, если в самом SQL запросе нули.
Кто сталкивался?
Предлагайте куда копнуть.
Задавайте уточняющие вопросы.
Предлагайте эксперименты :)
MODX 2.6.5-pl
PHP 7.2.1     
    
    
                                                                                
            Проблема была в типе данных по которым производился поиск. Заменил на 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
Комментарии: 19
                А 
М.б. его кто-то еще ухитряется поменять? Попробуй другую переменную, локальную использовать.
                    $this->whereнормальный формируется?М.б. его кто-то еще ухитряется поменять? Попробуй другую переменную, локальную использовать.
                [$this->where] => Array
(
[id:LIKE] => %100%
[city:LIKE] => %200%
[name:LIKE] => %300%
[phone:LIKE] => %400%
[mail:LIKE] => %500%
[performer:LIKE] => %600%
)
                    (
[id:LIKE] => %100%
[city:LIKE] => %200%
[name:LIKE] => %300%
[phone:LIKE] => %400%
[mail:LIKE] => %500%
[performer:LIKE] => %600%
)
                Не. С этой штукой всё четко.
Там как раз фишка в работе where()
Если в цикле убрать "%", то в выходном SQL все значения правильные. Но тогда запрос SQL будет не корректным, потому что для поиска надо чтобы были "%"
                    Там как раз фишка в работе where()
Если в цикле убрать "%", то в выходном SQL все значения правильные. Но тогда запрос SQL будет не корректным, потому что для поиска надо чтобы были "%"
В функции prepareQueryBeforeCount я формирую запрос. Формирую where через foreach:если у вас prepareQueryBeforeCount, то почему
$this->where а не
$c->whereна худой конец $this->query['where']            $this->whereЭто переменная я еезадал вначале скрипта. В нее я пишу массив значений, чтобы потом скопом их указать в
$c->where($this->where);Даже если я сразу $c->where([$k=>$v])укажу в цикле, результат будет такой же.            
                Случаем, типы полей не integer?            
                    
                Я пробовал перевести одно из полей в varchar, но эффект нулевой. 
Очистил кэш и папку с кэшнм до кучи :)
Но результата нет.
Может, есть еще какое заклинание?
                    Очистил кэш и папку с кэшнм до кучи :)
Но результата нет.
Может, есть еще какое заклинание?
                Править надо схему модели, а не таблицу в mySql. Надо всем этим полям указать phptype=«string».            
                    
                Спасибо, Сергей!
Я всё так и сделал, но есть один нюанс. Реализация, как я говорил, не моя и там оказалось несколько CMP с очень похожими названиями и в БД таблицы тоже с похожими названиями и схожей структурой таблиц. То есть столбцы с одинаковыми названиями.
Так вот в таблице я поменял в которой надо, а файл .map.inc.php менял другой :)
Ну, теперь в обоих CMP будет всё как надо.
                    Я всё так и сделал, но есть один нюанс. Реализация, как я говорил, не моя и там оказалось несколько CMP с очень похожими названиями и в БД таблицы тоже с похожими названиями и схожей структурой таблиц. То есть столбцы с одинаковыми названиями.
Так вот в таблице я поменял в которой надо, а файл .map.inc.php менял другой :)
Ну, теперь в обоих CMP будет всё как надо.
                «Спешат, спешат, а на спасибо и времени нет»

П.С. Где мой плюс? :)
                    
П.С. Где мой плюс? :)
                Я еще и коммент не туда залепил :) 
Стрелку апнул ;)
И еще раз, мерси боку!
                    Стрелку апнул ;)
И еще раз, мерси боку!
Сначала я думал, что проблема в типе данныхИменно. Фишка старого доброго (как говорит Иван Климчук) xPDO. Так что решение только одно — править схему.
                Можно же просто прописать нужный запрос в 
                    $this->query['where']            
                Я из 
Можешь рассказать подробнее, что ты имеешь в виду?
                    $this->queryберу значения для цикла. Можешь рассказать подробнее, что ты имеешь в виду?
                ты делаешь 
он всего лишь пишет в массив $this->query['where'] условия. Я тебе и предлагал туда записать условия напрямую в виде sql
                    $c->where($this->where);что делает метод where ?он всего лишь пишет в массив $this->query['where'] условия. Я тебе и предлагал туда записать условия напрямую в виде sql
И после обработки, в части кода, который сформирован методом 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Итог: в первом и втором запросе мы получили нужный результат. Так в чем же дело?
Фишка старого доброго (как говорит Иван Климчук) xPDOps. Вообщем не факт что твоя ошибка была в этом месте… совсем не факт. Просто при toSQL
выполняется parseBindings что приводит запрос к такому виду…
                Володя, спасибо!
Это очень ценная информация!
В итоге я еще обнаружил, что почти все поля по которым происходил поиск в схеме имели вместо 'phptype' => 'string', 'phptype' => 'text'
Я вообще теряюсь в догадках, как у заказчика это всё работало раньше, при таких косяках в коде.
Дело в том, что сайт был заражен и его как-то кто-то починил, после чего перестала работать система учета. Хоть заново всё пиши.
                    Это очень ценная информация!
В итоге я еще обнаружил, что почти все поля по которым происходил поиск в схеме имели вместо 'phptype' => 'string', 'phptype' => 'text'
Я вообще теряюсь в догадках, как у заказчика это всё работало раньше, при таких косяках в коде.
Дело в том, что сайт был заражен и его как-то кто-то починил, после чего перестала работать система учета. Хоть заново всё пиши.
                В xPDO нет типа «text» для phptype. dbtype может быть «text», а phptype должен быть равен «string» для char, varchar, text полей. Типы отличные от «string», «password», «date», «datetime», «timestamp», «time», «json», «array» приводятся к integer.            
                    
                В том и был прикол :)            
                    
                            Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.