Автоматическое обновление дат

Добрый день.

Суть вопроса.

На сайте есть каталог. Документы в нем выводятся с сортировкой по датам (сейчас createdon).

Нужно сделать так, чтобы эти даты как-то отслеживались и автоматически обновлялись через определенный промежуток времени, например, через месяц. Это должно происходить без участия админа.

Т.е. каждый документ через месяц автоматически подымается вверх, вроде он только что создан, еще через месяц — опят подымается, и т.д.

Прошу подсказать, как это можно сделать, желательно без крона.

Спасибо

26 комментариев

avatar
Все ресурсы расположены в таблице site_content
У каждого есть несколько разных полей с датами — pub_date, createdon и т.д. В зависимости от того, на какое из них завязана сортировка у вас, нужно их и обновлять.
Можно сделать плагин на любое событие, которое у вас часто возникает на сайте, перебрать все доки с датой, меньшей чем текущая, модифицировать нужное поле.
Примерно такое что-то. Выборку под себя поправьте, чтобы скажем менять только нужные шаблоны/доки и т.п.

$sql = "select * from $modx->getFullTableName('site_content')  WHERE FROM_UNIXTIME( createdon,  '%Y-%m-%d' ) < CURDATE()";
include_once(MODX_BASE_PATH."assets/lib/MODxAPI/modResource.php");
$data = $modx->db->makeArray($modx->db->query($sql));
foreach ($data as $el) {
    $doc = new modResource($modx);
    $doc->edit($el['id']);
	$doc->set('createdon','ТУТ НУЖНАЯ ДАТА В ФОРМАТЕ UNIXTIME');
    $doc->save(false,false);
}
  • 1px
  • +2
avatar
Спасибо, я примерно так и думал, для теста сделал для одного документа так
$table = $modx->getFullTableName('site_content');
$period = "432000"; //5 суток
$tek = time();
$res = $tek-$period;

$doc = $modx->getDocument($id);
$createdon = $doc['createdon'];
$template = $doc['template'];
	
$fields = array('createdon'  => $tek); 
if($res > $createdon && $template="7"){$modx->db->update($fields, $table, "id IN ($id)");}


Но потом понял, что если в выборке окажется несколько документов, то после обновления все они окажутся с одинаковыми датами, если вешать, например на OnWebPagePrerender, а посещаемость у молодого сайта стремится к нулю((

Или мои опасения беспочвенны?
avatar
Ну если ставить одинаковую дату, то да, так и будет. Но ведь можно даты и прибавлять, а не просто ставить всё одинаково? =)
$newDate = strtotime('+1 month',$oldDate);

Кстати, вообще-то можно всё сделать и средствами mySQL, но я с датами и update ненавижу работать, так что это уж сами.
avatar
Спасибо, подумаю над такой идеей, главное не прибавить лишнего, чтобы дата не оказалась из будущего))
avatar
Благодаря помощи 1px получился такой плагин
$e = &$modx->Event;
if ($e->name == "OnWebPageInit") {

$table = $modx->getFullTableName('site_content');
$period = "432000"; //5 суток
$tek = time();
$res = $tek-$period;
$template = "7";
$result = $modx->db->select("id,createdon", $table, "createdon < '".$res."' AND template = '".$template."'");
include_once(MODX_BASE_PATH."assets/lib/MODxAPI/modResource.php");
$data = $modx->db->makeArray($result);
foreach ($data as $el) {
    $doc = new modResource($modx);
    $doc->edit($el['id']);
	$news = ($el['createdon'])+$period;
        $doc->set('createdon',$news);
    $doc->save(false,true);
}
	
}

Но для полного счастья остались пару вопросов, если кто подскажет:

1. Есть какая-то возможность очищать кэш страниц одновременно с изменением даты? На случай если OnWebPageInit будет с чем то конфликтовать и все же придется ставить OnWebPagePrerender?

