| Current Path : /var/www/html/plugins/system/osmembershipreminder/src/Extension/ |
| Current File : /var/www/html/plugins/system/osmembershipreminder/src/Extension/Reminder.php |
<?php
/**
* @package Joomla
* @subpackage Membership Pro
* @author Tuan Pham Ngoc
* @copyright Copyright (C) 2012 - 2026 Ossolution Team
* @license GNU/GPL, see LICENSE.php
*/
namespace JoomDonation\MembershipPro\Plugin\System\Reminder\Extension;
use Joomla\CMS\Cache\Cache;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Event\DispatcherInterface;
use Joomla\Event\Event;
use Joomla\Event\SubscriberInterface;
use OSSolution\MembershipPro\Admin\Event\Reminder\BeforeSendingReminderEmails;
defined('_JEXEC') or die;
class Reminder extends CMSPlugin implements SubscriberInterface
{
use DatabaseAwareTrait;
public static function getSubscribedEvents(): array
{
return [
'onAfterRespond' => 'onAfterRespond',
];
}
/**
* Constructor.
*
* @param DispatcherInterface $dispatcher The dispatcher
* @param array $config An optional associative array of configuration settings
*/
public function __construct(DispatcherInterface $dispatcher, array $config)
{
parent::__construct($dispatcher, $config);
}
/**
* Register listeners
*
* @return void
*/
public function registerListeners()
{
if (!ComponentHelper::isEnabled('com_osmembership'))
{
return;
}
parent::registerListeners();
}
/**
* The sending reminder emails is triggered after the page has fully rendered.
*
* @return void
*
*/
public function onAfterRespond(Event $event): void
{
if (!$this->canRun())
{
return;
}
$bccEmail = $this->params->get('bcc_email', '');
$numberEmailSendEachTime = (int) $this->params->get('number_subscribers', 5);
$db = $this->getDatabase();
$query = $db->getQuery(true);
if (!trim($this->params->get('trigger_reminder_code', '')))
{
//Store last run time
$this->params->set('last_run', time());
$params = $this->params->toString();
$query->update('#__extensions')
->set('params=' . $db->quote($params))
->where('`element`="osmembershipreminder"')
->where('`folder`="system"');
try
{
// Lock the tables to prevent multiple plugin executions causing a race condition
$db->lockTable('#__extensions');
}
catch (\Exception $e)
{
// If we can't lock the tables it's too risk continuing execution
return;
}
try
{
// Update the plugin parameters
$result = $db->setQuery($query)->execute();
$this->clearCacheGroups(['com_plugins'], [0, 1]);
}
catch (\Exception $exc)
{
// If we failed to execite
$db->unlockTables();
$result = false;
}
try
{
// Unlock the tables after writing
$db->unlockTables();
}
catch (\Exception $e)
{
// If we can't lock the tables assume we have somehow failed
$result = false;
}
// Abort on failure
if (!$result)
{
return;
}
}
// Require library + register autoloader
require_once JPATH_ADMINISTRATOR . '/components/com_osmembership/loader.php';
$message = \OSMembershipHelper::getMessages();
PluginHelper::importPlugin('osmembership');
$app = $this->getApplication();
// Send first reminder
$rows = $this->getSubscriptionsToSendReminder(1, $numberEmailSendEachTime);
if (count($rows) > 0)
{
$reminderType = 'first_reminder';
$event = new BeforeSendingReminderEmails([
'rows' => $rows,
'reminderType' => $reminderType,
]);
$app->getDispatcher()->dispatch($event->getName(), $event);
\OSMembershipHelper::callOverridableHelperMethod('Mail', 'sendReminderEmails', [$rows, $bccEmail, 1]);
}
// Send second reminder
$rows = $this->getSubscriptionsToSendReminder(2, $numberEmailSendEachTime);
if (count($rows) > 0)
{
$reminderType = 'second_reminder';
$event = new BeforeSendingReminderEmails([
'rows' => $rows,
'reminderType' => $reminderType,
]);
$app->getDispatcher()->dispatch($event->getName(), $event);
\OSMembershipHelper::callOverridableHelperMethod('Mail', 'sendReminderEmails', [$rows, $bccEmail, 2]);
}
// Send third reminder
$rows = $this->getSubscriptionsToSendReminder(3, $numberEmailSendEachTime);
if (count($rows) > 0)
{
$reminderType = 'third_reminder';
$event = new BeforeSendingReminderEmails([
'rows' => $rows,
'reminderType' => $reminderType,
]);
$app->getDispatcher()->dispatch($event->getName(), $event);
\OSMembershipHelper::callOverridableHelperMethod('Mail', 'sendReminderEmails', [$rows, $bccEmail, 3]);
}
// Send fourth reminder if available
$fields = array_keys($this->getDatabase()->getTableColumns('#__osmembership_plans'));
if (in_array('send_fourth_reminder', $fields))
{
$rows = $this->getSubscriptionsToSendReminder(4, $numberEmailSendEachTime);
if (count($rows) > 0)
{
$reminderType = 'fourth_reminder';
$event = new BeforeSendingReminderEmails([
'rows' => $rows,
'reminderType' => $reminderType,
]);
$app->getDispatcher()->dispatch($event->getName(), $event);
\OSMembershipHelper::callOverridableHelperMethod('Mail', 'sendReminderEmails', [$rows, $bccEmail, 4]);
}
}
// Send fifth reminder if available
if (in_array('send_fifth_reminder', $fields))
{
$rows = $this->getSubscriptionsToSendReminder(5, $numberEmailSendEachTime);
if (count($rows) > 0)
{
$reminderType = 'fifth_reminder';
$event = new BeforeSendingReminderEmails([
'rows' => $rows,
'reminderType' => $reminderType,
]);
$app->getDispatcher()->dispatch($event->getName(), $event);
\OSMembershipHelper::callOverridableHelperMethod('Mail', 'sendReminderEmails', [$rows, $bccEmail, 5]);
}
}
// Send sixth reminder if available
if (in_array('send_sixth_reminder', $fields))
{
$rows = $this->getSubscriptionsToSendReminder(6, $numberEmailSendEachTime);
if (count($rows) > 0)
{
$reminderType = 'sixth_reminder';
$event = new BeforeSendingReminderEmails([
'rows' => $rows,
'reminderType' => $reminderType,
]);
$app->getDispatcher()->dispatch($event->getName(), $event);
\OSMembershipHelper::callOverridableHelperMethod('Mail', 'sendReminderEmails', [$rows, $bccEmail, 6]);
}
}
if (empty($message->subscription_end_email_subject))
{
return;
}
// Subscription end
$query->clear()
->select('a.*, b.title AS plan_title, b.recurring_subscription, b.number_payments, c.username')
->select(
'IF(b.send_subscription_end > 0, DATEDIFF(to_date, NOW()), DATEDIFF(NOW(), to_date)) AS number_days'
)
->from('#__osmembership_subscribers AS a')
->innerJoin('#__osmembership_plans AS b ON a.plan_id = b.id')
->leftJoin('#__users AS c ON a.user_id = c.id')
->where('b.send_subscription_end != 0')
->where('b.recurring_subscription = 1')
->where('b.number_payments > 0')
->where('a.published IN (1, 2)')
->where('a.subscription_end_sent = 0')
->where('a.group_admin_id = 0')
->where('a.payment_made = b.number_payments')
->where(
'IF(b.send_subscription_end > 0, b.send_subscription_end >= DATEDIFF(to_date, NOW()) AND DATEDIFF(to_date, NOW()) >= 0, DATEDIFF(NOW(), to_date) >= ABS(b.send_subscription_end) AND DATEDIFF(NOW(), to_date) <= 120 )'
)
->order('a.to_date');
$db->setQuery($query, 0, $numberEmailSendEachTime);
try
{
$rows = $db->loadObjectList();
if (!empty($rows))
{
\OSMembershipHelper::callOverridableHelperMethod('Mail', 'sendSubscriptionEndEmails', [$rows, $bccEmail]
);
}
}
catch (\Exception $e)
{
}
}
/**
* Get subscription records to send reminder
*
* @param int $reminderNumber
* @param int $numberEmailSendEachTime
*
* @return array|mixed
*/
private function getSubscriptionsToSendReminder($reminderNumber, $numberEmailSendEachTime)
{
if (!in_array($reminderNumber, [1, 2, 3, 4, 5, 6]))
{
return [];
}
switch ($reminderNumber)
{
case 1:
$sendReminderField = 'b.send_first_reminder';
$reminderSentField = 'a.first_reminder_sent';
break;
case 2:
$sendReminderField = 'b.send_second_reminder';
$reminderSentField = 'a.second_reminder_sent';
break;
case 3:
$sendReminderField = 'b.send_third_reminder';
$reminderSentField = 'a.third_reminder_sent';
break;
case 4:
$sendReminderField = 'b.send_fourth_reminder';
$reminderSentField = 'a.fourth_reminder_sent';
break;
case 5:
$sendReminderField = 'b.send_fifth_reminder';
$reminderSentField = 'a.fifth_reminder_sent';
break;
case 6:
$sendReminderField = 'b.send_sixth_reminder';
$reminderSentField = 'a.sixth_reminder_sent';
break;
}
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select('a.*, b.title AS plan_title, b.recurring_subscription, b.number_payments, c.username')
->select(
"IF($sendReminderField > 0, DATEDIFF(to_date, UTC_TIMESTAMP()), DATEDIFF(UTC_TIMESTAMP(), to_date)) AS number_days"
)
->from('#__osmembership_subscribers AS a')
->innerJoin('#__osmembership_plans AS b ON a.plan_id = b.id')
->leftJoin('#__users AS c ON a.user_id = c.id')
->where("$sendReminderField != 0")
->where('b.lifetime_membership != 1')
->where('a.published IN (1, 2)')
->where("$reminderSentField = 0")
->where(
"IF($sendReminderField > 0, $sendReminderField >= DATEDIFF(to_date, UTC_TIMESTAMP()) AND DATEDIFF(to_date, UTC_TIMESTAMP()) >= 0, DATEDIFF(UTC_TIMESTAMP(), to_date) >= ABS($sendReminderField) AND DATEDIFF(UTC_TIMESTAMP(), to_date) <= (ABS($sendReminderField) + 10))"
)
->order('a.to_date');
if (!$this->params->get('send_to_group_members'))
{
$query->where('a.group_admin_id = 0');
}
$db->setQuery($query, 0, $numberEmailSendEachTime);
try
{
return $db->loadObjectList();
}
catch (\Exception $e)
{
return [];
}
}
/**
* Method to check whether this plugin should be run
*
* @return bool
*/
private function canRun()
{
$app = $this->getApplication();
// If trigger reminder code is set, we will only process sending reminder from cron job
if (trim($this->params->get('trigger_reminder_code', ''))
&& trim($this->params->get('trigger_reminder_code', '')) != $app->getInput()->getString(
'trigger_reminder_code'
))
{
return false;
}
// If time ranges is set and current time is not within these specified ranges, we won't process sending reminder
if ($this->params->get('time_ranges'))
{
$withinTimeRage = false;
$date = Factory::getDate('Now', $app->get('offset'));
$currentHour = $date->format('G', true);
$timeRanges = explode(';', $this->params->get('time_ranges'));// Time ranges format 6,10;14,20
foreach ($timeRanges as $timeRange)
{
if (!str_contains($timeRange, ','))
{
continue;
}
[$fromHour, $toHour] = explode(',', $timeRange);
if ($fromHour <= $currentHour && $toHour >= $currentHour)
{
$withinTimeRage = true;
break;
}
}
if (!$withinTimeRage)
{
return false;
}
}
// We only need to check last run time if cron job is not used
if (!trim($this->params->get('trigger_reminder_code', '')))
{
$lastRun = (int) $this->params->get('last_run', 0);
$now = time();
$cacheTime = (int) $this->params->get('cache_time', 2) * 3600;
if (($now - $lastRun) < $cacheTime)
{
return false;
}
}
return true;
}
/**
* Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp.
*
* @param array $clearGroups The cache groups to clean
* @param array $cacheClients The cache clients (site, admin) to clean
*
* @return void
*
* @since 2.0.0
*/
private function clearCacheGroups(array $clearGroups, array $cacheClients = [0, 1])
{
$app = $this->getApplication();
foreach ($clearGroups as $group)
{
foreach ($cacheClients as $clientId)
{
try
{
$options = [
'defaultgroup' => $group,
'cachebase' => ($clientId) ? JPATH_ADMINISTRATOR . '/cache' :
$app->get('cache_path', JPATH_SITE . '/cache'),
];
$cache = Cache::getInstance('callback', $options);
$cache->clean();
}
catch (\Exception $e)
{
// Ignore it
}
}
}
}
}