PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.31.0
MailPoet – Newsletters, Email Marketing, and Automation v5.31.0
5.37.0 5.36.1 5.36.0 5.35.1 5.35.0 5.34.3 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 / API / JSON / ResponseBuilders / SubscribersResponseBuilder.php
mailpoet / lib / API / JSON / ResponseBuilders Last commit date
CustomFieldsResponseBuilder.php 1 year ago DynamicSegmentsResponseBuilder.php 3 months ago FormsResponseBuilder.php 1 year ago NewsletterTemplatesResponseBuilder.php 1 year ago NewslettersResponseBuilder.php 3 months ago ScheduledTaskSubscriberResponseBuilder.php 3 years ago SegmentsResponseBuilder.php 3 months ago SendingQueuesResponseBuilder.php 3 months ago SubscribersResponseBuilder.php 3 months ago index.php 3 years ago
SubscribersResponseBuilder.php
237 lines
1 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
2
3 namespace MailPoet\API\JSON\ResponseBuilders;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\CustomFields\CustomFieldsRepository;
9 use MailPoet\Entities\NewsletterEntity;
10 use MailPoet\Entities\SegmentEntity;
11 use MailPoet\Entities\StatisticsUnsubscribeEntity;
12 use MailPoet\Entities\SubscriberCustomFieldEntity;
13 use MailPoet\Entities\SubscriberEntity;
14 use MailPoet\Statistics\StatisticsUnsubscribesRepository;
15 use MailPoet\Statistics\UnsubscribeReasonTracker;
16 use MailPoet\Subscribers\Statistics\SubscriberStatisticsRepository;
17 use MailPoet\Subscribers\SubscriberCustomFieldRepository;
18 use MailPoetVendor\Doctrine\ORM\EntityManager;
19
20 class SubscribersResponseBuilder {
21 const DATE_FORMAT = 'Y-m-d H:i:s';
22
23 /** @var StatisticsUnsubscribesRepository */
24 private $statisticsUnsubscribesRepository;
25
26 /** @var CustomFieldsRepository */
27 private $customFieldsRepository;
28
29 /** @var SubscriberCustomFieldRepository */
30 private $subscriberCustomFieldRepository;
31
32 /** @var EntityManager */
33 private $entityManager;
34
35 /** @var UnsubscribeReasonTracker */
36 private $unsubscribeReasonTracker;
37
38 /** @var SubscriberStatisticsRepository */
39 private $subscriberStatisticsRepository;
40
41 public function __construct(
42 EntityManager $entityManager,
43 CustomFieldsRepository $customFieldsRepository,
44 SubscriberCustomFieldRepository $subscriberCustomFieldRepository,
45 StatisticsUnsubscribesRepository $statisticsUnsubscribesRepository,
46 UnsubscribeReasonTracker $unsubscribeReasonTracker,
47 SubscriberStatisticsRepository $subscriberStatisticsRepository
48 ) {
49 $this->statisticsUnsubscribesRepository = $statisticsUnsubscribesRepository;
50 $this->customFieldsRepository = $customFieldsRepository;
51 $this->subscriberCustomFieldRepository = $subscriberCustomFieldRepository;
52 $this->entityManager = $entityManager;
53 $this->unsubscribeReasonTracker = $unsubscribeReasonTracker;
54 $this->subscriberStatisticsRepository = $subscriberStatisticsRepository;
55 }
56
57 public function buildForListing(array $subscribers): array {
58 $this->prefetchRelations($subscribers);
59 $engagementScoreTypes = $this->subscriberStatisticsRepository->getEngagementScoreTypes($subscribers);
60 $data = [];
61 foreach ($subscribers as $subscriber) {
62 $data[] = $this->buildListingItem(
63 $subscriber,
64 $engagementScoreTypes[(int)$subscriber->getId()] ?? SubscriberStatisticsRepository::ENGAGEMENT_SCORE_UNKNOWN
65 );
66 }
67 return $data;
68 }
69
70 private function buildListingItem(SubscriberEntity $subscriber, string $engagementScoreType): array {
71 return [
72 'id' => (string)$subscriber->getId(), // (string) for BC
73 'email' => $subscriber->getEmail(),
74 'first_name' => $subscriber->getFirstName(),
75 'last_name' => $subscriber->getLastName(),
76 'subscriptions' => $this->buildSubscriptions($subscriber),
77 'status' => $subscriber->getStatus(),
78 'count_confirmations' => $subscriber->getConfirmationsCount(),
79 'wp_user_id' => $subscriber->getWpUserId(),
80 'is_woocommerce_user' => $subscriber->getIsWoocommerceUser(),
81 'created_at' => ($createdAt = $subscriber->getCreatedAt()) ? $createdAt->format(self::DATE_FORMAT) : null,
82 'deleted_at' => ($deletedAt = $subscriber->getDeletedAt()) ? $deletedAt->format(self::DATE_FORMAT) : null,
83 'last_subscribed_at' => ($lastSubscribedAt = $subscriber->getLastSubscribedAt()) ? $lastSubscribedAt->format(self::DATE_FORMAT) : null,
84 'engagement_score' => $subscriber->getEngagementScore(),
85 'engagement_score_type' => $engagementScoreType,
86 'tags' => $this->buildTags($subscriber),
87 ];
88 }
89
90 public function build(SubscriberEntity $subscriberEntity): array {
91 $data = [
92 'id' => (string)$subscriberEntity->getId(),
93 'wp_user_id' => $subscriberEntity->getWpUserId(),
94 'is_woocommerce_user' => $subscriberEntity->getIsWoocommerceUser(),
95 'subscriptions' => $this->buildSubscriptions($subscriberEntity),
96 'unsubscribes' => $this->buildUnsubscribes($subscriberEntity),
97 'status' => $subscriberEntity->getStatus(),
98 'last_name' => $subscriberEntity->getLastName(),
99 'first_name' => $subscriberEntity->getFirstName(),
100 'email' => $subscriberEntity->getEmail(),
101 'created_at' => ($createdAt = $subscriberEntity->getCreatedAt()) ? $createdAt->format(self::DATE_FORMAT) : null,
102 'updated_at' => ($updatedAt = $subscriberEntity->getUpdatedAt()) ? $updatedAt->format(self::DATE_FORMAT) : null,
103 'deleted_at' => ($deletedAt = $subscriberEntity->getDeletedAt()) ? $deletedAt->format(self::DATE_FORMAT) : null,
104 'subscribed_ip' => $subscriberEntity->getSubscribedIp(),
105 'confirmed_ip' => $subscriberEntity->getConfirmedIp(),
106 'confirmed_at' => ($confirmedAt = $subscriberEntity->getConfirmedAt()) ? $confirmedAt->format(self::DATE_FORMAT) : null,
107 'last_subscribed_at' => ($lastSubscribedAt = $subscriberEntity->getLastSubscribedAt()) ? $lastSubscribedAt->format(self::DATE_FORMAT) : null,
108 'unconfirmed_data' => $subscriberEntity->getUnconfirmedData(),
109 'source' => $subscriberEntity->getSource(),
110 'count_confirmations' => $subscriberEntity->getConfirmationsCount(),
111 'unsubscribe_token' => $subscriberEntity->getUnsubscribeToken(),
112 'link_token' => $subscriberEntity->getLinkToken(),
113 'tags' => $this->buildTags($subscriberEntity),
114 ];
115
116 return $this->buildCustomFields($subscriberEntity, $data);
117 }
118
119 private function buildSubscriptions(SubscriberEntity $subscriberEntity): array {
120 $result = [];
121 foreach ($subscriberEntity->getSubscriberSegments() as $subscriberSegment) {
122 $segment = $subscriberSegment->getSegment();
123 if ($segment instanceof SegmentEntity) {
124 $result[] = [
125 'id' => $subscriberSegment->getId(),
126 'subscriber_id' => (string)$subscriberEntity->getId(),
127 'created_at' => ($createdAt = $subscriberSegment->getCreatedAt()) ? $createdAt->format(self::DATE_FORMAT) : null,
128 'segment_id' => (string)$segment->getId(),
129 'status' => $subscriberSegment->getStatus(),
130 'updated_at' => ($updatedAt = $subscriberSegment->getUpdatedAt()) ? $updatedAt->format(self::DATE_FORMAT) : null,
131 ];
132 }
133 }
134 return $result;
135 }
136
137 private function buildUnsubscribes(SubscriberEntity $subscriberEntity): array {
138 $unsubscribes = $this->statisticsUnsubscribesRepository->findBy([
139 'subscriber' => $subscriberEntity,
140 ], [
141 'createdAt' => 'desc',
142 ]);
143 $result = [];
144 $reasonLabels = $this->unsubscribeReasonTracker->getReasonLabels();
145 foreach ($unsubscribes as $unsubscribe) {
146 $mapped = [
147 'source' => $unsubscribe->getSource(),
148 'meta' => $unsubscribe->getMeta(),
149 'createdAt' => $unsubscribe->getCreatedAt(),
150 'reason' => $unsubscribe->getReason(),
151 'reasonLabel' => $this->getUnsubscribeReasonLabel($unsubscribe->getReason(), $reasonLabels),
152 'reasonText' => $unsubscribe->getReasonText(),
153 'reasonSubmittedAt' => $unsubscribe->getReasonSubmittedAt(),
154 ];
155 $newsletter = $unsubscribe->getNewsletter();
156 if ($newsletter instanceof NewsletterEntity) {
157 $mapped['newsletterId'] = $newsletter->getId();
158 $mapped['newsletterSubject'] = $newsletter->getSubject();
159 }
160 $result[] = $mapped;
161 }
162 return $result;
163 }
164
165 /**
166 * @param array<string, string> $reasonLabels
167 */
168 private function getUnsubscribeReasonLabel(?string $reason, array $reasonLabels): ?string {
169 if ($reason === null) {
170 return null;
171 }
172 if ($reason === '' || $reason === StatisticsUnsubscribeEntity::REASON_UNSPECIFIED) {
173 return __('No reason provided', 'mailpoet');
174 }
175 return $reasonLabels[$reason] ?? $reason;
176 }
177
178 private function buildCustomFields(SubscriberEntity $subscriberEntity, array $data): array {
179 $customFields = $this->customFieldsRepository->findAllActive();
180
181 foreach ($customFields as $customField) {
182 $subscriberCustomField = $this->subscriberCustomFieldRepository->findOneBy(
183 ['subscriber' => $subscriberEntity, 'customField' => $customField]
184 );
185 if ($subscriberCustomField instanceof SubscriberCustomFieldEntity) {
186 $data['cf_' . $customField->getId()] = $subscriberCustomField->getValue();
187 }
188 }
189 return $data;
190 }
191
192 private function buildTags(SubscriberEntity $subscriber): array {
193 $result = [];
194 foreach ($subscriber->getSubscriberTags() as $subscriberTag) {
195 $tag = $subscriberTag->getTag();
196 if (!$tag) {
197 continue;
198 }
199 $result[] = [
200 'id' => $subscriberTag->getId(),
201 'subscriber_id' => (string)$subscriber->getId(),
202 'tag_id' => (string)$tag->getId(),
203 'created_at' => ($createdAt = $subscriberTag->getCreatedAt()) ? $createdAt->format(self::DATE_FORMAT) : null,
204 'updated_at' => ($updatedAt = $subscriberTag->getUpdatedAt()) ? $updatedAt->format(self::DATE_FORMAT) : null,
205 'name' => $tag->getName(),
206 ];
207 }
208 return $result;
209 }
210
211 /**
212 * @param SubscriberEntity[] $subscribers
213 */
214 private function prefetchRelations(array $subscribers): void {
215 // Prefetch subscriptions
216 $this->entityManager->createQueryBuilder()
217 ->select('PARTIAL s.{id}, ssg, sg')
218 ->from(SubscriberEntity::class, 's')
219 ->leftJoin('s.subscriberSegments', 'ssg')
220 ->leftJoin('ssg.segment', 'sg')
221 ->where('s.id IN (:subscribers)')
222 ->setParameter('subscribers', $subscribers)
223 ->getQuery()
224 ->getResult();
225 // Prefetch tags
226 $this->entityManager->createQueryBuilder()
227 ->select('PARTIAL s.{id}, st, t')
228 ->from(SubscriberEntity::class, 's')
229 ->leftJoin('s.subscriberTags', 'st')
230 ->leftJoin('st.tag', 't')
231 ->where('s.id IN (:subscribers)')
232 ->setParameter('subscribers', $subscribers)
233 ->getQuery()
234 ->getResult();
235 }
236 }
237