2. В админке EVO есть возможность установить дату публикации и дату отмены публикации — как EVO отслеживает эти даты? Или он тоже ждет, чтобы админ или посетитель сайта совершит какое-то событие, чтобы по этому событию сделать нужное действие. Или там какой то таймер установлен и нужные действия совершаются независимо ни от кого?
  • paic
  • 0
avatar
Ну ёлки же =)
$doc->save(false,true);
итак чистит кэш
avatar
Дык, в том то и дело, что елки — с моделями у меня пока совсем туго, хотя замечаю что все чаще в постах мелькают именно они, так что предстоит еще засаживаться за уроки.

Пользуясь случаем, а как сделать, если $period на разных страницах разный?

Т.е. на странице есть параметр TV c названием period типа radio вида
10 суток==4320000||20 суток==8640000||30 суток==3592000 и админ каждой странице назначает свой период обновления
avatar
мне кажется, все это можно сделать один запросом на update с джойном двух таблиц (контент и значения тв) где разница между текущей датой и createdon будет больше значения тв period и соответственно простановкой новой createdon в time() (текущее время) ну или в сумму createdon+period :)
Комментарий отредактирован 2019-08-08 19:37:05 пользователем webber
avatar
Спасибо, так и буду делать, я как малознакомый с моделями думал может там есть какие инструменты.
avatar
Или он тоже ждет, чтобы админ или посетитель сайта совершит какое-то событие, чтобы по этому событию сделать нужное действие
При каждом заходе на фронт сайта, если сайт не выключен, проверяются. Сама дата наступления следующей проверки хранится в файле assets/cache/sitePublishing.idx.php. Т.е. если наступила эта дата, то соответственно все неопубликованные, у которых наступила дата публикации — публикуются, а все опубликованные, у которых она закончилась — снимаются с публикации. Соответственно, при построении нового кэша формируется новая дата проверки в файлик из минимальных будущих даты начала публикации/даты окончания публикации.
avatar
Спасибо за разъяснения
avatar
На самом деле, если на странице есть ТВ с предустановленными периодами (админ выбирает сам через сколько суток какую страницу обновлять), делается аналогично, как и подсказал webber , через JOIN. Получилось так
$e = &$modx->Event;
if ($e->name == "OnWebPageInit") {
	
$t1 = $modx->getFullTableName('site_tmplvar_contentvalues');
$t2 = $modx->getFullTableName('site_content');

$tek = time();
	
$result = $modx->db->query("SELECT $t1.*, $t2.* FROM $t1 LEFT JOIN $t2 ON $t1.contentid = $t2.id WHERE $t1.tmplvarid='19' AND createdon<($tek-value)");
include_once(MODX_BASE_PATH."assets/lib/MODxAPI/modResource.php");
$data = $modx->db->makeArray($result);
foreach ($data as $el) {
    $doc = new modResource($modx);
    $doc->edit($el['id']);
	$period =($el['value']);
	$news = ($el['createdon'])+$period;
    $doc->set('createdon',$news);
    $doc->save(false,true);
}
	
}


Здесь ТВ c id=19 есть этот параметр для установки периода обновления даты создания страницы.

Всем спасибо за помощь.
  • paic
  • 0
avatar
Может все-таки через update попробовать без привлечения modResource($modx) и foreach. Ведь таким образом мы получаем все данные по всем ресурсам, которые хотим отредактировать — которые нам совершенно не нужны. Типа такого
$modx->db->query("UPDATE $t2 LEFT JOIN $t1 ON $t1.contentid = $t2.id SET $t2.createdon=($t2.createdon+$t1.value) WHERE $t1.tmplvarid='19' AND $t2.createdon<($tek-$t1.value)");

синтаксис, в случае чего, скорректировать только :)
avatar
Это все потому, что у меня подход, до того как прочитал Ваш пример, был другой:
1. Вытащить (получить), проверить — что все вытащилось правильно.
2. Совершить какое-то действие с тем что вытащил п.1.

А Ваш пример заставил посмотреть на жизнь по-новому — все можно сделать не выходя из (т.е. внутри) sql. Я раньше никогда так не делал, обязательно возьму на вооружение))

