cyrax_02 02 мая 2015 0 16
Пример запроса:
$query = $modx->newQuery('modResource');
$query->select(array('modResource.id AS resourceId'));
$query->innerJoin('modTemplateVarTemplate', 'TVValues', array('TVValues.contentid = modResource.id'));
$query->where(array('TVValues.tmplvarid:=' => 8));
Получаем SQL со строкой '8', а не числом 8:
SELECT modResource.id AS resourceId
FROM `modx_site_content` AS `modResource`
JOIN `modx_site_tmplvar_templates` `TVValues` ON TVValues.contentid = modResource.id
WHERE `TVValues`.`tmplvarid` = '8'
Проверил разные варианты. Вывод такой: xPDO не получает мета-информацию о присоединённых таблицах (хотя парсит их отлично). Поэтому, все поля этих таблиц он приводит к строковому типу.

Как заставить xPDOQuery получать информацию о типах данных присоединяемых таблиц?
16 комментариев
Fi1osof1
Fi1osof 02 мая 2015г в 14:14 #
Заставить — никак. Он не может знать является ли указанный алиас алиасом xPDO-объекта или просто алиас временной таблицы (на самом деле может, но, думаю, не будет этого делать, слишком много тонкостей и вариантов здесь). А вот сформировать правильный запрос можно.
$query->innerJoin('modTemplateVarTemplate', 'TVValues', "TVValues.contentid = modResource.id AND TVValues.tmplvarid = 8");


Если уж очень хочется именно в where засунуть условие, то так:
$query->where(array('TVValues.tmplvarid = 8'));


P.S. И вероятно предполагалось modTemplateVarResource, а не modTemplateVarTemplate.
c
cyrax_02 02 мая 2015г в 14:41 #
P.S. И вероятно предполагалось modTemplateVarResource, а не modTemplateVarTemplate.
Да, верно.

Он не может знать является ли указанный алиас алиасом xPDO-объекта или просто алиас временной таблицы
Так ведь в методе innerJoin первым параметром передаётся имя xPDO-объекта, вторым псевдоним, третьим — условие с использованием этого псевдонима. Если название таблицы в составе условия совпадает с псевдонимом, указанным вторым параметром, то однозначно это псевдоним xPDO-объекта, указанного первым параметром. Иначе быть не может, поскольку в выборке не могут участвовать 2 таблицы с одинаковыми псевдонимами.

Т.е. алгоритм проверки должен быть таким:
1) если имя таблицы в условии совпадает с псевдонимом присоединяемой таблицы => это и есть присоединяемая таблица => типизируем как положено
2) если имя таблицы в условии не совпадает с псевдонимом присоединяемой таблицы => парсим поле как строковое (т.к. ситуация неопределённая)
И xPDO этой элементарной проверки почему-то не выполняет…

А вот сформировать правильный запрос можно.
Я просто пример привёл такой со стандартной таблицей. В этом примере — да, логически правильнее внести фильтрацию по TV в ON. Но во многих других случаях (в т.ч. и с участием собственных таблиц) дополнительные условия должны содержаться в WHERE. Особенно, если запрос большой и частично он строится в одних методах, частично — в других.

В любом случае, проблема имеет место, не зависимо от того, где присутствует условие — в WHERE или в ON.
Fi1osof1
Fi1osof 02 мая 2015г в 14:48 #
Если уж очень хочется именно в where засунуть условие, то так:
$query->where(array('TVValues.tmplvarid = 8'));

И xPDO этой элементарной проверки почему-то не выполняет…
Отправляйте свой PR в xPDO, не вопрос.
c
cyrax_02 02 мая 2015г в 14:48 #
Вообще, у меня в коде много десятков подобных запросов по всему коду. Всегда полагался на типизацию xPDO. А сейчас, похоже, придётся все запросы перешерстить. Странно, что все запросы выполнялись корректно… до сегодняшнего дня…

Всё-таки отказ от автоматической xPDO-типизации в условиях — не совсем хороший вариант. Хотя бы, те же самые операторы IN. Напрашивается такое решение: обёртка для join'ов, в которых:
а) вручную читаем мета-данные
б) определяем тип
в) корректируем тип поля в объекте xPDOQuery (query['joins'][...])

