diff --git a/mailpoet/lib/Cache/TransientCache.php b/mailpoet/lib/Cache/TransientCache.php index d7ab61e1a5..752f7dda57 100644 --- a/mailpoet/lib/Cache/TransientCache.php +++ b/mailpoet/lib/Cache/TransientCache.php @@ -8,6 +8,7 @@ use MailPoetVendor\Carbon\Carbon; class TransientCache { public const SUBSCRIBERS_STATISTICS_COUNT_KEY = 'mailpoet_subscribers_statistics_count_cache'; public const SUBSCRIBERS_GLOBAL_STATUS_STATISTICS_COUNT_KEY = 'mailpoet_subscribers_statistics_count_global_status_cache'; + public const SUBSCRIBERS_HOMEPAGE_STATISTICS_COUNT_KEY = 'mailpoet_subscribers_statistics_count_homepage_cache'; /** @var WPFunctions */ private $wp; diff --git a/mailpoet/lib/Cron/Workers/SubscribersCountCacheRecalculation.php b/mailpoet/lib/Cron/Workers/SubscribersCountCacheRecalculation.php index cb04cf0e20..4962e1059d 100644 --- a/mailpoet/lib/Cron/Workers/SubscribersCountCacheRecalculation.php +++ b/mailpoet/lib/Cron/Workers/SubscribersCountCacheRecalculation.php @@ -46,7 +46,10 @@ class SubscribersCountCacheRecalculation extends SimpleWorker { // update cache for subscribers without segment $this->recalculateSegmentCache($timer, 0); + $this->recalculateHomepageCache($timer); + // remove redundancies from cache + $this->cronHelper->enforceExecutionLimit($timer); $this->subscribersCountsController->removeRedundancyFromStatisticsCache(); return true; @@ -68,6 +71,16 @@ class SubscribersCountCacheRecalculation extends SimpleWorker { } } + private function recalculateHomepageCache($timer): void { + $this->cronHelper->enforceExecutionLimit($timer); + $now = Carbon::now(); + $item = $this->transientCache->getItem(TransientCache::SUBSCRIBERS_HOMEPAGE_STATISTICS_COUNT_KEY, 0); + if ($item === null || !isset($item['created_at']) || $now->diffInMinutes($item['created_at']) > self::EXPIRATION_IN_MINUTES) { + $this->cronHelper->enforceExecutionLimit($timer); + $this->subscribersCountsController->recalculateHomepageStatisticsCache(); + } + } + public function getNextRunDate() { return Carbon::createFromTimestamp($this->wp->currentTime('timestamp')); } diff --git a/mailpoet/lib/Homepage/HomepageDataController.php b/mailpoet/lib/Homepage/HomepageDataController.php index 21c198b905..ed8a4f31a2 100644 --- a/mailpoet/lib/Homepage/HomepageDataController.php +++ b/mailpoet/lib/Homepage/HomepageDataController.php @@ -8,16 +8,13 @@ use MailPoet\Automation\Integrations\MailPoet\Actions\SendEmailAction; use MailPoet\Automation\Integrations\MailPoet\Triggers\SomeoneSubscribesTrigger; use MailPoet\Automation\Integrations\MailPoet\Triggers\UserRegistrationTrigger; use MailPoet\Entities\NewsletterEntity; -use MailPoet\Entities\SubscriberEntity; use MailPoet\Form\FormsRepository; use MailPoet\Newsletter\NewslettersRepository; use MailPoet\Services\Bridge; use MailPoet\Settings\SettingsController; -use MailPoet\Subscribers\SubscribersRepository; +use MailPoet\Subscribers\SubscribersCountsController; use MailPoet\Util\License\Features\Subscribers as SubscribersFeature; use MailPoet\WooCommerce\Helper as WooCommerceHelper; -use MailPoet\WP\Functions as WPFunctions; -use MailPoetVendor\Carbon\Carbon; class HomepageDataController { public const UPSELL_SUBSCRIBERS_COUNT_REQUIRED = 600; @@ -25,9 +22,6 @@ class HomepageDataController { /** @var SettingsController */ private $settingsController; - /** @var SubscribersRepository */ - private $subscribersRepository; - /** @var FormsRepository */ private $formsRepository; @@ -43,27 +37,25 @@ class HomepageDataController { /** @var SubscribersFeature */ private $subscribersFeature; - /** @var WPFunctions */ - private $wp; + /** @var SubscribersCountsController */ + private $subscribersCountsController; public function __construct( SettingsController $settingsController, - SubscribersRepository $subscribersRepository, FormsRepository $formsRepository, NewslettersRepository $newslettersRepository, AutomationStorage $automationStorage, SubscribersFeature $subscribersFeature, - WPFunctions $wp, + SubscribersCountsController $subscribersCountsController, WooCommerceHelper $wooCommerceHelper ) { $this->settingsController = $settingsController; - $this->subscribersRepository = $subscribersRepository; $this->formsRepository = $formsRepository; $this->newslettersRepository = $newslettersRepository; $this->automationStorage = $automationStorage; - $this->wp = $wp; $this->wooCommerceHelper = $wooCommerceHelper; $this->subscribersFeature = $subscribersFeature; + $this->subscribersCountsController = $subscribersCountsController; } public function getPageData(): array { @@ -158,15 +150,15 @@ class HomepageDataController { * @return array{global:array{subscribed:int, unsubscribed:int, changePercent:float|int}, lists:array} */ private function getSubscribersStats(): array { - $thirtyDaysAgo = Carbon::createFromTimestamp($this->wp->currentTime('timestamp'))->subDays(30); $listData = []; - $listsDataSubscribed = $this->subscribersRepository->getListLevelCountsOfSubscribedAfter($thirtyDaysAgo); + $counts = $this->subscribersCountsController->getHomepageStatistics(); + $listsDataSubscribed = $counts['listsDataSubscribed'] ?? []; foreach ($listsDataSubscribed as $list) { $listData[$list['id']] = array_intersect_key($list, array_flip(['name', 'id', 'type', 'averageEngagementScore'])); $listData[$list['id']]['subscribed'] = $list['count']; $listData[$list['id']]['unsubscribed'] = 0; } - $listsDataUnsubscribed = $this->subscribersRepository->getListLevelCountsOfUnsubscribedAfter($thirtyDaysAgo); + $listsDataUnsubscribed = $counts['listsDataUnsubscribed'] ?? []; foreach ($listsDataUnsubscribed as $list) { if (!isset($listData[$list['id']])) { $listData[$list['id']] = array_intersect_key($list, array_flip(['name', 'id', 'type', 'averageEngagementScore'])); @@ -175,9 +167,9 @@ class HomepageDataController { $listData[$list['id']]['unsubscribed'] = $list['count']; } - $subscribedCount = $this->subscribersRepository->getCountOfLastSubscribedAfter($thirtyDaysAgo); - $unsubscribedCount = $this->subscribersRepository->getCountOfUnsubscribedAfter($thirtyDaysAgo); - $subscribedSubscribersCount = $this->subscribersRepository->getCountOfSubscribersForStates([SubscriberEntity::STATUS_SUBSCRIBED]); + $subscribedCount = intval($counts['subscribedCount'] ?? 0); + $unsubscribedCount = intval($counts['unsubscribedCount'] ?? 0); + $subscribedSubscribersCount = intval($counts['subscribedSubscribersCount'] ?? 0); $subscribedSubscribers30DaysAgo = $subscribedSubscribersCount - $subscribedCount + $unsubscribedCount; if ($subscribedSubscribers30DaysAgo > 0) { $globalChangePercent = (($subscribedSubscribersCount - $subscribedSubscribers30DaysAgo) / $subscribedSubscribers30DaysAgo) * 100; diff --git a/mailpoet/lib/Subscribers/SubscribersCountsController.php b/mailpoet/lib/Subscribers/SubscribersCountsController.php index 0be091023b..9174eca92d 100644 --- a/mailpoet/lib/Subscribers/SubscribersCountsController.php +++ b/mailpoet/lib/Subscribers/SubscribersCountsController.php @@ -4,10 +4,14 @@ namespace MailPoet\Subscribers; use MailPoet\Cache\TransientCache; use MailPoet\Entities\SegmentEntity; +use MailPoet\Entities\SubscriberEntity; use MailPoet\InvalidStateException; use MailPoet\Segments\SegmentsRepository; use MailPoet\Segments\SegmentSubscribersRepository; +use MailPoet\Subscribers\SubscribersRepository; use MailPoet\Tags\TagRepository; +use MailPoet\WP\Functions as WPFunctions; +use MailPoetVendor\Carbon\Carbon; class SubscribersCountsController { /** @var SegmentsRepository */ @@ -16,23 +20,33 @@ class SubscribersCountsController { /** @var SegmentSubscribersRepository */ private $segmentSubscribersRepository; + /** @var SubscribersRepository */ + private $subscribersRepository; + /** @var TagRepository */ private $tagRepository; /** @var TransientCache */ private $transientCache; + /** @var WPFunctions */ + private $wp; + public function __construct( SegmentsRepository $segmentsRepository, SegmentSubscribersRepository $segmentSubscribersRepository, + SubscribersRepository $subscribersRepository, TagRepository $subscriberTagRepository, - TransientCache $transientCache + TransientCache $transientCache, + WPFunctions $wp ) { $this->segmentSubscribersRepository = $segmentSubscribersRepository; $this->transientCache = $transientCache; $this->segmentsRepository = $segmentsRepository; + $this->subscribersRepository = $subscribersRepository; $this->tagRepository = $subscriberTagRepository; + $this->wp = $wp; } public function getSubscribersWithoutSegmentStatisticsCount(): array { @@ -71,6 +85,14 @@ class SubscribersCountsController { return $result; } + public function getHomepageStatistics(): array { + $result = $this->transientCache->getItem(TransientCache::SUBSCRIBERS_HOMEPAGE_STATISTICS_COUNT_KEY, 0) ?? []; + if (!$result) { + $result = $this->recalculateHomepageStatisticsCache(); + } + return $result; + } + public function recalculateSegmentGlobalStatusStatisticsCache(SegmentEntity $segment): array { $result = $this->segmentSubscribersRepository->getSubscribersGlobalStatusStatisticsCount($segment); $this->transientCache->setItem( @@ -97,6 +119,22 @@ class SubscribersCountsController { return $result; } + public function recalculateHomepageStatisticsCache(): array { + $thirtyDaysAgo = Carbon::createFromTimestamp($this->wp->currentTime('timestamp'))->subDays(30); + $result = []; + $result['listsDataSubscribed'] = $this->subscribersRepository->getListLevelCountsOfSubscribedAfter($thirtyDaysAgo); + $result['listsDataUnsubscribed'] = $this->subscribersRepository->getListLevelCountsOfUnsubscribedAfter($thirtyDaysAgo); + $result['subscribedCount'] = $this->subscribersRepository->getCountOfLastSubscribedAfter($thirtyDaysAgo); + $result['unsubscribedCount'] = $this->subscribersRepository->getCountOfUnsubscribedAfter($thirtyDaysAgo); + $result['subscribedSubscribersCount'] = $this->subscribersRepository->getCountOfSubscribersForStates([SubscriberEntity::STATUS_SUBSCRIBED]); + $this->transientCache->setItem( + TransientCache::SUBSCRIBERS_HOMEPAGE_STATISTICS_COUNT_KEY, + $result, + 0 + ); + return $result; + } + public function removeRedundancyFromStatisticsCache() { $segments = $this->segmentsRepository->findAll(); $segmentIds = array_map(function (SegmentEntity $segment): int {