По modResource — это скорее всего от недопонимания — я считал, что если в селекте я уже вытащил что-то и в result получилось, к примеру, 3 ресурса, то дальше они эти 3 и будут обрабатываться, а не все как Вы указали.

Спасибо.
avatar
нет, вы сначала селектом вытащили все данные из обоих таблиц, а потом просто взяли оттуда всего одно значение — id и по нему заново получили для каждого документа и все данные из таблицы и все данные по тв с учетом значений по-умолчанию и т.п.
$doc->edit($el['id']);

причем в каждом шаге цикла потом еще удалили и по-новой сформировали весь файл кэша :)
avatar
да уж((
avatar
одно плохо — значения по умолчанию в базу не записываются ((
avatar
Какие такие значения по-умолчанию? :) Они вроде и в предыдущих вариантах кода нигде и никак не учитывались :) Для этого надо джойнить третью таблицу site_tmplvars
avatar
Да, мой прохлоп, вернее изначально ничего этого не предусматривалось, аппетит пришел позже))
И если добавлять в джойн таблицу site_tmplvars, то и команду SET наверное прописывать через IF или CASE, чтобы дважды не обновить один и тот же ресурс, да и where будут разные для случая есть ТВ в site_tmplvar_contentvalues или его там нет (т.е. значение по умолчанию).
avatar
В приведенном примере вынести за пределы foreach инициализацию класса
$doc = new modResource($modx);

и очистку кэша (зачем его чистить после каждого обновления — достаточно одного раза в конце:)
т.е. внутри цикла
$doc->save(false,false);

а уже после цикла
$modx->clearCache("full");
avatar
Спасибо
avatar
Скоро мы тут вызовем дух MySQL, он придёт и раздаст нам всем по ушам.
  • 1px
  • 0
avatar
а нам то за что? ©
avatar
Еще один вариант, теперь уже и значения по-умолчанию в периоде обновления тоже перезаписывают дату создания ресурса
$e = &$modx->Event;
if ($e->name == "OnWebPageInit") {
	
$t1 = $modx->getFullTableName('site_tmplvar_contentvalues');
$t2 = $modx->getFullTableName('site_content');
$t3 = $modx->getFullTableName('site_tmplvars');
$t4 = $modx->getFullTableName('site_tmplvar_templates');

$tek = time();
	
$modx->db->query("UPDATE $t2 
LEFT JOIN $t1 
ON $t1.contentid = $t2.id 
LEFT JOIN $t4 
ON $t2.template = $t4.templateid 
LEFT JOIN $t3 
ON $t4.tmplvarid = $t3.id
SET $t2.createdon = CASE
WHEN $t2.createdon < ($tek - $t1.value) AND $t1.value > '1' THEN ($t2.createdon + $t1.value)
WHEN $t2.createdon < ($tek - $t3.default_text) THEN ($t2.createdon + $t3.default_text)
ELSE $t2.createdon END
WHERE $t1.tmplvarid = '19' AND $t3.id = '19'
");
	
}

ТВ с id=19 — это период обновления, тип radio, возможные значения Нет==1||1 сутки==86400||10 суток==864000||…

Еще раз спасибо всем помогавшим, включая доброго духа MySQL))
  • paic
  • 0
avatar
Мне кажется, можно попробовать добавить еще условие, а не обновлять вообще все createdon
AND $t2.createdon<($tek-IFNULL($t1.value, $t3.default_text)");

+ добавить условие по шаблону (вряд ли нужно обновлять все шаблоны)
AND $t2.template=5
— например
Ну и не забыть после запроса скинуть кэш, если что-то поменялось:)
if ($modx->db->getAffectedRows() > 0) {
    $modx->clearCache("full");
}


В общем, надо на живой базе посмотреть разные варианты, чтобы понять какой эффективнее :)
avatar
Спасибо, поэкспериментирую. AND template я изначально прописывал, но потом посчитал, что раз у меня уже есть ограничение по ТВ=19, а он подключен только к одному шаблону, то этого будет достаточно. Ну и убрал как «избыточное».
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.