Бетон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())");
Другие вопросы по тегам