Здорово поможете, если навскидку состряпаете эту обёртку. Если нет — поковыряюсь сам…
Fi1osof1
Fi1osof 02 мая 2015г в 14:50 #
Вообще, у меня в коде много десятков подобных запросов по всему коду. Всегда полагался на типизацию xPDO. А сейчас, похоже, придётся все запросы перешерстить. Странно, что все запросы выполнялись корректно… до сегодняшнего дня…
У вас где-то запрос не так выполняется (имеется ввиду получаете не те результаты)? Мускул сам типизацию проведет, это вам не сортировка. Хотите более полный контроль над типами? — юзайте CAST, CONVERT и т.п.
Fi1osof1
Fi1osof 02 мая 2015г в 14:51 #
Здорово поможете, если навскидку состряпаете эту обёртку. Если нет — поковыряюсь сам…
Не вижу смысла. Не помогу с этим.
c
cyrax_02 02 мая 2015г в 15:24 #
У вас где-то запрос не так выполняется (имеется ввиду получаете не те результаты)? Мускул сам типизацию проведет, это вам не сортировка.

Именно. Сравнение числового поля со строковой константой всегда даёт false (в этом случае MySQL числовые значения поля приводит к строковому типу)
c
cyrax_02 02 мая 2015г в 15:28 #
Тьфу, что-то не то пишу. Должно нормально работать сравнение. Проверю ещё раз…
Fi1osof1
Fi1osof 02 мая 2015г в 15:38 #
Сравнение числового поля со строковой константой всегда даёт false (в этом случае MySQL числовые значения поля приводит к строковому типу)
Да, вы явно не то пишете. Все будет ОК работать. Это в сортировках может получиться, что '87' будет меньше чем '9', но 8 == '8'.
c
cyrax_02 02 мая 2015г в 16:25 #
Это в сортировках может получиться, что '87' будет меньше чем '9', но 8 == '8'.
И в условиях сравнения тоже.
Fi1osof1
Fi1osof 02 мая 2015г в 16:31 #
Больше/меньше — да, но равно/не равно — нет.
c
cyrax_02 02 мая 2015г в 16:42 #
Всё равно некошерно. Ладно, с TV понятно — если там сравнение на неравенство используется, нужно непосредственно прописывать условие в виде SQL. Но когда то же самое приходится делать с собственными типизированными таблицами — это уже извращение.
Fi1osof1
Fi1osof 02 мая 2015г в 16:49 #
Еще раз — шлите пуллреквесты, улучшайте работу MODX-а. Я вот шлю. На сегодня более 10% всех активных PR в MODX — мои. И вы можете приложить усилия, чтобы MODX стал лучше.
c
cyrax_02 02 мая 2015г в 17:13 #
На английском не очень получается. Впрочем, писал уже:
github.com/modxcms/revolution/issues/12307
ноль внимания…

Хотя в версии 2.3.3 они там логику чуть изменили (так, что в описанных в этой теме условиях ошибки больше не вылезали), но «корячность» этой логики сохранилась (а может, я её не понимаю). Так или иначе в 2.3.3 эти 2 ошибки по-прежнему иногда вылезают, но гораздо реже и при других условиях (при каких — неизвестно).

Что касается сабжа, то лучше я обёртку напишу. Так будет надёжнее.
Fi1osof1
Fi1osof 02 мая 2015г в 17:25 #
Issue — это только пожелания, обсуждения. Отправить готовый код — более предметно.
c
cyrax_02 02 мая 2015г в 17:49 #
Что касается сабжа, то лучше я обёртку напишу. Так будет надёжнее.
Нет. С разбегу не получится. Не 5 минут…

Логика должна быть такой. Перед выполнением метода prepare() запускается наша супер-функция (или метод), которая в объекте xPDOQuery делает следующее:
1) проходит по всем JOIN-таблицам и в их condition'ах корректирует ['condition']['bind']['type'], если он не соответствует модели таблицы
2) нестроковые условия по TV полям преобразовывает в их SQL-аналоги с использованием CAST'ов в зависимости от типа TV, задаваемого в modx_site_tmplvars
3) то же самое — для полей, участвующих в ORDER BY и HAVING

Тогда работа с xPDO станет сказкой…
А пока не горит. Нестроковые сравнения (< > <= >=) и сортировки по TV-полям и JOIN-полям оформляем в виде SQL с CAST'ами, всё остальное — оставляем как есть.
Авторизуйтесь или зарегистрируйтесь (можно через соцсети ), чтобы оставлять комментарии.