Бетон5 Фильтр SQL
Я пытаюсь изменить плагин Concrete5, который отправляет пользователям предупреждение по электронной почте, когда срок их подписки истекает. Он работает, отфильтровывая пользователей, которые уже были уведомлены в первую очередь, а затем выбирает пользователей, чьи подписки на сегодняшний день имеют заданное количество дней (emailOnExpirationDays) от даты истечения срока действия (expirationDate).
Моя проблема в том, что мне нужно иметь возможность уведомлять пользователей 3 раза, а не один раз. Я хотел бы уведомить их за 30 дней, за 5 дней и за 1 день. Моим первым препятствием является фильтрация только тех пользователей, которые были уведомлены в течение 5 дней (не были умышленно уведомлены 25 дней назад). Как я могу изменить PHP и SQL ниже для достижения этой цели? Закомментированный код - это то, что я пробовал. Информация о функции фильтра находится здесь.
Коллекция создается здесь:
$expiringTxns = new LMemTxnList();
$expiringTxns->filterByProductWithExpirationEmailsThatShouldBeWarned();
......
public function filterByProductWithExpirationEmailsThatShouldBeWarned() {
$this->setupProductExpirationQueries();//displays all with account
//we haven't already sent out an expiration warning or, for that matter, a notice
$this->filter('notifiedDate', null);
$this->filter('warnedDate', null); //Caitlin commented out to allow more than one warning
//$this->filter('warnedDate', '!= BETWEEN DATE_SUB(NOW(), INTERVAL 5 DAY) AND NOW()');
// the emailOnExpirationDays has been properly configured
$this->filter('emailOnExpirationDays', null, '!=');
$this->filter('emailOnExpirationDays', 0, '>');
//the expirationDate - warning is between 5 days ago (don't want to send a bunch of emails) and now
// the warning code should be getting run after the notice code, so we shouldn't have to worry about 3 day warnings and sending warning and notice at the same time
$this->filter(null, 'DATE_SUB(expirationDate, INTERVAL emailOnExpirationDays DAY) BETWEEN DATE_SUB(NOW(), INTERVAL 5 DAY) AND NOW()');
//$this->filter(null, 'DATE_SUB(expirationDate, INTERVAL 30 DAY) BETWEEN DATE_SUB(NOW(), INTERVAL 5 DAY) AND NOW()');
}
protected function setupProductExpirationQueries() {
$this->addToQuery(' INNER JOIN LMemProducts ON txns.productID = LMemProducts.ID');
// the expiration date exists (some products don't expire)
$this->filter('expirationDate', null, '!=');
// we're supposed to send emails
$this->filter('emailOnExpiration', true);
$this->filter('emailOnExpirationDays', null, '!=');
$this->filter('emailOnExpirationDays', 0, '!=');
}
}
1 ответ
Следующий SQL должен работать для вас:
(
(DATE_SUB(expirationDate, 30 DAYS) BETWEEN DATE_SUB(NOW(), 3 DAYS) AND NOW())
OR
(DATE_SUB(expirationDate, 5 DAYS) BETWEEN DATE_SUB(NOW(), 3 DAYS) AND NOW())
OR
(DATE_SUB(expirationDate, 1 DAYS) BETWEEN DATE_SUB(NOW(), 3 DAYS) AND NOW())
)
AND
(DATE_ADD(warnedDate, 4 DAYS) <= NOW())
По сути, вы проверяете дату истечения срока действия минус период предупреждения между 3 днями назад и сейчас. Это позволяет небольшим (3 дня) всплескам в работе не запускаться. В частности, если срок действия истекает 15 марта, он вернет истину между 15 февраля (предположим, что это 30 дней) и 18 февраля. Но мы не хотим отправлять его несколько раз в течение этого периода (что может стать потенциальной проблемой, если задание может выполняться несколько раз в день), поэтому вы также должны проверить, что warnedDate по крайней мере 4 дня назад. Это хорошо сочетается с вашими периодами 30/5/1.
Чтобы поместить это в функцию filterBy...Warned(), вы должны удалить $this->filter('warnedDate', null);
линия, а затем один с DATE_SUB
, а затем вы добавите SQL в "напрямую":
$this->filter(null, "(
(DATE_SUB(expirationDate, 30 DAYS) BETWEEN DATE_SUB(NOW(), 3 DAYS) AND NOW())
OR
(DATE_SUB(expirationDate, 5 DAYS) BETWEEN DATE_SUB(NOW(), 3 DAYS) AND NOW())
OR
(DATE_SUB(expirationDate, 1 DAYS) BETWEEN DATE_SUB(NOW(), 3 DAYS) AND NOW())
)
AND
(DATE_ADD(warnedDate, 4 DAYS) <= NOW())");