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 / EngagementDataBackfiller.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 4 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 4 days ago index.php 3 years ago
EngagementDataBackfiller.php
211 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\Subscribers;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Entities\StatisticsClickEntity;
9 use MailPoet\Entities\StatisticsNewsletterEntity;
10 use MailPoet\Entities\StatisticsOpenEntity;
11 use MailPoet\Entities\SubscriberEntity;
12 use MailPoet\Segments\DynamicSegments\Filters\FilterHelper;
13 use MailPoet\Segments\DynamicSegments\Filters\WooFilterHelper;
14 use MailPoet\WooCommerce\Helper;
15 use MailPoetVendor\Carbon\Carbon;
16 use MailPoetVendor\Doctrine\DBAL\ArrayParameterType;
17 use MailPoetVendor\Doctrine\DBAL\Result;
18 use MailPoetVendor\Doctrine\ORM\EntityManager;
19
20 class EngagementDataBackfiller {
21 /** @var EntityManager */
22 private $entityManager;
23
24 /** @var Helper */
25 private $wcHelper;
26
27 /** @var WooFilterHelper */
28 private $wooFilterHelper;
29
30 /** @var FilterHelper */
31 private $filterHelper;
32
33 /** @var int */
34 private $lastProcessedSubscriberId = 0;
35
36 public function __construct(
37 EntityManager $entityManager,
38 WooFilterHelper $wooFilterHelper,
39 FilterHelper $filterHelper,
40 Helper $wcHelper
41 ) {
42 $this->entityManager = $entityManager;
43 $this->wcHelper = $wcHelper;
44 $this->wooFilterHelper = $wooFilterHelper;
45 $this->filterHelper = $filterHelper;
46 }
47
48 /**
49 * @return SubscriberEntity[]
50 */
51 public function getBatch(int $lastProcessedId = 0, int $batchSize = 100): array {
52 $subscribers = $this->entityManager->createQueryBuilder()
53 ->select('PARTIAL s.{id, email, lastPurchaseAt, lastClickAt, lastOpenAt, lastSendingAt}')
54 ->from(SubscriberEntity::class, 's')
55 ->where('s.id > :lastProcessedId')
56 ->orderBy('s.id', 'ASC')
57 ->setMaxResults($batchSize)
58 ->setParameter('lastProcessedId', $lastProcessedId)
59 ->getQuery()
60 ->getResult();
61 if (!is_array($subscribers)) {
62 return [];
63 }
64 /** @var SubscriberEntity[] $subscribers */
65 return $subscribers;
66 }
67
68 /**
69 * @param SubscriberEntity[] $subscribers
70 *
71 * @return void
72 */
73 public function updateBatch(array $subscribers): void {
74 $subscriberIds = array_map(function (SubscriberEntity $subscriber) {
75 return $subscriber->getId();
76 }, $subscribers);
77
78 $clickData = $this->getClickDataForBatch($subscriberIds);
79 $openData = $this->getOpenDataForBatch($subscriberIds);
80 $sendingData = $this->getSendingDataForBatch($subscriberIds);
81 $purchaseData = $this->getPurchaseDataForBatch($subscriberIds);
82
83 foreach ($subscribers as $subscriber) {
84 if ($subscriber->getLastPurchaseAt() === null && isset($purchaseData[$subscriber->getId()]['last_purchase_at'])) {
85 $purchaseDate = new Carbon($purchaseData[$subscriber->getId()]['last_purchase_at']);
86 $subscriber->setLastPurchaseAt($purchaseDate);
87 }
88 if ($subscriber->getLastOpenAt() === null && isset($openData[$subscriber->getId()]['last_open_at'])) {
89 $openDate = new Carbon($openData[$subscriber->getId()]['last_open_at']);
90 $subscriber->setLastOpenAt($openDate);
91 }
92 if ($subscriber->getLastClickAt() === null && isset($clickData[$subscriber->getId()]['last_click_at'])) {
93 $clickDate = new Carbon($clickData[$subscriber->getId()]['last_click_at']);
94 $subscriber->setLastClickAt($clickDate);
95 }
96 if ($subscriber->getLastSendingAt() === null && isset($sendingData[$subscriber->getId()]['last_sending_at'])) {
97 $sendingDate = new Carbon($sendingData[$subscriber->getId()]['last_sending_at']);
98 $subscriber->setLastSendingAt($sendingDate);
99 }
100 if (is_int($subscriber->getId())) {
101 $this->lastProcessedSubscriberId = $subscriber->getId();
102 }
103 }
104
105 $this->entityManager->flush();
106 }
107
108 public function getClickDataForBatch(array $subscriberIds): array {
109 $subscribersTable = $this->filterHelper->getSubscribersTable();
110 $clicksTable = $this->filterHelper->getTableForEntity(StatisticsClickEntity::class);
111
112 $query = $this
113 ->entityManager
114 ->getConnection()
115 ->createQueryBuilder()
116 ->select("$subscribersTable.id, MAX(clicks.created_at) as last_click_at")
117 ->from($subscribersTable)
118 ->innerJoin($subscribersTable, $clicksTable, 'clicks', "$subscribersTable.id = clicks.subscriber_id")
119 ->andWhere("$subscribersTable.id IN (:subscriberIds)")
120 ->setParameter('subscriberIds', $subscriberIds, ArrayParameterType::INTEGER)
121 ->groupBy("$subscribersTable.id");
122
123 $result = $query->execute();
124 if ($result instanceof Result) {
125 return $result->fetchAllAssociativeIndexed();
126 }
127 return [];
128 }
129
130 public function getPurchaseDataForBatch(array $subscriberIds): array {
131 if (!$this->wcHelper->isWooCommerceActive()) {
132 return [];
133 }
134
135 $subscribersTable = $this->filterHelper->getSubscribersTable();
136
137 $query = $this
138 ->entityManager
139 ->getConnection()
140 ->createQueryBuilder()
141 // The orderStats alias comes from wooFilterHelper->applyOrderStatusFilter, which calls wooFilterHelper->applyCustomerOrderJoin
142 ->select("$subscribersTable.id, MAX(orderStats.date_created) as last_purchase_at")
143 ->from($subscribersTable)
144 ->andWhere("$subscribersTable.id IN (:subscriberIds)")
145 ->setParameter('subscriberIds', $subscriberIds, ArrayParameterType::INTEGER);
146 $this->wooFilterHelper->applyOrderStatusFilter($query);
147 $query->groupBy("$subscribersTable.id");
148
149 $result = $query->execute();
150 if ($result instanceof Result) {
151 return $result->fetchAllAssociativeIndexed();
152 }
153 return [];
154 }
155
156 public function getOpenDataForBatch(array $subscriberIds): array {
157 $subscribersTable = $this->filterHelper->getSubscribersTable();
158 $opensTable = $this->filterHelper->getTableForEntity(StatisticsOpenEntity::class);
159
160 $query = $this
161 ->entityManager
162 ->getConnection()
163 ->createQueryBuilder()
164 ->select("$subscribersTable.id, MAX(opens.created_at) as last_open_at")
165 ->from($subscribersTable)
166 ->innerJoin($subscribersTable, $opensTable, 'opens', "$subscribersTable.id = opens.subscriber_id")
167 ->andWhere("$subscribersTable.id IN (:subscriberIds)")
168 ->setParameter('subscriberIds', $subscriberIds, ArrayParameterType::INTEGER)
169 ->groupBy("$subscribersTable.id");
170
171 $result = $query->execute();
172 if ($result instanceof Result) {
173 return $result->fetchAllAssociativeIndexed();
174 }
175 return [];
176 }
177
178 public function getSendingDataForBatch(array $subscriberIds): array {
179 $subscribersTable = $this->filterHelper->getSubscribersTable();
180 $sendsTable = $this->filterHelper->getTableForEntity(StatisticsNewsletterEntity::class);
181
182 $query = $this
183 ->entityManager
184 ->getConnection()
185 ->createQueryBuilder()
186 ->select("$subscribersTable.id, MAX(sends.sent_at) as last_sending_at")
187 ->from($subscribersTable)
188 ->innerJoin($subscribersTable, $sendsTable, 'sends', "$subscribersTable.id = sends.subscriber_id")
189 ->andWhere("$subscribersTable.id IN (:subscriberIds)")
190 ->setParameter('subscriberIds', $subscriberIds, ArrayParameterType::INTEGER)
191 ->groupBy("$subscribersTable.id");
192
193 $result = $query->execute();
194 if ($result instanceof Result) {
195 return $result->fetchAllAssociativeIndexed();
196 }
197 return [];
198 }
199
200 /**
201 * @return int
202 */
203 public function getLastProcessedSubscriberId(): int {
204 return $this->lastProcessedSubscriberId;
205 }
206
207 public function setLastProcessedSubscriberId(int $id): void {
208 $this->lastProcessedSubscriberId = $id;
209 }
210 }
211