Use doctrine for save Subscriber

[MAILPOET-3031]
This commit is contained in:
Jan Lysý
2021-03-24 10:15:00 +01:00
committed by Veljko V
parent b8e7fb3dd0
commit dcc70b3865
3 changed files with 47 additions and 105 deletions

View File

@ -79,7 +79,18 @@ class SubscribersResponseBuilder {
'last_name' => $subscriberEntity->getLastName(), 'last_name' => $subscriberEntity->getLastName(),
'first_name' => $subscriberEntity->getFirstName(), 'first_name' => $subscriberEntity->getFirstName(),
'email' => $subscriberEntity->getEmail(), 'email' => $subscriberEntity->getEmail(),
'created_at' => $subscriberEntity->getCreatedAt()->format(self::DATE_FORMAT),
'updated_at' => $subscriberEntity->getUpdatedAt()->format(self::DATE_FORMAT),
'deleted_at' => ($deletedAt = $subscriberEntity->getDeletedAt()) ? $deletedAt->format(self::DATE_FORMAT) : null, 'deleted_at' => ($deletedAt = $subscriberEntity->getDeletedAt()) ? $deletedAt->format(self::DATE_FORMAT) : null,
'subscribed_ip' => $subscriberEntity->getSubscribedIp(),
'confirmed_ip' => $subscriberEntity->getConfirmedIp(),
'confirmed_at' => ($confirmedAt = $subscriberEntity->getConfirmedAt()) ? $confirmedAt->format(self::DATE_FORMAT) : null,
'last_subscribed_at' => ($lastSubscribedAt = $subscriberEntity->getLastSubscribedAt()) ? $lastSubscribedAt->format(self::DATE_FORMAT) : null,
'unconfirmed_data' => $subscriberEntity->getUnconfirmedData(),
'source' => $subscriberEntity->getSource(),
'count_confirmations' => $subscriberEntity->getConfirmationsCount(),
'unsubscribe_token' => $subscriberEntity->getUnsubscribeToken(),
'link_token' => $subscriberEntity->getLinkToken(),
]; ];
$data = $this->buildCustomFields($subscriberEntity, $data); $data = $this->buildCustomFields($subscriberEntity, $data);
return $data; return $data;

View File

