PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.33.1
MailPoet – Newsletters, Email Marketing, and Automation v5.33.1
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 / Subscription / Manage.php
mailpoet / lib / Subscription Last commit date
AdminUserSubscription.php 3 months ago Blacklist.php 1 year ago Comment.php 3 months ago Form.php 1 month ago Manage.php 1 month ago ManageSubscriptionFormRenderer.php 3 months ago Pages.php 1 month ago Registration.php 3 months ago SubscriptionUrlFactory.php 3 months ago Throttling.php 3 months ago index.php 3 years ago
Manage.php
494 lines
1 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
2
3 namespace MailPoet\Subscription;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\CustomFields\CustomFieldsRepository;
9 use MailPoet\Entities\SegmentEntity;
10 use MailPoet\Entities\StatisticsUnsubscribeEntity;
11 use MailPoet\Entities\SubscriberEntity;
12 use MailPoet\Entities\SubscriberSegmentEntity;
13 use MailPoet\Form\Util\FieldNameObfuscator;
14 use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
15 use MailPoet\Segments\SegmentsRepository;
16 use MailPoet\Statistics\Track\Unsubscribes;
17 use MailPoet\Subscribers\LinkTokens;
18 use MailPoet\Subscribers\NewSubscriberNotificationMailer;
19 use MailPoet\Subscribers\SubscriberSaveController;
20 use MailPoet\Subscribers\SubscriberSegmentRepository;
21 use MailPoet\Subscribers\SubscribersRepository;
22 use MailPoet\Util\Url as UrlHelper;
23 use MailPoetVendor\Doctrine\DBAL\ArrayParameterType;
24
25 class Manage {
26
27 /** @var UrlHelper */
28 private $urlHelper;
29
30 /** @var FieldNameObfuscator */
31 private $fieldNameObfuscator;
32
33 /** @var LinkTokens */
34 private $linkTokens;
35
36 /** @var Unsubscribes */
37 private $unsubscribesTracker;
38
39 /** @var NewSubscriberNotificationMailer */
40 private $newSubscriberNotificationMailer;
41
42 /** @var WelcomeScheduler */
43 private $welcomeScheduler;
44
45 /** @var CustomFieldsRepository */
46 private $customFieldsRepository;
47
48 /** @var SegmentsRepository */
49 private $segmentsRepository;
50
51 /** @var SubscribersRepository */
52 private $subscribersRepository;
53
54 /** @var SubscriberSegmentRepository */
55 private $subscriberSegmentRepository;
56
57 /** @var SubscriberSaveController */
58 private $subscriberSaveController;
59
60 public function __construct(
61 UrlHelper $urlHelper,
62 FieldNameObfuscator $fieldNameObfuscator,
63 LinkTokens $linkTokens,
64 Unsubscribes $unsubscribesTracker,
65 NewSubscriberNotificationMailer $newSubscriberNotificationMailer,
66 WelcomeScheduler $welcomeScheduler,
67 CustomFieldsRepository $customFieldsRepository,
68 SegmentsRepository $segmentsRepository,
69 SubscribersRepository $subscribersRepository,
70 SubscriberSegmentRepository $subscriberSegmentRepository,
71 SubscriberSaveController $subscriberSaveController
72 ) {
73 $this->urlHelper = $urlHelper;
74 $this->fieldNameObfuscator = $fieldNameObfuscator;
75 $this->unsubscribesTracker = $unsubscribesTracker;
76 $this->linkTokens = $linkTokens;
77 $this->newSubscriberNotificationMailer = $newSubscriberNotificationMailer;
78 $this->welcomeScheduler = $welcomeScheduler;
79 $this->segmentsRepository = $segmentsRepository;
80 $this->subscribersRepository = $subscribersRepository;
81 $this->subscriberSegmentRepository = $subscriberSegmentRepository;
82 $this->customFieldsRepository = $customFieldsRepository;
83 $this->subscriberSaveController = $subscriberSaveController;
84 }
85
86 public function onSave() {
87 $action = (isset($_POST['action']) && is_string($_POST['action']) ? sanitize_text_field(wp_unslash($_POST['action'])) : '');
88 $token = (isset($_POST['token']) && is_string($_POST['token']) ? sanitize_text_field(wp_unslash($_POST['token'])) : '');
89
90 if ($action !== 'mailpoet_subscription_update' || empty($_POST['data'])) {
91 $this->urlHelper->redirectBack();
92 return;
93 }
94
95 //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
96 $subscriberData = $this->fieldNameObfuscator->deobfuscateFormPayload(wp_unslash((array)$_POST['data']));
97 $subscriberData = $this->sanitizeFormValue($subscriberData);
98 if (!is_array($subscriberData)) {
99 $subscriberData = [];
100 }
101 if ($this->hasInvalidStatus($subscriberData) || $this->hasMalformedLegacySegmentIds($subscriberData)) {
102 $this->urlHelper->redirectBack(['error' => true]);
103 return;
104 }
105
106 $result = ['error' => true];
107 if (!empty($subscriberData['email'])) {
108 $subscriber = $this->subscribersRepository->findOneBy(['email' => $subscriberData['email']]);
109
110 if ($subscriber && $this->linkTokens->verifyToken($subscriber, $token)) {
111 if ($subscriberData['email'] !== Pages::DEMO_EMAIL) {
112 $previousStatus = $subscriber->getStatus();
113 $shouldTrackUnsubscribe = (
114 ($subscriberData['status'] ?? '') === SubscriberEntity::STATUS_UNSUBSCRIBED
115 && $subscriber instanceof SubscriberEntity
116 && $subscriber->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED
117 );
118 $subscriber = $this->subscriberSaveController->createOrUpdate($this->filterToEditableFields($subscriberData), $subscriber);
119 if ($shouldTrackUnsubscribe) {
120 $this->unsubscribesTracker->track(
121 (int)$subscriber->getId(),
122 StatisticsUnsubscribeEntity::SOURCE_MANAGE
123 );
124 }
125 $this->subscriberSaveController->updateCustomFields($this->filterOutEmptyMandatoryFields($subscriberData), $subscriber);
126 $this->updateSubscriptions(
127 $subscriber,
128 $subscriberData,
129 $previousStatus !== SubscriberEntity::STATUS_SUBSCRIBED
130 && $subscriber->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED
131 );
132 }
133 $result = ['success' => true];
134 }
135 }
136
137 $this->urlHelper->redirectBack($result);
138 }
139
140 private function updateSubscriptions(
141 SubscriberEntity $subscriber,
142 array $subscriberData,
143 bool $isGlobalResubscribe
144 ): void {
145 if ($subscriber->getStatus() !== SubscriberEntity::STATUS_SUBSCRIBED) {
146 return;
147 }
148
149 if (array_key_exists('segment_choices', $subscriberData)) {
150 $this->updateSubscriptionsFromSegmentChoices(
151 $subscriber,
152 $subscriberData['segment_choices'],
153 $isGlobalResubscribe
154 );
155 return;
156 }
157
158 $segmentsIds = $this->getLegacySegmentIds($subscriberData);
159 $legacySegmentIds = $segmentsIds;
160 $segments = $this->getVisibleDefaultManageSegmentsByIds($legacySegmentIds);
161 $segmentsIds = array_map('intval', array_keys($segments));
162 if ($legacySegmentIds && !$segmentsIds) {
163 return;
164 }
165
166 // Unsubscribe from all other segments already subscribed to
167 // but don't change disallowed segments
168 foreach ($subscriber->getSubscriberSegments() as $subscriberSegment) {
169 $segment = $subscriberSegment->getSegment();
170 if (!$segment) {
171 continue;
172 }
173
174 if (!$this->isVisibleDefaultManageSegment($segment)) {
175 continue;
176 }
177 if (!in_array((int)$segment->getId(), $segmentsIds, true)) {
178 $this->subscriberSegmentRepository->createOrUpdate(
179 $subscriber,
180 $segment,
181 SubscriberEntity::STATUS_UNSUBSCRIBED,
182 false,
183 true
184 );
185 }
186 }
187
188 $currentSegmentIds = $this->getCurrentSubscribedSegmentIds($subscriber);
189 $newSegmentIds = array_diff($segmentsIds, $currentSegmentIds);
190
191 foreach ($segmentsIds as $segmentId) {
192 $this->subscriberSegmentRepository->createOrUpdate(
193 $subscriber,
194 $segments[$segmentId],
195 SubscriberEntity::STATUS_SUBSCRIBED,
196 false,
197 true
198 );
199 }
200
201 $this->subscribersRepository->recalculateSegmentsCount([(int)$subscriber->getId()]);
202
203 $this->sendNotificationsForNewSegments(
204 $subscriber,
205 $isGlobalResubscribe ? $this->getCurrentSubscribedSegmentIds($subscriber) : $newSegmentIds
206 );
207 }
208
209 /**
210 * @param mixed $segmentChoices
211 */
212 private function updateSubscriptionsFromSegmentChoices(
213 SubscriberEntity $subscriber,
214 $segmentChoices,
215 bool $isGlobalResubscribe
216 ): void {
217 $choices = $this->getSegmentChoices($segmentChoices);
218 $segments = $this->getVisibleDefaultManageSegmentsByIds(array_keys($choices));
219 $subscribeIds = [];
220 $unsubscribeIds = [];
221
222 foreach ($choices as $segmentId => $choice) {
223 if (!isset($segments[$segmentId])) {
224 continue;
225 }
226 if ($choice === 'subscribed') {
227 $subscribeIds[] = $segmentId;
228 } elseif ($choice === 'unsubscribed') {
229 $unsubscribeIds[] = $segmentId;
230 }
231 }
232
233 $currentSegmentIds = $this->getCurrentSubscribedSegmentIds($subscriber);
234
235 foreach ($unsubscribeIds as $segmentId) {
236 $this->subscriberSegmentRepository->createOrUpdate(
237 $subscriber,
238 $segments[$segmentId],
239 SubscriberEntity::STATUS_UNSUBSCRIBED,
240 false,
241 true
242 );
243 }
244
245 foreach ($subscribeIds as $segmentId) {
246 $this->subscriberSegmentRepository->createOrUpdate(
247 $subscriber,
248 $segments[$segmentId],
249 SubscriberEntity::STATUS_SUBSCRIBED,
250 false,
251 true
252 );
253 }
254
255 $this->subscribersRepository->recalculateSegmentsCount([(int)$subscriber->getId()]);
256
257 $this->sendNotificationsForNewSegments(
258 $subscriber,
259 $isGlobalResubscribe
260 ? $this->getCurrentSubscribedSegmentIds($subscriber)
261 : array_diff($subscribeIds, $currentSegmentIds)
262 );
263 }
264
265 /**
266 * The manage-subscription form only edits the subscriber's name, email and
267 * global status. Subscription choices and custom fields are handled
268 * separately. Keep only those fields when saving the subscriber so any other
269 * submitted key is ignored. `status` is already validated by
270 * hasInvalidStatus().
271 */
272 private function filterToEditableFields(array $subscriberData): array {
273 return array_intersect_key(
274 $subscriberData,
275 array_flip(['email', 'first_name', 'last_name', 'status'])
276 );
277 }
278
279 private function hasInvalidStatus(array $subscriberData): bool {
280 if (!isset($subscriberData['status'])) {
281 return false;
282 }
283 return !in_array($subscriberData['status'], [
284 SubscriberEntity::STATUS_SUBSCRIBED,
285 SubscriberEntity::STATUS_UNSUBSCRIBED,
286 ], true);
287 }
288
289 /**
290 * @param mixed $value
291 * @return mixed
292 */
293 private function sanitizeFormValue($value, ?string $parentKey = null) {
294 if (is_array($value)) {
295 $sanitized = [];
296 foreach ($value as $key => $item) {
297 $sanitizedKey = $parentKey === 'segment_choices' ? $key : sanitize_text_field((string)$key);
298 $childParentKey = $parentKey === 'segments' ? 'segments' : (string)$sanitizedKey;
299 $sanitized[$sanitizedKey] = $this->sanitizeFormValue($item, $childParentKey);
300 }
301 return $sanitized;
302 }
303 if ($parentKey === 'segments') {
304 return is_scalar($value) ? (string)$value : '';
305 }
306 return sanitize_text_field(is_scalar($value) ? (string)$value : '');
307 }
308
309 /**
310 * @return int[]
311 */
312 private function getLegacySegmentIds(array $subscriberData): array {
313 if (!isset($subscriberData['segments']) || !is_array($subscriberData['segments'])) {
314 return [];
315 }
316
317 $segmentIds = [];
318 foreach ($subscriberData['segments'] as $segmentId) {
319 $segmentId = $this->normalizePositiveIntegerId($segmentId);
320 if ($segmentId === null) {
321 continue;
322 }
323 $segmentIds[] = $segmentId;
324 }
325 return array_values(array_unique($segmentIds));
326 }
327
328 private function hasMalformedLegacySegmentIds(array $subscriberData): bool {
329 if (!isset($subscriberData['segments'])) {
330 return false;
331 }
332 if ($subscriberData['segments'] === '') {
333 return false;
334 }
335 if (!is_array($subscriberData['segments'])) {
336 return true;
337 }
338
339 foreach ($subscriberData['segments'] as $segmentId) {
340 if ($segmentId === '') {
341 continue;
342 }
343 if ($this->normalizePositiveIntegerId($segmentId) === null) {
344 return true;
345 }
346 }
347 return false;
348 }
349
350 /**
351 * @param mixed $segmentChoices
352 * @return array<int, string>
353 */
354 private function getSegmentChoices($segmentChoices): array {
355 if (!is_array($segmentChoices)) {
356 return [];
357 }
358
359 $choices = [];
360 foreach ($segmentChoices as $segmentId => $choice) {
361 $segmentId = $this->normalizePositiveIntegerId($segmentId);
362 if ($segmentId === null || !is_string($choice)) {
363 continue;
364 }
365 if (!in_array($choice, ['subscribed', 'unsubscribed'], true)) {
366 continue;
367 }
368 $choices[$segmentId] = $choice;
369 }
370 return $choices;
371 }
372
373 /**
374 * @param mixed $segmentId
375 */
376 private function normalizePositiveIntegerId($segmentId): ?int {
377 if (is_int($segmentId)) {
378 return $segmentId > 0 ? $segmentId : null;
379 }
380 if (!is_string($segmentId) || $segmentId === '' || $segmentId[0] === '0' || !ctype_digit($segmentId)) {
381 return null;
382 }
383 $normalized = (int)$segmentId;
384 if ((string)$normalized !== $segmentId || $normalized <= 0) {
385 return null;
386 }
387 return $normalized;
388 }
389
390 /**
391 * @param int[] $segmentIds
392 * @return array<int, SegmentEntity>
393 */
394 private function getVisibleDefaultManageSegmentsByIds(array $segmentIds): array {
395 $segmentIds = array_values(array_unique(array_filter(array_map('intval', $segmentIds))));
396 if (!$segmentIds) {
397 return [];
398 }
399
400 $segments = $this->segmentsRepository->createQueryBuilder('s')
401 ->where('s.id IN (:ids)')
402 ->andWhere('s.type = :type')
403 ->andWhere('s.deletedAt IS NULL')
404 ->andWhere('s.displayInManageSubscriptionPage = :displayInManageSubscriptionPage')
405 ->setParameter('ids', $segmentIds, ArrayParameterType::INTEGER)
406 ->setParameter('type', SegmentEntity::TYPE_DEFAULT)
407 ->setParameter('displayInManageSubscriptionPage', true)
408 ->getQuery()
409 ->getResult();
410
411 $segmentsMap = [];
412 foreach ($segments as $segment) {
413 if ($segment instanceof SegmentEntity && $segment->getId()) {
414 $segmentsMap[(int)$segment->getId()] = $segment;
415 }
416 }
417 return $segmentsMap;
418 }
419
420 private function isVisibleDefaultManageSegment(SegmentEntity $segment): bool {
421 return (
422 $segment->getType() === SegmentEntity::TYPE_DEFAULT
423 && $segment->getDeletedAt() === null
424 && $segment->getDisplayInManageSubscriptionPage()
425 );
426 }
427
428 /**
429 * @return int[]
430 */
431 private function getCurrentSubscribedSegmentIds(SubscriberEntity $subscriber): array {
432 $subscriberSegments = $this->subscriberSegmentRepository->findBy([
433 'status' => SubscriberEntity::STATUS_SUBSCRIBED,
434 'subscriber' => $subscriber,
435 ]);
436 return array_values(array_filter(array_map(function (SubscriberSegmentEntity $subscriberSegment): ?int {
437 $segment = $subscriberSegment->getSegment();
438 return $segment ? (int)$segment->getId() : null;
439 }, $subscriberSegments)));
440 }
441
442 /**
443 * @param int[] $newSegmentIds
444 */
445 private function sendNotificationsForNewSegments(SubscriberEntity $subscriber, array $newSegmentIds): void {
446 $newSegmentIds = array_values(array_unique(array_map('intval', $newSegmentIds)));
447 if ($subscriber->getStatus() !== SubscriberEntity::STATUS_SUBSCRIBED || !$newSegmentIds) {
448 return;
449 }
450
451 $newSegments = $this->segmentsRepository->findByIds($newSegmentIds);
452 $this->newSubscriberNotificationMailer->send($subscriber, $newSegments);
453 $this->welcomeScheduler->scheduleSubscriberWelcomeNotification(
454 $subscriber->getId(),
455 $newSegmentIds
456 );
457 }
458
459 private function filterOutEmptyMandatoryFields(array $subscriberData): array {
460 $mandatory = $this->getMandatory();
461 foreach ($mandatory as $name) {
462 if (!isset($subscriberData[$name])) {
463 continue;
464 }
465 if (is_array($subscriberData[$name]) && count(array_filter($subscriberData[$name])) === 0) {
466 unset($subscriberData[$name]);
467 }
468 if (is_string($subscriberData[$name]) && strlen(trim($subscriberData[$name])) === 0) {
469 unset($subscriberData[$name]);
470 }
471 }
472 return $subscriberData;
473 }
474
475 /**
476 * @return string[]
477 */
478 private function getMandatory(): array {
479 $mandatory = [];
480 $requiredCustomFields = $this->customFieldsRepository->findAllActive();
481 foreach ($requiredCustomFields as $customField) {
482 $params = $customField->getParams();
483 if (
484 is_array($params)
485 && isset($params['required'])
486 && $params['required']
487 ) {
488 $mandatory[] = 'cf_' . $customField->getId();
489 }
490 }
491 return $mandatory;
492 }
493 }
494