Add NewsletterListingRepository, use it for newsletters data

[MAILPOET-2645]
This commit is contained in:
Jan Jakeš
2020-02-27 14:46:36 +01:00
committed by Jack Kitterhing
parent f1e044aa28
commit 51882b43cf
5 changed files with 197 additions and 49 deletions

View File

@ -76,6 +76,45 @@ class NewslettersResponseBuilder {
return $data;
}
public function buildForListing(NewsletterEntity $newsletter): array {
$data = [
'id' => (string)$newsletter->getId(), // (string) for BC
'hash' => $newsletter->getHash(),
'subject' => $newsletter->getSubject(),
'type' => $newsletter->getType(),
'status' => $newsletter->getStatus(),
'sent_at' => ($sentAt = $newsletter->getSentAt()) ? $sentAt->format(self::DATE_FORMAT) : null,
'updated_at' => $newsletter->getUpdatedAt()->format(self::DATE_FORMAT),
'deleted_at' => ($deletedAt = $newsletter->getDeletedAt()) ? $deletedAt->format(self::DATE_FORMAT) : null,
'segments' => [],
'queue' => false,
'statistics' => false,
];
if ($newsletter->getType() === NewsletterEntity::TYPE_STANDARD) {
$data['segments'] = $this->buildSegments($newsletter);
$data['statistics'] = $this->newslettersStatsRepository->getStatistics($newsletter)->asArray();
$data['queue'] = ($queue = $newsletter->getLatestQueue()) ? $this->buildQueue($queue) : false; // false for BC
} elseif (in_array($newsletter->getType(), [NewsletterEntity::TYPE_WELCOME, NewsletterEntity::TYPE_AUTOMATIC], true)) {
$data['segments'] = [];
$data['statistics'] = $this->newslettersStatsRepository->getStatistics($newsletter)->asArray();
$data['options'] = $this->buildOptions($newsletter);
$data['total_sent'] = $this->newslettersStatsRepository->getTotalSentCount($newsletter);
$data['total_scheduled'] = (int)SendingQueue::findTaskByNewsletterId($newsletter->getId())
->where('tasks.status', SendingQueue::STATUS_SCHEDULED)
->count();
} elseif ($newsletter->getType() === NewsletterEntity::TYPE_NOTIFICATION) {
$data['segments'] = $this->buildSegments($newsletter);
$data['children_count'] = $this->newslettersStatsRepository->getChildrenCount($newsletter);
$data['options'] = $this->buildOptions($newsletter);
} elseif ($newsletter->getType() === NewsletterEntity::TYPE_NOTIFICATION_HISTORY) {
$data['segments'] = $this->buildSegments($newsletter);
$data['statistics'] = $this->newslettersStatsRepository->getStatistics($newsletter)->asArray();
$data['queue'] = ($queue = $newsletter->getLatestQueue()) ? $this->buildQueue($queue) : false; // false for BC
}
return $data;
}
private function buildSegments(NewsletterEntity $newsletter) {
$output = [];
foreach ($newsletter->getNewsletterSegments() as $newsletterSegment) {

View File

@ -19,6 +19,7 @@ use MailPoet\Models\NewsletterSegment;
use MailPoet\Models\NewsletterTemplate;
use MailPoet\Models\SendingQueue;
use MailPoet\Models\Subscriber;
use MailPoet\Newsletter\Listing\NewsletterListingRepository;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Newsletter\Renderer\Renderer;
use MailPoet\Newsletter\Scheduler\PostNotificationScheduler;
@ -26,8 +27,8 @@ use MailPoet\Newsletter\Scheduler\Scheduler;
use MailPoet\Newsletter\Url as NewsletterUrl;
use MailPoet\Services\AuthorizedEmailsController;
use MailPoet\Settings\SettingsController;
use MailPoet\Tasks\Sending as SendingTask;
use MailPoet\Util\License\Features\Subscribers as SubscribersFeature;
use MailPoet\WooCommerce\Helper as WCHelper;
use MailPoet\WP\Emoji;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Carbon\Carbon;
@ -43,9 +44,6 @@ class Newsletters extends APIEndpoint {
/** @var WPFunctions */
private $wp;
/** @var WCHelper */
private $woocommerceHelper;
/** @var SettingsController */
private $settings;
@ -62,6 +60,9 @@ class Newsletters extends APIEndpoint {
/** @var NewslettersRepository */
private $newslettersRepository;
/** @var NewsletterListingRepository */
private $newsletterListingRepository;
/** @var NewslettersResponseBuilder */
private $newslettersResponseBuilder;
@ -84,11 +85,11 @@ class Newsletters extends APIEndpoint {
Listing\BulkActionController $bulkAction,
Listing\Handler $listingHandler,
WPFunctions $wp,
WCHelper $woocommerceHelper,
SettingsController $settings,
CronHelper $cronHelper,
AuthorizedEmailsController $authorizedEmailsController,
NewslettersRepository $newslettersRepository,
NewsletterListingRepository $newsletterListingRepository,
NewslettersResponseBuilder $newslettersResponseBuilder,
PostNotificationScheduler $postNotificationScheduler,
MailerFactory $mailer,
@ -99,11 +100,11 @@ class Newsletters extends APIEndpoint {
$this->bulkAction = $bulkAction;
$this->listingHandler = $listingHandler;
$this->wp = $wp;
$this->woocommerceHelper = $woocommerceHelper;
$this->settings = $settings;
$this->cronHelper = $cronHelper;
$this->authorizedEmailsController = $authorizedEmailsController;
$this->newslettersRepository = $newslettersRepository;
$this->newsletterListingRepository = $newsletterListingRepository;
$this->newslettersResponseBuilder = $newslettersResponseBuilder;
$this->postNotificationScheduler = $postNotificationScheduler;
$this->mailer = $mailer;
@ -520,51 +521,35 @@ class Newsletters extends APIEndpoint {
}
public function listing($data = []) {
$listingData = $this->listingHandler->get('\MailPoet\Models\Newsletter', $data);
$definition = $this->listingHandler->getListingDefinition($data);
$items = $this->newsletterListingRepository->getData($definition);
$count = $this->newsletterListingRepository->getCount($definition);
$filters = Newsletter::filters($data);
$groups = Newsletter::groups($data);
$data = [];
foreach ($listingData['items'] as $newsletter) {
foreach ($items as $newsletter) {
$queue = false;
if ($newsletter->type === Newsletter::TYPE_STANDARD) {
$newsletter
->withSegments(true)
->withSendingQueue()
->withStatistics($this->woocommerceHelper);
} else if ($newsletter->type === Newsletter::TYPE_WELCOME || $newsletter->type === Newsletter::TYPE_AUTOMATIC) {
$newsletter
->withOptions()
->withTotalSent()
->withScheduledToBeSent()
->withStatistics($this->woocommerceHelper);
} else if ($newsletter->type === Newsletter::TYPE_NOTIFICATION) {
$newsletter
->withOptions()
->withSegments(true)
->withChildrenCount();
} else if ($newsletter->type === Newsletter::TYPE_NOTIFICATION_HISTORY) {
$newsletter
->withSegments(true)
->withSendingQueue()
->withStatistics($this->woocommerceHelper);
if (in_array($newsletter->getStatus(), [Newsletter::STATUS_SENT, Newsletter::STATUS_SENDING], true)) {
$queue = SendingTask::getByNewsletterId($newsletter->getId());
}
if ($newsletter->status === Newsletter::STATUS_SENT ||
$newsletter->status === Newsletter::STATUS_SENDING
) {
$queue = $newsletter->getQueue();
}
// get preview url
$newsletter->previewUrl = NewsletterUrl::getViewInBrowserUrl($newsletter, null, $queue);
$data[] = $this->wp->applyFilters('mailpoet_api_newsletters_listing_item', $newsletter->asArray());
$newsletterData = $this->newslettersResponseBuilder->buildForListing($newsletter);
$newsletterData['preview_url'] = NewsletterUrl::getViewInBrowserUrl(
(object)[
'id' => $newsletter->getId(),
'hash' => $newsletter->getHash(),
],
null,
$queue
);
$data[] = $this->wp->applyFilters('mailpoet_api_newsletters_listing_item', $newsletterData);
}
return $this->successResponse($data, [
'count' => $listingData['count'],
'filters' => $listingData['filters'],
'groups' => $listingData['groups'],
'count' => $count,
'filters' => $filters,
'groups' => $groups,
'mta_log' => $this->settings->get('mta_log'),
'mta_method' => $this->settings->get('mta.method'),
'cron_accessible' => $this->cronHelper->isDaemonAccessible(),

View File

@ -254,6 +254,7 @@ class ContainerConfigurator implements IContainerConfigurator {
// Newsletter
$container->autowire(\MailPoet\Newsletter\AutomatedLatestContent::class)->setPublic(true);
$container->autowire(\MailPoet\Newsletter\NewslettersRepository::class);
$container->autowire(\MailPoet\Newsletter\Listing\NewsletterListingRepository::class);
$container->autowire(\MailPoet\Newsletter\Statistics\NewsletterStatisticsRepository::class);
$container->autowire(\MailPoet\Newsletter\Scheduler\WelcomeScheduler::class);
$container->autowire(\MailPoet\Newsletter\Scheduler\PostNotificationScheduler::class);

View File

@ -0,0 +1,109 @@
<?php declare(strict_types = 1);
namespace MailPoet\Newsletter\Listing;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Listing\ListingRepository;
use MailPoetVendor\Doctrine\ORM\QueryBuilder;
class NewsletterListingRepository extends ListingRepository {
private static $supportedStatuses = [
NewsletterEntity::STATUS_DRAFT,
NewsletterEntity::STATUS_SCHEDULED,
NewsletterEntity::STATUS_SENDING,
NewsletterEntity::STATUS_SENT,
NewsletterEntity::STATUS_ACTIVE,
];
private static $supportedTypes = [
NewsletterEntity::TYPE_STANDARD,
NewsletterEntity::TYPE_WELCOME,
NewsletterEntity::TYPE_AUTOMATIC,
NewsletterEntity::TYPE_NOTIFICATION,
NewsletterEntity::TYPE_NOTIFICATION_HISTORY,
];
protected function applySelectClause(QueryBuilder $queryBuilder) {
$queryBuilder->select("PARTIAL n.{id,subject,hash,type,status,sentAt,updatedAt,deletedAt}");
}
protected function applyFromClause(QueryBuilder $queryBuilder) {
$queryBuilder->from(NewsletterEntity::class, 'n');
}
protected function applyGroup(QueryBuilder $queryBuilder, string $group) {
// include/exclude deleted
if ($group === 'trash') {
$queryBuilder->andWhere('n.deletedAt IS NOT NULL');
} else {
$queryBuilder->andWhere('n.deletedAt IS NULL');
}
if (!in_array($group, self::$supportedStatuses)) {
return;
}
$queryBuilder
->andWhere('n.status = :status')
->setParameter('status', $group);
}
protected function applySearch(QueryBuilder $queryBuilder, string $search) {
$queryBuilder
->andWhere('n.subject LIKE :search')
->setParameter('search', "%$search%"); // TODO: escape?
}
protected function applyFilters(QueryBuilder $queryBuilder, array $filters) {
$segmentId = $filters['segment'] ?? null;
if ($segmentId) {
$queryBuilder
->join('n.newsletterSegments', 'ns')
->andWhere('ns.segment = :segmentId')
->setParameter('segmentId', $segmentId);
}
}
protected function applyParameters(QueryBuilder $queryBuilder, array $parameters) {
$type = $parameters['type'] ?? null;
$group = $parameters['group'] ?? null;
$parentId = $parameters['parent_id'] ?? null;
if ($type) {
$this->applyType($queryBuilder, $type, $group);
}
if ($parentId) {
$queryBuilder
->andWhere('n.parent = :parentId')
->setParameter('parentId', $parentId);
}
}
protected function applySorting(QueryBuilder $queryBuilder, string $sortBy, string $sortOrder) {
if ($sortBy === 'sentAt') {
$queryBuilder->addSelect('CASE WHEN n.sentAt IS NULL THEN 1 ELSE 0 END AS HIDDEN sentAtIsNull');
$queryBuilder->addOrderBy('sentAtIsNull', 'DESC');
}
$queryBuilder->addOrderBy("n.$sortBy", $sortOrder);
}
private function applyType(QueryBuilder $queryBuilder, string $type, string $group = null) {
if (!in_array($type, self::$supportedTypes)) {
return;
}
if ($type === NewsletterEntity::TYPE_AUTOMATIC && $group) {
$queryBuilder
->join('n.options', 'o')
->join('o.optionField', 'opf')
->andWhere('o.value = :group')
->setParameter('group', $group)
->andWhere('opf.newsletterType = n.type');
} else {
$queryBuilder
->andWhere('n.type = :type')
->setParameter('type', $type);
}
}
}

View File

@ -24,9 +24,11 @@ use MailPoet\Models\ScheduledTask;
use MailPoet\Models\Segment;
use MailPoet\Models\SendingQueue;
use MailPoet\Models\SubscriberSegment;
use MailPoet\Newsletter\Listing\NewsletterListingRepository;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Newsletter\Scheduler\PostNotificationScheduler;
use MailPoet\Newsletter\Scheduler\Scheduler;
use MailPoet\Newsletter\Statistics\NewsletterStatisticsRepository;
use MailPoet\Newsletter\Url;
use MailPoet\Router\Router;
use MailPoet\Services\AuthorizedEmailsController;
@ -38,6 +40,7 @@ use MailPoet\WooCommerce\Helper as WCHelper;
use MailPoet\WP\Emoji;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Carbon\Carbon;
use MailPoetVendor\Doctrine\ORM\EntityManager;
use MailPoetVendor\Idiorm\ORM;
class NewslettersTest extends \MailPoetTest {
@ -56,7 +59,17 @@ class NewslettersTest extends \MailPoetTest {
parent::_before();
$this->subscriptionUrlFactory = SubscriptionUrlFactory::getInstance();
$this->cronHelper = ContainerWrapper::getInstance()->get(CronHelper::class);
$this->endpoint = ContainerWrapper::getInstance()->get(Newsletters::class);
$this->endpoint = Stub::copy(
ContainerWrapper::getInstance()->get(Newsletters::class),
[
'newslettersResponseBuilder' => new NewslettersResponseBuilder(
new NewsletterStatisticsRepository(
$this->diContainer->get(EntityManager::class),
$this->makeEmpty(WCHelper::class)
)
),
]
);
$this->newsletter = Newsletter::createOrUpdate(
[
'subject' => 'My Standard Newsletter',
@ -144,11 +157,11 @@ class NewslettersTest extends \MailPoetTest {
ContainerWrapper::getInstance()->get(BulkActionController::class),
ContainerWrapper::getInstance()->get(Handler::class),
$wp,
$this->makeEmpty(WCHelper::class),
SettingsController::getInstance(),
$this->cronHelper,
$this->make(AuthorizedEmailsController::class, ['onNewsletterUpdate' => Expected::never()]),
ContainerWrapper::getInstance()->get(NewslettersRepository::class),
ContainerWrapper::getInstance()->get(NewsletterListingRepository::class),
ContainerWrapper::getInstance()->get(NewslettersResponseBuilder::class),
ContainerWrapper::getInstance()->get(PostNotificationScheduler::class),
ContainerWrapper::getInstance()->get(Mailer::class),
@ -200,11 +213,11 @@ class NewslettersTest extends \MailPoetTest {
ContainerWrapper::getInstance()->get(BulkActionController::class),
ContainerWrapper::getInstance()->get(Handler::class),
$wp,
$this->makeEmpty(WCHelper::class),
SettingsController::getInstance(),
$this->cronHelper,
$this->make(AuthorizedEmailsController::class, ['onNewsletterUpdate' => Expected::once()]),
ContainerWrapper::getInstance()->get(NewslettersRepository::class),
ContainerWrapper::getInstance()->get(NewsletterListingRepository::class),
ContainerWrapper::getInstance()->get(NewslettersResponseBuilder::class),
ContainerWrapper::getInstance()->get(PostNotificationScheduler::class),
ContainerWrapper::getInstance()->get(Mailer::class),
@ -433,11 +446,11 @@ class NewslettersTest extends \MailPoetTest {
ContainerWrapper::getInstance()->get(BulkActionController::class),
ContainerWrapper::getInstance()->get(Handler::class),
ContainerWrapper::getInstance()->get(WPFunctions::class),
$this->makeEmpty(WCHelper::class),
SettingsController::getInstance(),
$this->cronHelper,
$this->make(AuthorizedEmailsController::class),
ContainerWrapper::getInstance()->get(NewslettersRepository::class),
ContainerWrapper::getInstance()->get(NewsletterListingRepository::class),
ContainerWrapper::getInstance()->get(NewslettersResponseBuilder::class),
ContainerWrapper::getInstance()->get(PostNotificationScheduler::class),
ContainerWrapper::getInstance()->get(Mailer::class),
@ -604,11 +617,11 @@ class NewslettersTest extends \MailPoetTest {
ContainerWrapper::getInstance()->get(BulkActionController::class),
ContainerWrapper::getInstance()->get(Handler::class),
$wp,
$this->makeEmpty(WCHelper::class),
SettingsController::getInstance(),
$this->cronHelper,
$this->make(AuthorizedEmailsController::class, ['onNewsletterUpdate' => Expected::never()]),
ContainerWrapper::getInstance()->get(NewslettersRepository::class),
ContainerWrapper::getInstance()->get(NewsletterListingRepository::class),
ContainerWrapper::getInstance()->get(NewslettersResponseBuilder::class),
ContainerWrapper::getInstance()->get(PostNotificationScheduler::class),
ContainerWrapper::getInstance()->get(Mailer::class),
@ -953,11 +966,11 @@ class NewslettersTest extends \MailPoetTest {
ContainerWrapper::getInstance()->get(BulkActionController::class),
ContainerWrapper::getInstance()->get(Handler::class),
$wp,
$this->makeEmpty(WCHelper::class),
SettingsController::getInstance(),
$this->cronHelper,
ContainerWrapper::getInstance()->get(AuthorizedEmailsController::class),
ContainerWrapper::getInstance()->get(NewslettersRepository::class),
ContainerWrapper::getInstance()->get(NewsletterListingRepository::class),
ContainerWrapper::getInstance()->get(NewslettersResponseBuilder::class),
ContainerWrapper::getInstance()->get(PostNotificationScheduler::class),
ContainerWrapper::getInstance()->get(Mailer::class),
@ -1066,6 +1079,7 @@ class NewslettersTest extends \MailPoetTest {
public function _after() {
ORM::raw_execute('TRUNCATE ' . Newsletter::$_table);
ORM::raw_execute('TRUNCATE ' . NewsletterSegment::$_table);
ORM::raw_execute('TRUNCATE ' . NewsletterOption::$_table);
ORM::raw_execute('TRUNCATE ' . NewsletterOptionField::$_table);
ORM::raw_execute('TRUNCATE ' . ScheduledTask::$_table);
ORM::raw_execute('TRUNCATE ' . Segment::$_table);