Prevent invalid states due to filter segment
MAILPOET-5509
This commit is contained in:
committed by
Aschepikov
parent
77aef00652
commit
fe44df1884
@@ -11,6 +11,7 @@ use MailPoet\Cron\Workers\StatsNotifications\Scheduler as StatsNotificationsSche
|
||||
use MailPoet\Entities\NewsletterEntity;
|
||||
use MailPoet\Entities\ScheduledTaskEntity;
|
||||
use MailPoet\Entities\SubscriberEntity;
|
||||
use MailPoet\InvalidStateException;
|
||||
use MailPoet\Logging\LoggerFactory;
|
||||
use MailPoet\Mailer\MailerLog;
|
||||
use MailPoet\Mailer\MetaInfo;
|
||||
@@ -237,7 +238,17 @@ class SendingQueue {
|
||||
);
|
||||
if (!empty($newsletterSegmentsIds[0])) {
|
||||
// Check that subscribers are in segments
|
||||
try {
|
||||
$foundSubscribersIds = $this->subscribersFinder->findSubscribersInSegments($subscribersToProcessIds, $newsletterSegmentsIds, $filterSegmentId);
|
||||
} catch (InvalidStateException $exception) {
|
||||
$this->loggerFactory->getLogger(LoggerFactory::TOPIC_NEWSLETTERS)->info(
|
||||
'paused task in sending queue due to problem finding subscribers: ' . $exception->getMessage(),
|
||||
['task_id' => $queue->taskId]
|
||||
);
|
||||
$queue->status = ScheduledTaskEntity::STATUS_PAUSED;
|
||||
$queue->save();
|
||||
return;
|
||||
}
|
||||
$foundSubscribers = empty($foundSubscribersIds) ? [] : SubscriberModel::whereIn('id', $foundSubscribersIds)
|
||||
->whereNull('deleted_at')
|
||||
->findMany();
|
||||
|
@@ -36,6 +36,7 @@ class LoggerFactory {
|
||||
const TOPIC_TRACKING = 'tracking';
|
||||
const TOPIC_COUPONS = 'coupons';
|
||||
const TOPIC_PROVISIONING = 'provisioning';
|
||||
const TOPIC_SEGMENTS = 'segments';
|
||||
|
||||
/** @var LoggerFactory */
|
||||
private static $instance;
|
||||
|
@@ -11,6 +11,8 @@ use MailPoet\Entities\NewsletterSegmentEntity;
|
||||
use MailPoet\Entities\SegmentEntity;
|
||||
use MailPoet\Entities\SubscriberSegmentEntity;
|
||||
use MailPoet\Form\FormsRepository;
|
||||
use MailPoet\InvalidStateException;
|
||||
use MailPoet\Logging\LoggerFactory;
|
||||
use MailPoet\Newsletter\Segment\NewsletterSegmentRepository;
|
||||
use MailPoet\NotFoundException;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
@@ -33,16 +35,21 @@ class SegmentsRepository extends Repository {
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
/** @var LoggerFactory */
|
||||
private $loggerFactory;
|
||||
|
||||
public function __construct(
|
||||
EntityManager $entityManager,
|
||||
NewsletterSegmentRepository $newsletterSegmentRepository,
|
||||
FormsRepository $formsRepository,
|
||||
WPFunctions $wp
|
||||
WPFunctions $wp,
|
||||
LoggerFactory $loggerFactory
|
||||
) {
|
||||
parent::__construct($entityManager);
|
||||
$this->newsletterSegmentRepository = $newsletterSegmentRepository;
|
||||
$this->formsRepository = $formsRepository;
|
||||
$this->wp = $wp;
|
||||
$this->loggerFactory = $loggerFactory;
|
||||
}
|
||||
|
||||
protected function getEntityClassName() {
|
||||
@@ -136,6 +143,28 @@ class SegmentsRepository extends Repository {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return SegmentEntity
|
||||
* @throws InvalidStateException
|
||||
*/
|
||||
public function verifyFilterSegmentExists(int $id): SegmentEntity {
|
||||
try {
|
||||
$filterSegment = $this->findOneById($id);
|
||||
if (!$filterSegment instanceof SegmentEntity) {
|
||||
throw InvalidStateException::create()->withMessage("Filter segment with ID of $id could not be found.");
|
||||
}
|
||||
if ($filterSegment->getType() !== SegmentEntity::TYPE_DYNAMIC) {
|
||||
throw InvalidStateException::create()->withMessage("Filter segment ID must be a dynamic segment. Type of filter with ID {$filterSegment->getId()} is {$filterSegment->getType()}.");
|
||||
}
|
||||
} catch (InvalidStateException $exception) {
|
||||
$this->loggerFactory->getLogger(LoggerFactory::TOPIC_SEGMENTS)->error('Error verifying filter segment: ' . $exception->getMessage());
|
||||
throw $exception;
|
||||
}
|
||||
return $filterSegment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DynamicSegmentFilterData[] $filtersData
|
||||
* @throws ConflictException
|
||||
|
@@ -8,7 +8,6 @@ use MailPoet\Entities\SegmentEntity;
|
||||
use MailPoet\Entities\SubscriberEntity;
|
||||
use MailPoet\Entities\SubscriberSegmentEntity;
|
||||
use MailPoet\InvalidStateException;
|
||||
use MailPoet\UnexpectedValueException;
|
||||
use MailPoetVendor\Doctrine\DBAL\Connection;
|
||||
use MailPoetVendor\Doctrine\DBAL\ParameterType;
|
||||
use MailPoetVendor\Doctrine\ORM\EntityManager;
|
||||
@@ -34,6 +33,10 @@ class SubscribersFinder {
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws InvalidStateException
|
||||
*/
|
||||
public function findSubscribersInSegments($subscribersToProcessIds, $newsletterSegmentsIds, ?int $filterSegmentId = null) {
|
||||
$result = [];
|
||||
foreach ($newsletterSegmentsIds as $segmentId) {
|
||||
@@ -45,15 +48,10 @@ class SubscribersFinder {
|
||||
}
|
||||
|
||||
if (is_int($filterSegmentId)) {
|
||||
$filterSegment = $this->segmentsRepository->findOneById($filterSegmentId);
|
||||
if ($filterSegment instanceof SegmentEntity) {
|
||||
if ($filterSegment->getType() !== SegmentEntity::TYPE_DYNAMIC) {
|
||||
throw new UnexpectedValueException("Filter segment ID must be a dynamic segment. Type of filter with ID {$filterSegment->getId()} is {$filterSegment->getType()}.");
|
||||
}
|
||||
$filterSegment = $this->segmentsRepository->verifyFilterSegmentExists($filterSegmentId);
|
||||
$idsInFilterSegment = $this->findSubscribersInSegment($filterSegment, $subscribersToProcessIds);
|
||||
$result = array_intersect($result, $idsInFilterSegment);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->unique($result);
|
||||
}
|
||||
@@ -74,6 +72,13 @@ class SubscribersFinder {
|
||||
*/
|
||||
public function addSubscribersToTaskFromSegments(ScheduledTaskEntity $task, array $segmentIds, ?int $filterSegmentId = null) {
|
||||
// Prepare subscribers on the DB side for performance reasons
|
||||
if (is_int($filterSegmentId)) {
|
||||
try {
|
||||
$this->segmentsRepository->verifyFilterSegmentExists($filterSegmentId);
|
||||
} catch (InvalidStateException $exception) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
$staticSegmentIds = [];
|
||||
$dynamicSegmentIds = [];
|
||||
foreach ($segmentIds as $segment) {
|
||||
|
@@ -6,13 +6,13 @@ use Codeception\Util\Stub;
|
||||
use MailPoet\Entities\ScheduledTaskEntity;
|
||||
use MailPoet\Entities\SegmentEntity;
|
||||
use MailPoet\Entities\SubscriberEntity;
|
||||
use MailPoet\InvalidStateException;
|
||||
use MailPoet\Newsletter\Sending\ScheduledTaskSubscribersRepository;
|
||||
use MailPoet\Tasks\Sending as SendingTask;
|
||||
use MailPoet\Test\DataFactories\DynamicSegment;
|
||||
use MailPoet\Test\DataFactories\ScheduledTask as ScheduledTaskFactory;
|
||||
use MailPoet\Test\DataFactories\Segment as SegmentFactory;
|
||||
use MailPoet\Test\DataFactories\Subscriber as SubscriberFactory;
|
||||
use MailPoet\UnexpectedValueException;
|
||||
use MailPoetVendor\Carbon\Carbon;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
@@ -214,7 +214,7 @@ class SubscribersFinderTest extends \MailPoetTest {
|
||||
}
|
||||
|
||||
public function testFilterSegmentMustBeDynamicSegment() {
|
||||
$this->expectException(UnexpectedValueException::class);
|
||||
$this->expectException(InvalidStateException::class);
|
||||
$this->subscribersFinder->findSubscribersInSegments([$this->subscriber1->getId()], [$this->segment1->getId()], $this->segment2->getId());
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user