PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / Subscribers / SubscribersCountsController.php
mailpoet / lib / Subscribers Last commit date
ConfirmationEmailTemplate 1 month ago ImportExport 2 weeks ago RestApi 3 days ago Statistics 1 month ago BulkActionController.php 3 days ago BulkActionException.php 1 month ago BulkConfirmationEmailResender.php 2 months ago ConfirmationEmailCustomizer.php 2 months ago ConfirmationEmailMailer.php 2 months ago ConfirmationEmailResolver.php 2 months ago EngagementDataBackfiller.php 2 months ago InactiveSubscribersController.php 5 days ago LinkTokens.php 2 months ago NewSubscriberNotificationMailer.php 2 months ago RequiredCustomFieldValidator.php 2 months ago SegmentsCountRecalculator.php 2 weeks ago Source.php 2 months ago SubscriberActions.php 2 months ago SubscriberCustomFieldRepository.php 3 years ago SubscriberIPsRepository.php 2 years ago SubscriberLimitNotificationEvaluator.php 2 months ago SubscriberLimitNotificationMailer.php 2 months ago SubscriberLimitNotificationScheduler.php 2 months ago SubscriberListingRepository.php 2 weeks ago SubscriberPersonalDataEraser.php 2 months ago SubscriberSaveController.php 3 days ago SubscriberSegmentRepository.php 2 weeks ago SubscriberSubscribeController.php 2 weeks ago SubscriberTagRepository.php 4 years ago SubscribersCountsController.php 2 weeks ago SubscribersEmailCountsController.php 2 weeks ago SubscribersRepository.php 3 days ago TrackingConsentController.php 5 days ago index.php 3 years ago
SubscribersCountsController.php
177 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\Subscribers;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Cache\TransientCache;
9 use MailPoet\Entities\SegmentEntity;
10 use MailPoet\Entities\SubscriberEntity;
11 use MailPoet\InvalidStateException;
12 use MailPoet\Segments\SegmentsRepository;
13 use MailPoet\Segments\SegmentSubscribersRepository;
14 use MailPoet\Tags\TagRepository;
15 use MailPoet\Util\License\Features\Subscribers as SubscribersFeature;
16 use MailPoetVendor\Carbon\Carbon;
17
18 class SubscribersCountsController {
19 /** @var SegmentsRepository */
20 private $segmentsRepository;
21
22 /** @var SegmentSubscribersRepository */
23 private $segmentSubscribersRepository;
24
25 /** @var SubscribersRepository */
26 private $subscribersRepository;
27
28 /** @var TagRepository */
29 private $tagRepository;
30
31 /** @var TransientCache */
32 private $transientCache;
33
34 /** @var SubscribersFeature */
35 private $subscribersFeature;
36
37 public function __construct(
38 SegmentsRepository $segmentsRepository,
39 SegmentSubscribersRepository $segmentSubscribersRepository,
40 SubscribersRepository $subscribersRepository,
41 TagRepository $subscriberTagRepository,
42 TransientCache $transientCache,
43 SubscribersFeature $subscribersFeature
44 ) {
45
46 $this->segmentSubscribersRepository = $segmentSubscribersRepository;
47 $this->transientCache = $transientCache;
48 $this->segmentsRepository = $segmentsRepository;
49 $this->subscribersRepository = $subscribersRepository;
50 $this->tagRepository = $subscriberTagRepository;
51 $this->subscribersFeature = $subscribersFeature;
52 }
53
54 public function getSubscribersWithoutSegmentStatisticsCount(): array {
55 $result = $this->getCacheItem(TransientCache::SUBSCRIBERS_STATISTICS_COUNT_KEY, 0)['item'] ?? null;
56 if (!$result) {
57 $result = $this->recalculateSubscribersWithoutSegmentStatisticsCache();
58 }
59 return $result;
60 }
61
62 public function getSegmentStatisticsCount(SegmentEntity $segment): array {
63 $result = $this->getCacheItem(TransientCache::SUBSCRIBERS_STATISTICS_COUNT_KEY, (int)$segment->getId())['item'] ?? null;
64 if (!$result) {
65 $result = $this->recalculateSegmentStatisticsCache($segment);
66 }
67 return $result;
68 }
69
70 public function getSegmentStatisticsCountById(int $segmentId): array {
71 $result = $this->getCacheItem(TransientCache::SUBSCRIBERS_STATISTICS_COUNT_KEY, $segmentId)['item'] ?? null;
72 if (!$result) {
73 $segment = $this->segmentsRepository->findOneById($segmentId);
74 if (!$segment) {
75 throw new InvalidStateException("Segment with ID $segmentId not found");
76 }
77 $result = $this->recalculateSegmentStatisticsCache($segment);
78 }
79 return $result;
80 }
81
82 public function getGlobalStatusStatisticsCount(): array {
83 $result = $this->getCacheItem(TransientCache::SUBSCRIBERS_GLOBAL_STATISTICS_COUNT_KEY, 0)['item'] ?? null;
84 if (!$result) {
85 $result = $this->recalculateGlobalStatusStatisticsCache();
86 }
87 return $result;
88 }
89
90 public function recalculateGlobalStatusStatisticsCache(): array {
91 $result = $this->subscribersRepository->getStatusStatisticsCount();
92 $this->setCacheItem(TransientCache::SUBSCRIBERS_GLOBAL_STATISTICS_COUNT_KEY, $result, 0);
93 return $result;
94 }
95
96 public function getHomepageStatistics(): array {
97 $result = $this->getCacheItem(TransientCache::SUBSCRIBERS_HOMEPAGE_STATISTICS_COUNT_KEY, 0)['item'] ?? [];
98 if (!$result) {
99 $result = $this->recalculateHomepageStatisticsCache();
100 }
101 return $result;
102 }
103
104 public function recalculateSegmentStatisticsCache(SegmentEntity $segment): array {
105 $result = $this->segmentSubscribersRepository->getSubscribersStatisticsCount($segment);
106 $this->setCacheItem(
107 TransientCache::SUBSCRIBERS_STATISTICS_COUNT_KEY,
108 $result,
109 (int)$segment->getId()
110 );
111 return $result;
112 }
113
114 public function recalculateSubscribersWithoutSegmentStatisticsCache(): array {
115 $result = $this->segmentSubscribersRepository->getSubscribersWithoutSegmentStatisticsCount();
116 $this->setCacheItem(TransientCache::SUBSCRIBERS_STATISTICS_COUNT_KEY, $result, 0);
117 return $result;
118 }
119
120 public function recalculateHomepageStatisticsCache(): array {
121 $thirtyDaysAgo = Carbon::now()->millisecond(0)->subDays(30);
122 $result = [];
123 $result['listsDataSubscribed'] = $this->subscribersRepository->getListLevelCountsOfSubscribedAfter($thirtyDaysAgo);
124 $result['listsDataUnsubscribed'] = $this->subscribersRepository->getListLevelCountsOfUnsubscribedAfter($thirtyDaysAgo);
125 $result['subscribedCount'] = $this->subscribersRepository->getCountOfLastSubscribedAfter($thirtyDaysAgo);
126 $result['unsubscribedCount'] = $this->subscribersRepository->getCountOfUnsubscribedAfter($thirtyDaysAgo);
127 $result['subscribedSubscribersCount'] = $this->subscribersRepository->getCountOfSubscribersForStates([SubscriberEntity::STATUS_SUBSCRIBED]);
128 $this->setCacheItem(
129 TransientCache::SUBSCRIBERS_HOMEPAGE_STATISTICS_COUNT_KEY,
130 $result,
131 0
132 );
133 return $result;
134 }
135
136 public function removeRedundancyFromStatisticsCache() {
137 $segments = $this->segmentsRepository->findAll();
138 $segmentIds = array_map(function (SegmentEntity $segment): int {
139 return (int)$segment->getId();
140 }, $segments);
141 foreach ($this->transientCache->getItems(TransientCache::SUBSCRIBERS_STATISTICS_COUNT_KEY) as $id => $item) {
142 // id 0 is the "subscribers without a list" entry, not an orphaned segment —
143 // keep it, otherwise every cache warm deletes it right after building it and
144 // the (expensive) count is recomputed live on the next page load.
145 if ($id === 0) {
146 continue;
147 }
148 if (!in_array($id, $segmentIds)) {
149 $this->transientCache->invalidateItem(TransientCache::SUBSCRIBERS_STATISTICS_COUNT_KEY, $id);
150 }
151 }
152 }
153
154 /**
155 * Use cache only if subscribers count is above minimum
156 */
157 private function getCacheItem(string $key, int $id): ?array {
158 if ($this->subscribersFeature->isSubscribersCountEnoughForCache()) {
159 return $this->transientCache->getItem($key, $id);
160 }
161 return [];
162 }
163
164 private function setCacheItem(string $key, array $item, int $id): void {
165 if ($this->subscribersFeature->isSubscribersCountEnoughForCache()) {
166 $this->transientCache->setItem($key, $item, $id);
167 }
168 }
169
170 /**
171 * @return array<int, array{id: int, name: string, subscribersCount: int}>
172 */
173 public function getTagsStatisticsCount(?string $status, bool $isDeleted): array {
174 return $this->tagRepository->getSubscriberStatisticsCount($status, $isDeleted);
175 }
176 }
177