Сортировка и гибкая выборка по комментариям
После моих неудачных попыток приджойнить на лету нужное мне количество комментариев и сортировать по ним, пришлось идти другим путём.
Минусы джойна не давали нормально работать:
Итак, всё по порядку:
1. Создаём расширенное поле в БД
Создаём в таблице modx_site_content новое поле ext_comments:
2. Создаём плагин для нового поля
Приведу сразу мой сокращённый плагин с примером нескольких расширенных полей:
3. Создаём плагин для копирования количества комментариев в наше поле
Я создал плагин, реагирующий на любые действия с комментариями (события OnCommentDelete, OnCommentPublish, OnCommentRemove, OnCommentSave, OnCommentUndelete, OnCommentUnpublish):
4. Импортируем все существующие уже комментарии
Открываем компонент Console и вбиваем туда код для импорта количества комментариев в наше поле ext_comments:
5. Исправляем вызовы сниппетов и чанков
Теперь уже можно указать новое поле в вызова сниппетов для ограничение выборки по ним и сортировки.
Вот сокращённый пример сниппета (феном):
В чанках тоже везде используем плейсхолдер ext_comments (например {$ext_comments} для фенома)
===================================================
Ура! Так и хочется похлопать в ладоши — у меня наконец-то всё работает именно так как мне нужно и без глюков!
████▐▐▐██████████
███▐▐▐▐███▌▌▌████
███───▐▌██▌▌▌▌███
███▄──▄▄█▐▌───███
█████████▄▄──▄███
Теперь можно и чайку попить...
───))░░░((
──((░-:¦:-░))
───))░░((
─█▀▀▀▀▀█▄░
─█░░░░░█─█
─▀▄▄▄▄▄▀▀░
Меня результат устроил, хотя может быть можно всё и более элегантно сделать… =)
Минусы джойна не давали нормально работать:
- Невозможность выбрать только тикеты, у которых комментариев >= 10
- Невозможность подсчитать только комментарии первого уровня (в моём случае это количество вопросов без ответов) и сортировать по ним
- При загрузке страницы и при пролистывани через пагинацию подгружались разные тикеты и сортировались по разному.
- Приходилось выбирать все тикеты, и в чанке через условие прятать те, у которых комментариев < 10
- Отсюда приходилось и пагинацию делать на костылях
- Создаём расширенное поле в БД (можно и тв-шку использовать, но так оптимальнее)
- Создаём плагин для нового поля (или дописываем существующий, если расширенные поля уже имеются).
- Создаём плагин для копирования количества комментариев в наше созданное поле с учётом нужных нам условий выборки.
- Импортируем все существующие уже комментарии
- Исправляем вызовы сниппетов и чанков
Итак, всё по порядку:
1. Создаём расширенное поле в БД
Создаём в таблице modx_site_content новое поле ext_comments:
- Тип: INT
- Длина: 10
- По умолчанию: 0
- Атрибуты: UNSIGNED
2. Создаём плагин для нового поля
Приведу сразу мой сокращённый плагин с примером нескольких расширенных полей:
<?php
switch ($modx->event->name) {
case 'OnMODXInit':
// Загружаем поля в модель ресурса
$modx->map['modResource']['fields']['ext_hot'] =
$modx->map['modResource']['fields']['ext_vip'] =
$modx->map['modResource']['fields']['ext_comments'] =
0;
$modx->map['modResource']['fieldMeta']['ext_hot'] =
$modx->map['modResource']['fieldMeta']['ext_vip'] =
array(
'dbtype' => 'tinyint',
'precision' => 1,
'attributes' => 'unsigned',
'phptype' => 'integer',
'default' => 0,
);
// Наше поле
$modx->map['modResource']['fieldMeta']['ext_comments'] =
array(
'dbtype' => 'int',
'precision' => 10,
'attributes' => 'unsigned',
'phptype' => 'integer',
'default' => 0,
);
break;
case 'OnDocFormSave':
// Сохраняем ТВ в поле таблицы ресурса
$resource->ext_hot = $resource->getTVValue('hot');
$resource->ext_vip = $resource->getTVValue('vip');
$resource->save();
break;
}
Я привёл пример с 3-мя полями и синхронизацией с ТВ. Наше поле ext_comments не нуждается в тв-шке, оно автономно3. Создаём плагин для копирования количества комментариев в наше поле
Я создал плагин, реагирующий на любые действия с комментариями (события OnCommentDelete, OnCommentPublish, OnCommentRemove, OnCommentSave, OnCommentUndelete, OnCommentUnpublish):
<?php
$obj = $object->toArray();
$thread = $obj['thread'];
$result = $modx->query("SELECT resource, comments FROM modx_tickets_threads WHERE id = '{$thread}'");
$row = $result->fetch(PDO::FETCH_ASSOC);
$resource = $row['resource'];
$comments = $row['comments'];
$result2 = $modx->query("SELECT parent FROM modx_site_content WHERE id = '{$resource}'");
$row2 = $result2->fetch(PDO::FETCH_ASSOC);
$parent = $row2['parent'];
// Посчёт только ответов в нужном нам разделе (комментарии 1-го уровня)
if($parent == 364375) {
$q = $modx->prepare("SELECT id FROM modx_tickets_comments WHERE thread = '{$thread}' AND parent = 0 AND published = 1");
$q->execute();
$r = $q->fetchAll(PDO::FETCH_ASSOC);
$comments = count($r);
}
if($resource&&$comments) {
$q_upd = $modx->prepare("UPDATE modx_site_content SET ext_comments = '{$comments}' where id ='{$resource}'");
$q_upd->execute();
}
// $modx->log( xPDO::LOG_LEVEL_ERROR, "RES - COM - PAR: ".$resource.", ".$comments.", ".$parent );
4. Импортируем все существующие уже комментарии
Открываем компонент Console и вбиваем туда код для импорта количества комментариев в наше поле ext_comments:
<?php
$q = $modx->prepare("SELECT id, resource, comments FROM modx_tickets_threads WHERE comments != '0'");
$q->execute();
$r = $q->fetchAll(PDO::FETCH_ASSOC);
print "<b>Всего: ".count($r)."</b>
";
foreach($r as $row){
$thread = $row['id'];
$resource = $row['resource'];
$comments = $row['comments']; // количество комментариев уже есть в ветке
$result2 = $modx->query("SELECT parent FROM modx_site_content WHERE id = '{$resource}'");
$row2 = $result2->fetch(PDO::FETCH_ASSOC);
$parent = $row2['parent'];
// Посчёт только ответов (комментарии 1-го уровня)
if($parent == 364375) {
$q = $modx->prepare("SELECT id FROM modx_tickets_comments WHERE thread = '{$thread}' AND parent = 0 AND published = 1");
$q->execute();
$r = $q->fetchAll(PDO::FETCH_ASSOC);
$comments = count($r);
}
if($resource&&$comments) {
$q_upd = $modx->prepare("UPDATE modx_site_content SET ext_comments = '{$comments}' where id ='{$resource}'");
$q_upd->execute();
}
print $resource." - ".$comments." - ".$parent."
";
}
$memory = round(memory_get_usage(true)/1024/1024, 4).' Mb';
print "
***********************************************
<div>Memory: {$memory}</div>";
$totalTime= (microtime(true) - $modx->startTime);
$queryTime= $modx->queryTime;
$queryTime= sprintf("%2.4f s", $queryTime);
$queries= isset ($modx->executedQueries) ? $modx->executedQueries : 0;
$totalTime= sprintf("%2.4f s", $totalTime);
$phpTime= $totalTime - $queryTime;
$phpTime= sprintf("%2.4f s", $phpTime);
print "<div>TotalTime: {$totalTime}</div>";
5. Исправляем вызовы сниппетов и чанков
Теперь уже можно указать новое поле в вызова сниппетов для ограничение выборки по ним и сортировки.
Вот сокращённый пример сниппета (феном):
{set $results = $_modx->runSnippet('!pdoPage', [
'element' => 'getTickets',
'tpl' => 'tpl.consultant.card',
'sortdir' => 'DESC',
'sortby' => 'ext_comments',
'includeContent' => 1,
'showHidden' => 1,
'limit' => 10,
'parents' => 364375,
'totalVar' => 'totalVar',
'where' => '{ "ext_comments:>=":"10" }',
'tplPageWrapper' => '@INLINE <div class="pagination uk-margin-remove"><ul class="pagination uk-margin-remove">{$first}{$prev}{$pages}{$next}{$last}</ul></div>',
'loadModels' => 'ms2gallery',
'leftJoin' => '{
"95x125": { "class":"msResourceFile","alias":"95x125", "on": "95x125.resource_id = Ticket.id AND 95x125.path LIKE \'%/95x125/\' AND 95x125.rank=0" }
}',
'select' => '{
"Ticket":"*",
"95x125":"95x125.url as 95x125"
}',
])}
Тут я выбираю только лучшие тикеты (те у которых комментариев >= 10). Также я выкинул из джойна мои предыдущие опыты с подсчётом комментариев на лету и остались только подключение фотки из ms2Gallery.В чанках тоже везде используем плейсхолдер ext_comments (например {$ext_comments} для фенома)
===================================================
Ура! Так и хочется похлопать в ладоши — у меня наконец-то всё работает именно так как мне нужно и без глюков!
████▐▐▐██████████
███▐▐▐▐███▌▌▌████
███───▐▌██▌▌▌▌███
███▄──▄▄█▐▌───███
█████████▄▄──▄███
Теперь можно и чайку попить...
───))░░░((
──((░-:¦:-░))
───))░░((
─█▀▀▀▀▀█▄░
─█░░░░░█─█
─▀▄▄▄▄▄▀▀░
Меня результат устроил, хотя может быть можно всё и более элегантно сделать… =)
Комментарии: 7
Мощно
Спасибо, решил: зачем труду пропадать — другим пригодится, да и себе чтобы сохранилось. ;)
Я ничего не понял, а где глянуть рабочий пример для понимания дела?
И как ты себе это представляешь?
Я не могу тебе дать доступ к сайту клиента, над которым я работаю. А если покажу сайт внешне, там можно будет увидеть только то, что описано в этом топике: сортировку по количеству комментариев + выборку тех тикетов, у которых комментариев больше чем 10.
Это же пошаговая инструкция! Может быть скажешь что именно не понимаешь? Попробую объяснить…
Я не могу тебе дать доступ к сайту клиента, над которым я работаю. А если покажу сайт внешне, там можно будет увидеть только то, что описано в этом топике: сортировку по количеству комментариев + выборку тех тикетов, у которых комментариев больше чем 10.
Это же пошаговая инструкция! Может быть скажешь что именно не понимаешь? Попробую объяснить…
т.е. вся суть дела это сортировка комментариев?
Нет, не комментариев, а сортировка и выборка ТИКЕТОВ в зависимости от количества комментариев.
Также в статье приводится пример сортировки только учитывая количество комментариев первого уровня не считая дочерних и наоборот.
Также в статье приводится пример сортировки только учитывая количество комментариев первого уровня не считая дочерних и наоборот.
Ага, понял. Спасибо =)
Я просто пытался найти суть/цель/назначение в начале статьи.
Я просто пытался найти суть/цель/назначение в начале статьи.
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.