@ -7,27 +7,23 @@ use MailPoet\API\JSON\Error as APIError;
use MailPoet\API\JSON\Response as APIResponse; use MailPoet\API\JSON\Response as APIResponse;
use MailPoet\API\JSON\ResponseBuilders\SubscribersResponseBuilder; use MailPoet\API\JSON\ResponseBuilders\SubscribersResponseBuilder;
use MailPoet\Config\AccessControl; use MailPoet\Config\AccessControl;
use MailPoet\Doctrine\Validator\ValidationException;
use MailPoet\Entities\FormEntity; use MailPoet\Entities\FormEntity;
use MailPoet\Entities\SegmentEntity; use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\StatisticsUnsubscribeEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
use MailPoet\Form\FormsRepository; use MailPoet\Form\FormsRepository;
use MailPoet\Form\Util\FieldNameObfuscator; use MailPoet\Form\Util\FieldNameObfuscator;
use MailPoet\Listing; use MailPoet\Listing;
use MailPoet\Models\Form; use MailPoet\Models\Form;
use MailPoet\Models\Segment;
use MailPoet\Models\StatisticsForms; use MailPoet\Models\StatisticsForms;
use MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberSegment;
use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
use MailPoet\Segments\SegmentsRepository; use MailPoet\Segments\SegmentsRepository;
use MailPoet\Settings\SettingsController; use MailPoet\Settings\SettingsController;
use MailPoet\Statistics\Track\Unsubscribes;
use MailPoet\Subscribers\ConfirmationEmailMailer; use MailPoet\Subscribers\ConfirmationEmailMailer;
use MailPoet\Subscribers\RequiredCustomFieldValidator; use MailPoet\Subscribers\RequiredCustomFieldValidator;
use MailPoet\Subscribers\Source;
use MailPoet\Subscribers\SubscriberActions; use MailPoet\Subscribers\SubscriberActions;
use MailPoet\Subscribers\SubscriberListingRepository; use MailPoet\Subscribers\SubscriberListingRepository;
use MailPoet\Subscribers\SubscriberSaveController;
use MailPoet\Subscribers\SubscribersRepository; use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Subscription\Captcha; use MailPoet\Subscription\Captcha;
use MailPoet\Subscription\CaptchaSession; use MailPoet\Subscription\CaptchaSession;
@ -56,9 +52,6 @@ class Subscribers extends APIEndpoint {
/** @var Captcha */ /** @var Captcha */
private $subscriptionCaptcha; private $subscriptionCaptcha;
/** @var WPFunctions */
private $wp;
/** @var SettingsController */ /** @var SettingsController */
private $settings; private $settings;
@ -74,9 +67,6 @@ class Subscribers extends APIEndpoint {
/** @var FieldNameObfuscator */ /** @var FieldNameObfuscator */
private $fieldNameObfuscator; private $fieldNameObfuscator;
/** @var Unsubscribes */
private $unsubscribesTracker;
/** @var SubscribersRepository */ /** @var SubscribersRepository */
private $subscribersRepository; private $subscribersRepository;
@ -89,48 +79,44 @@ class Subscribers extends APIEndpoint {
/** @var SegmentsRepository */ /** @var SegmentsRepository */
private $segmentsRepository; private $segmentsRepository;
/** @var WelcomeScheduler */
private $welcomeScheduler;
/** @var FormsRepository */ /** @var FormsRepository */
private $formsRepository; private $formsRepository;
/** @var SubscriberSaveController */
private $saveController;
public function __construct( public function __construct(
SubscriberActions $subscriberActions, SubscriberActions $subscriberActions,
RequiredCustomFieldValidator $requiredCustomFieldValidator, RequiredCustomFieldValidator $requiredCustomFieldValidator,
Listing\Handler $listingHandler, Listing\Handler $listingHandler,
Captcha $subscriptionCaptcha, Captcha $subscriptionCaptcha,
WPFunctions $wp,
SettingsController $settings, SettingsController $settings,
CaptchaSession $captchaSession, CaptchaSession $captchaSession,
ConfirmationEmailMailer $confirmationEmailMailer, ConfirmationEmailMailer $confirmationEmailMailer,
SubscriptionUrlFactory $subscriptionUrlFactory, SubscriptionUrlFactory $subscriptionUrlFactory,
Unsubscribes $unsubscribesTracker,
SubscribersRepository $subscribersRepository, SubscribersRepository $subscribersRepository,
SubscribersResponseBuilder $subscribersResponseBuilder, SubscribersResponseBuilder $subscribersResponseBuilder,
SubscriberListingRepository $subscriberListingRepository, SubscriberListingRepository $subscriberListingRepository,
SegmentsRepository $segmentsRepository, SegmentsRepository $segmentsRepository,
FieldNameObfuscator $fieldNameObfuscator, FieldNameObfuscator $fieldNameObfuscator,
WelcomeScheduler $welcomeScheduler, FormsRepository $formsRepository,
FormsRepository $formsRepository SubscriberSaveController $saveController
) { ) {
$this->subscriberActions = $subscriberActions; $this->subscriberActions = $subscriberActions;
$this->requiredCustomFieldValidator = $requiredCustomFieldValidator; $this->requiredCustomFieldValidator = $requiredCustomFieldValidator;
$this->listingHandler = $listingHandler; $this->listingHandler = $listingHandler;
$this->subscriptionCaptcha = $subscriptionCaptcha; $this->subscriptionCaptcha = $subscriptionCaptcha;
$this->wp = $wp;
$this->settings = $settings; $this->settings = $settings;
$this->captchaSession = $captchaSession; $this->captchaSession = $captchaSession;
$this->confirmationEmailMailer = $confirmationEmailMailer; $this->confirmationEmailMailer = $confirmationEmailMailer;
$this->subscriptionUrlFactory = $subscriptionUrlFactory; $this->subscriptionUrlFactory = $subscriptionUrlFactory;
$this->fieldNameObfuscator = $fieldNameObfuscator; $this->fieldNameObfuscator = $fieldNameObfuscator;
$this->unsubscribesTracker = $unsubscribesTracker;
$this->subscribersRepository = $subscribersRepository; $this->subscribersRepository = $subscribersRepository;
$this->subscribersResponseBuilder = $subscribersResponseBuilder; $this->subscribersResponseBuilder = $subscribersResponseBuilder;
$this->subscriberListingRepository = $subscriberListingRepository; $this->subscriberListingRepository = $subscriberListingRepository;
$this->segmentsRepository = $segmentsRepository; $this->segmentsRepository = $segmentsRepository;
$this->welcomeScheduler = $welcomeScheduler;
$this->formsRepository = $formsRepository; $this->formsRepository = $formsRepository;
$this->saveController = $saveController;
} }
public function get($data = []) { public function get($data = []) {
@ -358,85 +344,17 @@ class Subscribers extends APIEndpoint {
} }
public function save($data = []) { public function save($data = []) {
if (empty($data['segments'])) { try {
$data['segments'] = []; $subscriber = $this->saveController->save($data);
} } catch (ValidationException $validationException) {
$data['segments'] = array_merge($data['segments'], $this->getNonDefaultSubscribedSegments($data)); return $this->badRequest([$this->getErrorMessage($validationException)]);
$newSegments = $this->findNewSegments($data);
if (isset($data['id']) && (int)$data['id'] > 0) {
$oldSubscriber = Subscriber::findOne((int)$data['id']);
if (
isset($data['status'])
&& ($data['status'] === SubscriberEntity::STATUS_UNSUBSCRIBED)
&& ($oldSubscriber instanceof Subscriber)
&& ($oldSubscriber->status !== SubscriberEntity::STATUS_UNSUBSCRIBED)
) {
$currentUser = $this->wp->wpGetCurrentUser();
$this->unsubscribesTracker->track(
(int)$oldSubscriber->id,
StatisticsUnsubscribeEntity::SOURCE_ADMINISTRATOR,
null,
$currentUser->display_name // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps
);
}
}
$subscriber = Subscriber::createOrUpdate($data);
$errors = $subscriber->getErrors();
if (!empty($errors)) {
return $this->badRequest($errors);
}
if ($subscriber->isNew()) {
$subscriber = Source::setSource($subscriber, Source::ADMINISTRATOR);
$subscriber->save();
}
if (!empty($newSegments)) {
$this->welcomeScheduler->scheduleSubscriberWelcomeNotification($subscriber->id, $newSegments);
} }
return $this->successResponse( return $this->successResponse(
Subscriber::findOne($subscriber->id)->asArray() $this->subscribersResponseBuilder->build($subscriber)
); );
} }
private function getNonDefaultSubscribedSegments(array $data) {
if (!isset($data['id']) || (int)$data['id'] <= 0) {
return [];
}
$subscribedSegmentIds = [];
$nonDefaultSegment = Segment::select('id')
->whereNotEqual('type', Segment::TYPE_DEFAULT)
->findArray();
$nonDefaultSegmentIds = array_map(function($segment) {
return $segment['id'];
}, $nonDefaultSegment);
$subscribedSegments = SubscriberSegment::select('segment_id')
->where('subscriber_id', $data['id'])
->where('status', Subscriber::STATUS_SUBSCRIBED)
->whereIn('segment_id', $nonDefaultSegmentIds)
->findArray();
$subscribedSegmentIds = array_map(function($segment) {
return $segment['segment_id'];
}, $subscribedSegments);
return $subscribedSegmentIds;
}
private function findNewSegments(array $data) {
$oldSegmentIds = [];
if (isset($data['id']) && (int)$data['id'] > 0) {
$oldSegments = SubscriberSegment::where('subscriber_id', $data['id'])->findMany();
foreach ($oldSegments as $oldSegment) {
$oldSegmentIds[] = $oldSegment->segmentId;
}
}
return array_diff($data['segments'], $oldSegmentIds);
}
public function restore($data = []) { public function restore($data = []) {
$subscriber = $this->getSubscriber($data); $subscriber = $this->getSubscriber($data);
if ($subscriber instanceof SubscriberEntity) { if ($subscriber instanceof SubscriberEntity) {
@ -565,4 +483,15 @@ class Subscribers extends APIEndpoint {
} }
return $formEntity->getSettingsSegmentIds(); return $formEntity->getSettingsSegmentIds();
} }
private function getErrorMessage(ValidationException $exception): string {
$exceptionMessage = $exception->getMessage();
if (strpos($exceptionMessage, 'This value should not be blank.') !== false) {
return WPFunctions::get()->__('Please enter your email address', 'mailpoet');
} elseif (strpos($exceptionMessage, 'This value is not a valid email address.') !== false) {
return WPFunctions::get()->__('Your email address is invalid!', 'mailpoet');
}
return WPFunctions::get()->__('Unexpected error.', 'mailpoet');
}
} }

View File

@ -31,17 +31,16 @@ use MailPoet\Models\SendingQueue;
use MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberIP; use MailPoet\Models\SubscriberIP;
use MailPoet\Models\SubscriberSegment; use MailPoet\Models\SubscriberSegment;
use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
use MailPoet\Segments\SegmentsRepository; use MailPoet\Segments\SegmentsRepository;
use MailPoet\Settings\SettingsController; use MailPoet\Settings\SettingsController;
use MailPoet\Settings\SettingsRepository; use MailPoet\Settings\SettingsRepository;
use MailPoet\Statistics\Track\Unsubscribes;
use MailPoet\Subscribers\ConfirmationEmailMailer; use MailPoet\Subscribers\ConfirmationEmailMailer;
use MailPoet\Subscribers\LinkTokens; use MailPoet\Subscribers\LinkTokens;
use MailPoet\Subscribers\RequiredCustomFieldValidator; use MailPoet\Subscribers\RequiredCustomFieldValidator;
use MailPoet\Subscribers\Source; use MailPoet\Subscribers\Source;
use MailPoet\Subscribers\SubscriberActions; use MailPoet\Subscribers\SubscriberActions;
use MailPoet\Subscribers\SubscriberListingRepository; use MailPoet\Subscribers\SubscriberListingRepository;
use MailPoet\Subscribers\SubscriberSaveController;
use MailPoet\Subscribers\SubscribersRepository; use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Subscription\Captcha; use MailPoet\Subscription\Captcha;
use MailPoet\Subscription\CaptchaSession; use MailPoet\Subscription\CaptchaSession;
@ -81,6 +80,9 @@ class SubscribersTest extends \MailPoetTest {
/** @var CaptchaSession */ /** @var CaptchaSession */
private $captchaSession; private $captchaSession;
/** @var SubscribersResponseBuilder */
private $responseBuilder;
public function _before() { public function _before() {
parent::_before(); parent::_before();
$this->cleanup(); $this->cleanup();
@ -88,25 +90,24 @@ class SubscribersTest extends \MailPoetTest {
$settings = $container->get(SettingsController::class); $settings = $container->get(SettingsController::class);
$wp = $container->get(Functions::class); $wp = $container->get(Functions::class);
$this->captchaSession = new CaptchaSession($container->get(Functions::class)); $this->captchaSession = new CaptchaSession($container->get(Functions::class));
$this->responseBuilder = $container->get(SubscribersResponseBuilder::class);
$obfuscator = new FieldNameObfuscator($wp); $obfuscator = new FieldNameObfuscator($wp);
$this->endpoint = new Subscribers( $this->endpoint = new Subscribers(
$container->get(SubscriberActions::class), $container->get(SubscriberActions::class),
$container->get(RequiredCustomFieldValidator::class), $container->get(RequiredCustomFieldValidator::class),
$container->get(Handler::class), $container->get(Handler::class),
$container->get(Captcha::class), $container->get(Captcha::class),
$wp,
$settings, $settings,
$this->captchaSession, $this->captchaSession,
$container->get(ConfirmationEmailMailer::class), $container->get(ConfirmationEmailMailer::class),
new SubscriptionUrlFactory($wp, $settings, new LinkTokens), new SubscriptionUrlFactory($wp, $settings, new LinkTokens),
$container->get(Unsubscribes::class),
$container->get(SubscribersRepository::class), $container->get(SubscribersRepository::class),
$container->get(SubscribersResponseBuilder::class), $this->responseBuilder,
$container->get(SubscriberListingRepository::class), $container->get(SubscriberListingRepository::class),
$container->get(SegmentsRepository::class), $container->get(SegmentsRepository::class),
$obfuscator, $obfuscator,
$container->get(WelcomeScheduler::class), $container->get(FormsRepository::class),
$container->get(FormsRepository::class) $container->get(SubscriberSaveController::class)
); );
$this->obfuscatedEmail = $obfuscator->obfuscate('email'); $this->obfuscatedEmail = $obfuscator->obfuscate('email');
$this->obfuscatedSegments = $obfuscator->obfuscate('segments'); $this->obfuscatedSegments = $obfuscator->obfuscate('segments');
@ -202,6 +203,7 @@ class SubscribersTest extends \MailPoetTest {
$response = $this->endpoint->save($validData); $response = $this->endpoint->save($validData);
expect($response->status)->equals(APIResponse::STATUS_OK); expect($response->status)->equals(APIResponse::STATUS_OK);
$this->entityManager->clear();
$subscriberRepository = $this->diContainer->get(SubscribersRepository::class); $subscriberRepository = $this->diContainer->get(SubscribersRepository::class);
$subscriber = $subscriberRepository->findOneBy(['email' => 'raul.doe@mailpoet.com']); $subscriber = $subscriberRepository->findOneBy(['email' => 'raul.doe@mailpoet.com']);
expect($response->data['email'])->equals('raul.doe@mailpoet.com'); expect($response->data['email'])->equals('raul.doe@mailpoet.com');
@ -242,7 +244,7 @@ class SubscribersTest extends \MailPoetTest {
$response = $this->endpoint->save($subscriberData); $response = $this->endpoint->save($subscriberData);
expect($response->status)->equals(APIResponse::STATUS_OK); expect($response->status)->equals(APIResponse::STATUS_OK);
expect($response->data)->equals( expect($response->data)->equals(
Subscriber::findOne($this->subscriber2->getId())->asArray() $this->responseBuilder->build($this->subscriber2)
); );
expect($response->data['first_name'])->equals('Super Jane'); expect($response->data['first_name'])->equals('Super Jane');
expect($response->data['source'])->equals('api'); expect($response->data['source'])->equals('api');
@ -260,7 +262,7 @@ class SubscribersTest extends \MailPoetTest {
$response = $this->endpoint->save($subscriberData); $response = $this->endpoint->save($subscriberData);
expect($response->status)->equals(APIResponse::STATUS_OK); expect($response->status)->equals(APIResponse::STATUS_OK);
expect($response->data)->equals( expect($response->data)->equals(
Subscriber::findOne($this->subscriber2->getId())->asArray() $this->responseBuilder->build($this->subscriber2)
); );
expect($this->subscriber2->getSegments()->count())->equals(0); expect($this->subscriber2->getSegments()->count())->equals(0);
} }