PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
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 11 months ago DynamicSegmentsResponseBuilder.php 2 months ago FormsResponseBuilder.php 11 months ago NewsletterTemplatesResponseBuilder.php 11 months ago NewslettersResponseBuilder.php 3 weeks ago ScheduledTaskSubscriberResponseBuilder.php 3 years ago SegmentsResponseBuilder.php 2 months ago SendingQueuesResponseBuilder.php 2 months ago SubscribersResponseBuilder.php 2 weeks ago index.php 3 years ago
SubscribersResponseBuilder.php
238 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 'timezone' => $subscriberEntity->getTimeZone(),
115 ];
116
117 return $this->buildCustomFields($subscriberEntity, $data);
118 }
119
120 private function buildSubscriptions(SubscriberEntity $subscriberEntity): array {
121 $result = [];
122 foreach ($subscriberEntity->getSubscriberSegments() as $subscriberSegment) {
123 $segment = $subscriberSegment->getSegment();
124 if ($segment instanceof SegmentEntity) {
125 $result[] = [
126 'id' => $subscriberSegment->getId(),
127 'subscriber_id' => (string)$subscriberEntity->getId(),
128 'created_at' => ($createdAt = $subscriberSegment->getCreatedAt()) ? $createdAt->format(self::DATE_FORMAT) : null,
129 'segment_id' => (string)$segment->getId(),
130 'status' => $subscriberSegment->getStatus(),
131 'updated_at' => ($updatedAt = $subscriberSegment->getUpdatedAt()) ? $updatedAt->format(self::DATE_FORMAT) : null,
132 ];
133 }
134 }
135 return $result;
136 }
137
138 private function buildUnsubscribes(SubscriberEntity $subscriberEntity): array {
139 $unsubscribes = $this->statisticsUnsubscribesRepository->findBy([
140 'subscriber' => $subscriberEntity,
141 ], [
142 'createdAt' => 'desc',
143 ]);
144 $result = [];
145 $reasonLabels = $this->unsubscribeReasonTracker->getReasonLabels();
146 foreach ($unsubscribes as $unsubscribe) {
147 $mapped = [
148 'source' => $unsubscribe->getSource(),
149 'meta' => $unsubscribe->getMeta(),
150 'createdAt' => $unsubscribe->getCreatedAt(),
151 'reason' => $unsubscribe->getReason(),
152 'reasonLabel' => $this->getUnsubscribeReasonLabel($unsubscribe->getReason(), $reasonLabels),
153 'reasonText' => $unsubscribe->getReasonText(),
154 'reasonSubmittedAt' => $unsubscribe->getReasonSubmittedAt(),
155 ];
156 $newsletter = $unsubscribe->getNewsletter();
157 if ($newsletter instanceof NewsletterEntity) {
158 $mapped['newsletterId'] = $newsletter->getId();
159 $mapped['newsletterSubject'] = $newsletter->getSubject();
160 }
161 $result[] = $mapped;
162 }
163 return $result;
164 }
165
166 /**
167 * @param array<string, string> $reasonLabels
168 */
169 private function getUnsubscribeReasonLabel(?string $reason, array $reasonLabels): ?string {
170 if ($reason === null) {
171 return null;
172 }
173 if ($reason === '' || $reason === StatisticsUnsubscribeEntity::REASON_UNSPECIFIED) {
174 return __('No reason provided', 'mailpoet');
175 }
176 return $reasonLabels[$reason] ?? $reason;
177 }
178
179 private function buildCustomFields(SubscriberEntity $subscriberEntity, array $data): array {
180 $customFields = $this->customFieldsRepository->findAllActive();
181
182 foreach ($customFields as $customField) {
183 $subscriberCustomField = $this->subscriberCustomFieldRepository->findOneBy(
184 ['subscriber' => $subscriberEntity, 'customField' => $customField]
185 );
186 if ($subscriberCustomField instanceof SubscriberCustomFieldEntity) {
187 $data['cf_' . $customField->getId()] = $subscriberCustomField->getValue();
188 }
189 }
190 return $data;
191 }
192
193 private function buildTags(SubscriberEntity $subscriber): array {
194 $result = [];
195 foreach ($subscriber->getSubscriberTags() as $subscriberTag) {
196 $tag = $subscriberTag->getTag();
197 if (!$tag) {
198 continue;
199 }
200 $result[] = [
201 'id' => $subscriberTag->getId(),
202 'subscriber_id' => (string)$subscriber->getId(),
203 'tag_id' => (string)$tag->getId(),
204 'created_at' => ($createdAt = $subscriberTag->getCreatedAt()) ? $createdAt->format(self::DATE_FORMAT) : null,
205 'updated_at' => ($updatedAt = $subscriberTag->getUpdatedAt()) ? $updatedAt->format(self::DATE_FORMAT) : null,
206 'name' => $tag->getName(),
207 ];
208 }
209 return $result;
210 }
211
212 /**
213 * @param SubscriberEntity[] $subscribers
214 */
215 private function prefetchRelations(array $subscribers): void {
216 // Prefetch subscriptions
217 $this->entityManager->createQueryBuilder()
218 ->select('PARTIAL s.{id}, ssg, sg')
219 ->from(SubscriberEntity::class, 's')
220 ->leftJoin('s.subscriberSegments', 'ssg')
221 ->leftJoin('ssg.segment', 'sg')
222 ->where('s.id IN (:subscribers)')
223 ->setParameter('subscribers', $subscribers)
224 ->getQuery()
225 ->getResult();
226 // Prefetch tags
227 $this->entityManager->createQueryBuilder()
228 ->select('PARTIAL s.{id}, st, t')
229 ->from(SubscriberEntity::class, 's')
230 ->leftJoin('s.subscriberTags', 'st')
231 ->leftJoin('st.tag', 't')
232 ->where('s.id IN (:subscribers)')
233 ->setParameter('subscribers', $subscribers)
234 ->getQuery()
235 ->getResult();
236 }
237 }
238