No Description

Manage.php 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. <?php
  2. namespace MailPoet\Subscription;
  3. if (!defined('ABSPATH')) exit;
  4. use MailPoet\Entities\StatisticsUnsubscribeEntity;
  5. use MailPoet\Entities\SubscriberEntity;
  6. use MailPoet\Entities\SubscriberSegmentEntity;
  7. use MailPoet\Form\Util\FieldNameObfuscator;
  8. use MailPoet\InvalidStateException;
  9. use MailPoet\Models\CustomField;
  10. use MailPoet\Models\Segment;
  11. use MailPoet\Models\Subscriber;
  12. use MailPoet\Models\SubscriberSegment;
  13. use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
  14. use MailPoet\Settings\SettingsController;
  15. use MailPoet\Statistics\Track\Unsubscribes;
  16. use MailPoet\Subscribers\LinkTokens;
  17. use MailPoet\Subscribers\NewSubscriberNotificationMailer;
  18. use MailPoet\Subscribers\SubscriberSegmentRepository;
  19. use MailPoet\Subscribers\SubscribersRepository;
  20. use MailPoet\Util\Url as UrlHelper;
  21. class Manage {
  22. /** @var UrlHelper */
  23. private $urlHelper;
  24. /** @var FieldNameObfuscator */
  25. private $fieldNameObfuscator;
  26. /** @var LinkTokens */
  27. private $linkTokens;
  28. /** @var SettingsController */
  29. private $settings;
  30. /** @var Unsubscribes */
  31. private $unsubscribesTracker;
  32. /** @var NewSubscriberNotificationMailer */
  33. private $newSubscriberNotificationMailer;
  34. /** @var WelcomeScheduler */
  35. private $welcomeScheduler;
  36. /** @var SubscribersRepository */
  37. private $subscribersRepository;
  38. /** @var SubscriberSegmentRepository */
  39. private $subscriberSegmentRepository;
  40. public function __construct(
  41. UrlHelper $urlHelper,
  42. FieldNameObfuscator $fieldNameObfuscator,
  43. LinkTokens $linkTokens,
  44. Unsubscribes $unsubscribesTracker,
  45. SettingsController $settings,
  46. NewSubscriberNotificationMailer $newSubscriberNotificationMailer,
  47. WelcomeScheduler $welcomeScheduler,
  48. SubscribersRepository $subscribersRepository,
  49. SubscriberSegmentRepository $subscriberSegmentRepository
  50. ) {
  51. $this->urlHelper = $urlHelper;
  52. $this->fieldNameObfuscator = $fieldNameObfuscator;
  53. $this->unsubscribesTracker = $unsubscribesTracker;
  54. $this->linkTokens = $linkTokens;
  55. $this->settings = $settings;
  56. $this->newSubscriberNotificationMailer = $newSubscriberNotificationMailer;
  57. $this->welcomeScheduler = $welcomeScheduler;
  58. $this->subscribersRepository = $subscribersRepository;
  59. $this->subscriberSegmentRepository = $subscriberSegmentRepository;
  60. }
  61. public function onSave() {
  62. $action = (isset($_POST['action']) ? $_POST['action'] : null);
  63. $token = (isset($_POST['token']) ? $_POST['token'] : null);
  64. if ($action !== 'mailpoet_subscription_update' || empty($_POST['data'])) {
  65. $this->urlHelper->redirectBack();
  66. }
  67. $subscriberData = $_POST['data'];
  68. $subscriberData = $this->fieldNameObfuscator->deobfuscateFormPayload($subscriberData);
  69. $result = [];
  70. if (!empty($subscriberData['email'])) {
  71. $subscriber = $this->subscribersRepository->findOneBy(['email' => $subscriberData['email']]);
  72. if (
  73. ($subscriberData['status'] === SubscriberEntity::STATUS_UNSUBSCRIBED)
  74. && ($subscriber instanceof SubscriberEntity)
  75. && ($subscriber->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED)
  76. ) {
  77. $this->unsubscribesTracker->track(
  78. (int)$subscriber->getId(),
  79. StatisticsUnsubscribeEntity::SOURCE_MANAGE
  80. );
  81. }
  82. if ($subscriber && $this->linkTokens->verifyToken($subscriber, $token)) {
  83. $subscriberModel = Subscriber::findOne($subscriber->getId());
  84. if (!$subscriberModel instanceof Subscriber) {
  85. throw new InvalidStateException();
  86. }
  87. if ($subscriberData['email'] !== Pages::DEMO_EMAIL) {
  88. $this->updateSubscriptions($subscriberModel, $subscriberData);
  89. unset($subscriberData['segments']);
  90. $subscriberModel = Subscriber::createOrUpdate($this->filterOutEmptyMandatoryFields($subscriberData));
  91. $subscriberModel->getErrors();
  92. }
  93. }
  94. $result = ['success' => true];
  95. }
  96. $this->urlHelper->redirectBack($result);
  97. }
  98. private function updateSubscriptions(Subscriber $subscriber, array $subscriberData) {
  99. $segmentsIds = [];
  100. if (isset($subscriberData['segments']) && is_array($subscriberData['segments'])) {
  101. $segmentsIds = $subscriberData['segments'];
  102. }
  103. $subscriber->withSubscriptions();
  104. $allowedSegments = $this->settings->get('subscription.segments', false);
  105. // Unsubscribe from all other segments already subscribed to
  106. // but don't change disallowed segments
  107. foreach ($subscriber->subscriptions as $subscription) {
  108. $segmentId = $subscription['segment_id'];
  109. if ($allowedSegments && !in_array($segmentId, $allowedSegments)) {
  110. continue;
  111. }
  112. if (!in_array($segmentId, $segmentsIds)) {
  113. SubscriberSegment::createOrUpdate([
  114. 'subscriber_id' => $subscriber->id,
  115. 'segment_id' => $segmentId,
  116. 'status' => Subscriber::STATUS_UNSUBSCRIBED,
  117. ]);
  118. }
  119. }
  120. // Store new segments for notifications
  121. $subscriberSegments = $this->subscriberSegmentRepository->findBy([
  122. 'status' => SubscriberEntity::STATUS_SUBSCRIBED,
  123. 'subscriber' => $subscriber->id,
  124. ]);
  125. $currentSegmentIds = array_filter(array_map(function (SubscriberSegmentEntity $subscriberSegment): ?string {
  126. $segment = $subscriberSegment->getSegment();
  127. return $segment ? (string)$segment->getId() : null;
  128. }, $subscriberSegments));
  129. $newSegmentIds = array_diff($segmentsIds, $currentSegmentIds);
  130. // Allow subscribing only to allowed segments
  131. if ($allowedSegments) {
  132. $segmentsIds = array_intersect($segmentsIds, $allowedSegments);
  133. }
  134. foreach ($segmentsIds as $segmentId) {
  135. SubscriberSegment::createOrUpdate([
  136. 'subscriber_id' => $subscriber->id,
  137. 'segment_id' => $segmentId,
  138. 'status' => Subscriber::STATUS_SUBSCRIBED,
  139. ]);
  140. }
  141. if ($subscriber->status === SubscriberEntity::STATUS_SUBSCRIBED && $newSegmentIds) {
  142. $this->newSubscriberNotificationMailer->send($subscriber, Segment::whereIn('id', $newSegmentIds)->findMany());
  143. $this->welcomeScheduler->scheduleSubscriberWelcomeNotification(
  144. $subscriber->id,
  145. $newSegmentIds
  146. );
  147. }
  148. }
  149. private function filterOutEmptyMandatoryFields(array $subscriberData) {
  150. $mandatory = $this->getMandatory();
  151. foreach ($mandatory as $name) {
  152. if (strlen(trim($subscriberData[$name])) === 0) {
  153. unset($subscriberData[$name]);
  154. }
  155. }
  156. return $subscriberData;
  157. }
  158. private function getMandatory() {
  159. $mandatory = [];
  160. $requiredCustomFields = CustomField::findMany();
  161. foreach ($requiredCustomFields as $customField) {
  162. if (is_serialized($customField->params)) {
  163. $params = unserialize($customField->params);
  164. } else {
  165. $params = $customField->params;
  166. }
  167. if (
  168. is_array($params)
  169. && isset($params['required'])
  170. && $params['required']
  171. ) {
  172. $mandatory[] = 'cf_' . $customField->id;
  173. }
  174. }
  175. return $mandatory;
  176. }
  177. }