[РЕШЕНО] Мозгодробилка с $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.
В том и был прикол :)
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.