Вывести только тикеты с рейтингом больше нуля
1 300
Итак, если вам нужно вывести тикеты с рейтингом выше ноля, то эту задачу можно решить двумя способами. Первый для высоконагруженных проектов, второй для менее нагруженных.
Первый вариант (относительно сложный в реализации, но выигрывает по скорости при большой выборке ресурсов):
Далее:
Создаем плагин (допустим, customTicketRating) со следующим содержанием:
Теперь осталось только вызвать сниппет с нужным условием:
За решение благодарим modx.pro/users/kaminari/
Второй вариант более простой в реализации и подойдет, если вам нужно выбрать тикеты из относительно небольшого кол-ва ресурсов:
1. Создаем сниппет:
Первый вариант (относительно сложный в реализации, но выигрывает по скорости при большой выборке ресурсов):
- Заходите в phpmyadmin.
- Выбираете таблицу modx_site_content
- — Переходите в закладку «структура»
- — Внизу открывшегося окна нажимаете ОК (Добавить 1 поле в конец таблицы)
Имя: ticket_rating Тип: int Длина/значение: 10 По умолчанию: Как определено (0) Null: галочка
- Сохраняем
Далее:
Создаем плагин (допустим, customTicketRating) со следующим содержанием:
<?php
switch ($modx->event->name) {
case 'OnMODXInit':
$modx->loadClass('modResource');
$modx->map['modResource']['fields']['ticket_rating'] = 0;
$modx->map['modResource']['fieldMeta']['ticket_rating'] = array(
'dbtype' => 'int',
'precision' => 10,
'attributes' => '',
'phptype' => 'int',
'null' => true,
'default' => 0,
);
break;
case 'OnTicketVote':
if ($object->class == 'Ticket') {
if ($ticket = $modx->getObject('Ticket', $object->id)) {
$properties = $ticket->getProperties('tickets');
$rating = !empty($properties['rating'])
? $properties['rating']
: 0;
$ticket->set('ticket_rating', $rating + $object->value);
$ticket->save();
}
}
break;
}
«Вешаем» его на события OnTicketVote и OnMODXInit. Теперь наше новое поле воспринимается модксом и изменяется после каждого голосования за любой ресурс.Теперь осталось только вызвать сниппет с нужным условием:
[[!pdoPage?
&element=`getTickets`
&where=`{"ticket_rating:>": 1}`
]]
Важно: рейтинг начнет вычисляться только с последующих голосований за тикеты.За решение благодарим modx.pro/users/kaminari/
Второй вариант более простой в реализации и подойдет, если вам нужно выбрать тикеты из относительно небольшого кол-ва ресурсов:
1. Создаем сниппет:
<?php
$class = 'modResource';
$pdo = $modx->getService('pdoFetch');
$pdo->addTime('pdoFetch загружен');
$options = array(
'cacheTime' => '10',
);
if (!$output = $pdo->getCache($options)) {
$pdo->addTime('Кэш не найден, генерируем данные');
$pdo->setConfig(array(
'class' => $class,
'select' => 'id, properties',
'limit' => 0,
'parents' => 0,
'return' => 'data'
));
$data = $pdo->run();
$output = array();
foreach ($data as $row) {
if (isset($row['properties']['tickets']['rating']) && $row['properties']['tickets']['rating'] > 1) {
$output[] = $row['id'];
}
}
$output = implode(',', $output);
$pdo->setCache($output, $options);
$pdo->addTime('Данные сохранены в кэш');
} else {
$pdo->addTime('Данные загружены из кэша');
}
$pdo->addTime('Данные получены');
// print $pdo->getTime();
return $output;
Здесь указано, сколько в секундах хранить кеш:$options = array(
'cacheTime' => '10',
);
А здесь — больше какого значения должен быть рейтинг у ресурсов:if (isset($row['properties']['tickets']['rating']) && $row['properties']['tickets']['rating'] > 1) {
$output[] = $row['id'];
}
2. Передаем результат его работы в getTickets или другой используемый сниппет, который принимает параметр resources. Например:[[getTickets?
&parents=`0`
&resources=`[[имя сниппета с кодом выше]]`
]]
За вариант благодарим modx.pro/users/1801/ Комментарии: 23
Класс. Идея Василию. Добавить раздел «вопросы за 300». С автоматической отправкой победителю выигрыша ) и 10% на развития портала.
Я готов играть в эту игру. :) Лишь бы результат был.
Насколько я понял, раньше в тикетах было присоединение таких данных к выборке по-умолчанию, но создавало проблемы с производительностью — поэтому от нее отказались.
Поэтому, вот этот вариант, пожалуй, самый правильный для хранения таких данных. А дальше дело только за
Поэтому, вот этот вариант, пожалуй, самый правильный для хранения таких данных. А дальше дело только за
&where=`{"ticket_rating:>": 1}`
Максим, я прошу прощения, не силен в этих символах. Я за копипаст и проверку на производительность debugParser'ом. Если у вас есть возможность, напишите «от» и «до» в комментариях и я готов заплатить. Благодарю!
— Заходите в phpmyadmin.
— Выбираете таблицу modx_site_content
— Переходите в закладку «структура»
— Внизу открывшегося окна нажимаете ОК (Добавить 1 поле в конец таблицы)
Имя: ticket_rating
Тип: int
Длина/значение: 10
По умолчанию: Как определено (0)
Null: галочка
(сохраняем)
Таким способом мы расширили дефолтную таблицу MODX'a со списком ресурсов. Далее:
— Создаем плагин (допустим, customTicketRating) со следующим содержанием:
Теперь осталось только вызвать сниппет с нужным условием:
Важно: рейтинг начнет вычисляться только с последующих голосований за тикеты.
— Выбираете таблицу modx_site_content
— Переходите в закладку «структура»
— Внизу открывшегося окна нажимаете ОК (Добавить 1 поле в конец таблицы)
Имя: ticket_rating
Тип: int
Длина/значение: 10
По умолчанию: Как определено (0)
Null: галочка
(сохраняем)
Таким способом мы расширили дефолтную таблицу MODX'a со списком ресурсов. Далее:
— Создаем плагин (допустим, customTicketRating) со следующим содержанием:
<?php
switch ($modx->event->name) {
case 'OnMODXInit':
$modx->loadClass('modResource');
$modx->map['modResource']['fields']['ticket_rating'] = 0;
$modx->map['modResource']['fieldMeta']['ticket_rating'] = array(
'dbtype' => 'int',
'precision' => 10,
'attributes' => '',
'phptype' => 'int',
'null' => true,
'default' => 0,
);
break;
case 'OnTicketVote':
if ($object->class == 'Ticket') {
if ($ticket = $modx->getObject('Ticket', $object->id)) {
$properties = $ticket->getProperties('tickets');
$rating = !empty($properties['rating'])
? $properties['rating']
: 0;
$ticket->set('ticket_rating', $rating + $object->value);
$ticket->save();
}
}
break;
}
и включаем его на события OnTicketVote и OnMODXInit. Теперь наше новое поле воспринимается модксом и изменяется после каждого голосования за любой ресурс.Теперь осталось только вызвать сниппет с нужным условием:
[[!pdoPage?
&element=`getTickets`
&where=`{"ticket_rating:>": 1}`
]]
Важно: рейтинг начнет вычисляться только с последующих голосований за тикеты.
А для чего создавать отдельное поле для хранения этого значения у каждого ресурса. Разве тикеты не хранят его по дефолту?
Хранят, в поле properties вместе с остальными кастомными данными
То есть, по этому полю сортировка будет быстрее?
Нет, сортировка по данным в поле properties не реализована, и реализовывать ее, нет смысла, потому что данные в базе хранятся в json формате.
Владимир, я не про поле properties. В комментариях ниже уже увидел, что сортировка по вашему полю будет быстрее.
На самом деле, если объединить мое решение и решение Максима Кузнецова, скорость будет еще выше. Насколько наши решения отличаются по скорости сказать не могу, его решение, будет даже быстрее моего, если использовать для вывода сниппеты Василия. Я привел статистику выборки в которой участвуют 112 ресурсов.
Мое решение просто проще в реализации. Решение Максима для человека, который знает, что он делает и зачем.
Мое решение просто проще в реализации. Решение Максима для человека, который знает, что он делает и зачем.
Мне нужно выводить по сто ресурсов из 20.000.
Пробуйте, что Вам больше подходит, вот мое решение modx.pro/work/8017-display-only-tickets-with-a-rating-greater-than-one/#comment-56556, которое с реализацией кеша. Первое мое решение, точно не подходит. В скрипте, что я скинул, время кеша установлено в 10 секунд, можете больше поставить.
Хранят. Но только в общем поле properties в формате json:
(по этой же причине, например, очень нежелательно производить сортировку пользователей по extended-полям)
К слову, на modx.pro хранение рейтинга реализована примерно таким же способом.
{
"tickets": {
"disable_jevix":false,
"process_tags":false,
"rating":1,
"rating_plus":1,
"rating_minus":0
},
"ms2gallery": {
"media_source": "4"
}
}
Сортировка такого поля в естественном виде как минимум требует дополнительную выборку (как в примере ниже), а как максимум — весьма ощутимо проигрывает в скорости. (по этой же причине, например, очень нежелательно производить сортировку пользователей по extended-полям)
К слову, на modx.pro хранение рейтинга реализована примерно таким же способом.
Максим, спасибо за вариант. Напишите через личку куда отправлять деньги.
Деньги отправил. Спасибо!
Код сниппета, который вернет id ресурсов, рейтинг которых больше 0.
Передаешь результат его работы в getTickets или другой используемый сниппет, который принимает параметр resources. Например:
$class = 'modResource';
$pdo = $modx->getService('pdoFetch');
$pdo->setConfig(array(
'class' => $class,
'select' => 'id, properties',
'limit' => 0,
'parents' => 0,
'return' => 'data'
));
$data = $pdo->run();
$output = array();
foreach ($data as $row) {
if (isset($row['properties']['tickets']['rating']) && $row['properties']['tickets']['rating'] > 0) {
$output[] = $row['id'];
}
}
$output = implode(',', $output);
return $output;
Передаешь результат его работы в getTickets или другой используемый сниппет, который принимает параметр resources. Например:
[[getTickets?
&parents=`0`
&resources=`[[имя сниппета с кодом выше]]`
]]
Можно еще попробовать закешировать результаты сниппета, допустим, на 5-10 минут, чтобы уменьшить нагрузку, если сайт популярный. Для кеширования можно использовать методы getCache и setCache класса pdoTools.
Опробую в течение дня. Спасибо.
Если выбирать по шустрости, то этот вариант проигрывает. У Максима выбираются нужные тикеты за один запрос. А у Владимира выбираются все тикеты, а потом вторым шагом формируется массив с id нужных тикетов. А потом нужно еще раз зачитать с этими айдишниками. Если к варианту Максима добавить индекс по этому полю, то на больших объемах разница между этими вариантами будет очень заметна.
П.С. Ещё обрати внимание на ошибку. Класс должен быть Ticket, а не modResource.
П.С. Ещё обрати внимание на ошибку. Класс должен быть Ticket, а не modResource.
$class = 'Ticket';
И еще нужно учитывать удаленные и опубликованные.
modResource, тоже хранят рейтинг, смотря как это все реализовано на сайте. Мой вариант действительно, проигрывает по скорости, но он не требует написания плагинов, которые будут кастомизировать карты классов при инициализации MODX
Еще один вариант с использованием кеша:
Без кеша:
С кешем:
В итоге, не нужно ничего кастомизировать.
P.S. Насчет «И еще нужно учитывать удаленные и опубликованные» не соглашусь. Нам нужно вернуть id ресурсов которые имеют положительный рейтинг больше единицы. А уж решать выводить неопубликованные или удаленные, должен сниппет, которому передаются эти id, у него для этого есть логика
Еще один вариант с использованием кеша:
$class = 'modResource';
$pdo = $modx->getService('pdoFetch');
$pdo->addTime('pdoFetch загружен');
$options = array(
'cacheTime' => '10',
);
if (!$output = $pdo->getCache($options)) {
$pdo->addTime('Кэш не найден, генерируем данные');
$pdo->setConfig(array(
'class' => $class,
'select' => 'id, properties',
'limit' => 0,
'parents' => 0,
'return' => 'data'
));
$data = $pdo->run();
$output = array();
foreach ($data as $row) {
if (isset($row['properties']['tickets']['rating']) && $row['properties']['tickets']['rating'] > 1) {
$output[] = $row['id'];
}
}
$output = implode(',', $output);
$pdo->setCache($output, $options);
$pdo->addTime('Данные сохранены в кэш');
} else {
$pdo->addTime('Данные загружены из кэша');
}
$pdo->addTime('Данные получены');
// print $pdo->getTime();
return $output;
Без кеша:
0.0000479: xPDO query object created
0.0037699: Added selection of <b>modResource</b>: <small>SQL_CALC_FOUND_ROWS `id`, `properties`</small>
0.0000160: Processed additional conditions
0.0001459: Sorted by <b>modResource.id</b>, <b>ASC</b>
0.0001490: SQL prepared <small>"SELECT SQL_CALC_FOUND_ROWS `modResource`.`id`, `modResource`.`properties` FROM `modx_site_content` AS `modResource` ORDER BY modResource.id ASC "</small>
0.0010781: SQL executed
0.0000989: Total rows: <b>112</b>
0.0001380: Rows fetched
0.0003340: Returning raw data
0.0011299: Saved data to cache "default//055045fd31203f5f6ebcd7e3c93408e60bdf372a"
0.0000112: Данные сохранены в кэш
0.0000038: Данные получены
0.0074821: <b>Total time</b>
4 456 448: <b>Memory usage</b>
С кешем:
0.0001650: pdoFetch загружен
0.0002382: Retrieved data from cache "default//055045fd31203f5f6ebcd7e3c93408e60bdf372a"
0.0000088: Данные загружены из кэша
0.0000021: Данные получены
0.0004170: <b>Total time</b>
3 145 728: <b>Memory usage</b>
В итоге, не нужно ничего кастомизировать.
P.S. Насчет «И еще нужно учитывать удаленные и опубликованные» не соглашусь. Нам нужно вернуть id ресурсов которые имеют положительный рейтинг больше единицы. А уж решать выводить неопубликованные или удаленные, должен сниппет, которому передаются эти id, у него для этого есть логика
Спасибо! Мне понравились оба варианта. Ваш и modx.pro/users/kaminari/. Поэтому, готов заплатить обоим. Напишите в личку куда прислать деньги.
Брюки превращаются...Прикольно. Сначала задаешь вопросы, а потом переводишь их в пошаговые инструкции. ;)
Я плачу за ответы. :) И новичкам проще, когда ответ есть в шапке тикета. По себе знаю.
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.