И снова здравствуйте, банда креативных программистов, кодирующих дизайнеров и БД-админов, способных оглушить всю рыбу в озере одним лишь SQL-запросом. В робких попытках погреться в лучах чужой славы, попытаюсь затесаться в ваши ряды и выложу в качестве взноса очередной рецепт из кухни народов MODx.

C недавним рассказом о выборе форума на самом выборе (лично для меня) была поставлена точка. Да и что продолжать, если все работает, устраивает меня, заказчика и посетителей сайта? Как выяснилось, устраивает не все. При использовании форума вскрылся маленький, но очень досадный глюк. Пользователь, создавший пост в теме форума, наделен властью редактировать и удалять свою запись. Правки проходили гладко, но вот при попытке удаления записи MODx выбрасывал сообщение об ошибке примерно такого содержания:

« Execution of a query to the database failed - Incorrect integer value: 'posts_count-1' for column 'posts_count' at row 1 »
SQL: UPDATE `mybase`.`mybase_myforum_topics` SET posts_count='posts_count-1',last_post_at='1280175316',last_post_user_id='8' WHERE id = 5

Тем не менее, при следующей попытке войти в ветку форума, удаляемой записи уже не было. Насторожил нюанс – хотя пост исчезал, количество записей, указываемое в теме на форуме, оставалось прежним. Не будучи знатоком PHP и SQL, можно все-таки догадаться о причинах таких возмущений со стороны движка. Все дело в том, что вычисляемое выражение 'posts_count-1' заключено в апострофы (кавычки). Возможно, такие вычисления поддерживаются версиями MySQL, отличными от моей, но я-то хочу чтобы все работало здесь и сейчас, именно данном сервере, без переустановок софта. Ну и ладно. Берем мясницкий нож и с немытыми руками лезем в сниппет. Степень кривизны рук не имеет значения.

Поскольку префикс, имя базы и таблицы могут меняться, искать нужное место в сниппете по тексту SQL-запроса бесполезно. Давайте-ка попробуем найти именно оскандалившийся кусочек ‘posts_count-1’. Заходим в папку, где лежат файлы сниппета (“…/siteroot/assets/snippets/myforum/”) и ищем файл, в котором есть такая строка символов. Задача облегчается, когда находится всего один такой файл: «myforum_db.class.inc.php». Откройте его в любом текстовом редакторе. Найдя в нем нужное место (в функции «removePost»), читаем строку кода:

$modx->db->update( 
array('posts_count' => 'posts_count-1', 
'last_post_at' => $newLastRow['created_at'], 
'last_post_user_id' => $newLastRow['author_id']), 
$modx->getFullTableName('myforum_topics'), 
'id = '.$topicId
);

Вот оно. Именно здесь вычисляемое выражение заключается в кавычки. Править все ручками и выдумывать велосипед не интересно, поэтому включаем думалку. Где еще используется похожий код? Не думайте! Вы можете устать! Я и так скажу – он находится несколькими строками выше, в функции «addNewPost». Заметьте, исполнение этой функции не вызывает ошибки, хотя поле 'posts_count' обновляется, разница лишь в знаке операции: вместо вычитания единицы, функция прибавляет ее к имеющемуся значению. Хм… Нет, есть еще отличие. Операция производится не функцией MODx, а непосредственно SQL-запросом, вот так:

$modx->db->query('
UPDATE
'.$modx->getFullTableName('myforum_topics').'
SET
posts_count = posts_count+1,
last_post_at = '.time().',
last_post_user_id = '.intval($fields['author_id']).'
WHERE
id = '.intval($fields['topic_id']).'
LIMIT 1'
);

Копируем этот фрагмент функции, вставляем его в «removePost», и вносим исправления по аналогии с исходным текстом. В результате получается что-то вроде этого:

$modx->db->query('
UPDATE
'.$modx->getFullTableName('myforum_topics').'
SET
posts_count = posts_count-1,
last_post_at = '.$newLastRow['created_at'].',
last_post_user_id = '.$newLastRow['author_id'].'
WHERE
id = '.$topicId.'
LIMIT 1'
);

На этом месте я прекратил свое криворукое кодирование и отлучился на перекур. Впереди меня поджидали зловещие глюки, роковые баги и страшные сообщения от парсера. Курил я неторопливо, так что они меня, наверное, не дождались. По крайней мере, когда я вернулся за компьютер, ошибок не наблюдалось. Все работало гладко, количество сообщений на форуме подсчитывалось правильно, а отдельные наглые комменты в форуме удалялись без шума, пыли и претензий насчет «Incorrect integer value». Пользуйтесь на здоровье.

P.S. Наглый удаляемый коммент – этот тот, который не подтверждает мою точку зрения.

P.P.S. Комментируйте, друзья, не стесняйтесь :)

Автор статьи: Александр Поляков, lecosson@mail.ru