diff --git a/lib/Cron/Workers/SendingQueue/Tasks/Shortcodes.php b/lib/Cron/Workers/SendingQueue/Tasks/Shortcodes.php index 9345ca27bc..1617bd2623 100644 --- a/lib/Cron/Workers/SendingQueue/Tasks/Shortcodes.php +++ b/lib/Cron/Workers/SendingQueue/Tasks/Shortcodes.php @@ -27,19 +27,19 @@ class Shortcodes { /** @var SubscribersRepository $subscribersRepository */ $subscribersRepository = ContainerWrapper::getInstance()->get(SubscribersRepository::class); - if ($queue instanceof Sending || $queue instanceof SendingQueue) { + if (($queue instanceof Sending || $queue instanceof SendingQueue) && $queue->id) { $queue = $sendingQueueRepository->findOneById($queue->id); } if ($queue instanceof SendingQueueEntity) { $shortcodes->setQueue($queue); } - if ($newsletter instanceof \MailPoet\Models\Newsletter) { + if ($newsletter instanceof \MailPoet\Models\Newsletter && $newsletter->id) { $newsletter = $newsletterRepository->findOneById($newsletter->id); } if ($newsletter instanceof NewsletterEntity) { $shortcodes->setNewsletter($newsletter); } - if ($subscriber instanceof Subscriber) { + if ($subscriber instanceof Subscriber && $subscriber->id) { $subscriber = $subscribersRepository->findOneById($subscriber->id); } if ($subscriber instanceof SubscriberEntity) { diff --git a/lib/DI/ContainerConfigurator.php b/lib/DI/ContainerConfigurator.php index 6e18221ce5..8e7632ba56 100644 --- a/lib/DI/ContainerConfigurator.php +++ b/lib/DI/ContainerConfigurator.php @@ -309,6 +309,10 @@ class ContainerConfigurator implements IContainerConfigurator { $container->autowire(\MailPoet\Newsletter\Segment\NewsletterSegmentRepository::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\Shortcodes\ShortcodesHelper::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\Shortcodes\Shortcodes::class)->setPublic(true); + $container->autowire(\MailPoet\Newsletter\Shortcodes\Categories\Date::class)->setPublic(true); + $container->autowire(\MailPoet\Newsletter\Shortcodes\Categories\Link::class)->setPublic(true); + $container->autowire(\MailPoet\Newsletter\Shortcodes\Categories\Newsletter::class)->setPublic(true); + $container->autowire(\MailPoet\Newsletter\Shortcodes\Categories\Subscriber::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\Statistics\NewsletterStatisticsRepository::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\Scheduler\WelcomeScheduler::class)->setPublic(true); $container->autowire(\MailPoet\Newsletter\Scheduler\PostNotificationScheduler::class)->setPublic(true); diff --git a/lib/Doctrine/Repository.php b/lib/Doctrine/Repository.php index 1f0f3d4394..615f2542dd 100644 --- a/lib/Doctrine/Repository.php +++ b/lib/Doctrine/Repository.php @@ -37,6 +37,10 @@ abstract class Repository { return $this->doctrineRepository->findBy($criteria, $orderBy, $limit, $offset); } + public function countBy(array $criteria): int { + return $this->doctrineRepository->count($criteria); + } + /** * @param array $criteria * @param array|null $orderBy diff --git a/lib/Newsletter/Shortcodes/Categories/CategoryInterface.php b/lib/Newsletter/Shortcodes/Categories/CategoryInterface.php new file mode 100644 index 0000000000..bed26829da --- /dev/null +++ b/lib/Newsletter/Shortcodes/Categories/CategoryInterface.php @@ -0,0 +1,18 @@ + 'd', 'dordinal' => 'jS', @@ -22,6 +30,6 @@ class Date { } return ($shortcodeDetails['action'] === 'custom' && $shortcodeDetails['action_argument'] === 'format') ? WPFunctions::get()->dateI18n($shortcodeDetails['action_argument_value'], $wp->currentTime('timestamp')) : - false; + null; } } diff --git a/lib/Newsletter/Shortcodes/Categories/Link.php b/lib/Newsletter/Shortcodes/Categories/Link.php index 546e966970..b5056b5b64 100644 --- a/lib/Newsletter/Shortcodes/Categories/Link.php +++ b/lib/Newsletter/Shortcodes/Categories/Link.php @@ -2,31 +2,52 @@ namespace MailPoet\Newsletter\Shortcodes\Categories; +use MailPoet\Entities\NewsletterEntity; use MailPoet\Entities\SendingQueueEntity; +use MailPoet\Entities\SubscriberEntity; +use MailPoet\Models\Newsletter as NewsletterModel; +use MailPoet\Models\SendingQueue; +use MailPoet\Models\Subscriber as SubscriberModel; use MailPoet\Newsletter\Url as NewsletterUrl; use MailPoet\Settings\SettingsController; use MailPoet\Subscription\SubscriptionUrlFactory; -use MailPoet\Tasks\Sending; use MailPoet\WP\Functions as WPFunctions; -class Link { +class Link implements CategoryInterface { const CATEGORY_NAME = 'link'; - public static function process( - $shortcodeDetails, - $newsletter, - $subscriber, - $queue, - $content, - $wpUserPreview + /** @var SettingsController */ + private $settings; + + /** @var WPFunctions */ + private $wp; + + public function __construct( + SettingsController $settings, + WPFunctions $wp ) { + $this->settings = $settings; + $this->wp = $wp; + } + + public function process( + array $shortcodeDetails, + NewsletterEntity $newsletter = null, + SubscriberEntity $subscriber = null, + SendingQueueEntity $queue = null, + string $content = '', + bool $wpUserPreview = false + ): ?string { $subscriptionUrlFactory = SubscriptionUrlFactory::getInstance(); + $subscriberModel = $this->getSubscriberModel($subscriber); + $newsletterModel = $this->getNewsletterModel($newsletter); + $queueModel = $this->getQueueModel($queue); switch ($shortcodeDetails['action']) { case 'subscription_unsubscribe_url': return self::processUrl( $shortcodeDetails['action'], - $subscriptionUrlFactory->getConfirmUnsubscribeUrl($wpUserPreview ? null : $subscriber, self::getSendingQueueId($queue)), + $subscriptionUrlFactory->getConfirmUnsubscribeUrl($wpUserPreview ? null : $subscriberModel, self::getSendingQueueId($queue)), $queue, $wpUserPreview ); @@ -34,7 +55,7 @@ class Link { case 'subscription_instant_unsubscribe_url': return self::processUrl( $shortcodeDetails['action'], - $subscriptionUrlFactory->getUnsubscribeUrl($wpUserPreview ? null : $subscriber, self::getSendingQueueId($queue)), + $subscriptionUrlFactory->getUnsubscribeUrl($wpUserPreview ? null : $subscriberModel, self::getSendingQueueId($queue)), $queue, $wpUserPreview ); @@ -42,96 +63,121 @@ class Link { case 'subscription_manage_url': return self::processUrl( $shortcodeDetails['action'], - $subscriptionUrlFactory->getManageUrl($wpUserPreview ? null : $subscriber), + $subscriptionUrlFactory->getManageUrl($wpUserPreview ? null : $subscriberModel), $queue, $wpUserPreview ); case 'newsletter_view_in_browser_url': $url = NewsletterUrl::getViewInBrowserUrl( - $newsletter, + $newsletterModel, $wpUserPreview ? null : $subscriber, - $queue, + $queueModel, $wpUserPreview ); return self::processUrl($shortcodeDetails['action'], $url, $queue, $wpUserPreview); default: $shortcode = self::getFullShortcode($shortcodeDetails['action']); - $url = WPFunctions::get()->applyFilters( + $url = $this->wp->applyFilters( 'mailpoet_newsletter_shortcode_link', $shortcode, - $newsletter, - $subscriber, - $queue, + $newsletterModel, + $subscriberModel, + $queueModel, $wpUserPreview ); + return ($url !== $shortcode) ? self::processUrl($shortcodeDetails['action'], $url, $queue, $wpUserPreview) : - false; + null; } } - public static function processUrl($action, $url, $queue, $wpUserPreview = false) { + public function processUrl($action, $url, $queue, $wpUserPreview = false): string { if ($wpUserPreview) return $url; - $settings = SettingsController::getInstance(); - return ($queue !== false && (boolean)$settings->get('tracking.enabled')) ? + return ($queue !== false && (boolean)$this->settings->get('tracking.enabled')) ? self::getFullShortcode($action) : $url; } - public static function processShortcodeAction( - $shortcodeAction, $newsletter, $subscriber, $queue, $wpUserPreview - ) { + public function processShortcodeAction( + $shortcodeAction, + NewsletterEntity $newsletter = null, + SubscriberEntity $subscriber = null, + SendingQueueEntity $queue = null, + $wpUserPreview = false + ): ?string { + $subscriberModel = $this->getSubscriberModel($subscriber); + $newsletterModel = $this->getNewsletterModel($newsletter); + $queueModel = $this->getQueueModel($queue); $subscriptionUrlFactory = SubscriptionUrlFactory::getInstance(); switch ($shortcodeAction) { case 'subscription_unsubscribe_url': - $url = $subscriptionUrlFactory->getConfirmUnsubscribeUrl($subscriber, self::getSendingQueueId($queue)); + $url = $subscriptionUrlFactory->getConfirmUnsubscribeUrl($subscriberModel, self::getSendingQueueId($queue)); break; case 'subscription_instant_unsubscribe_url': - $url = $subscriptionUrlFactory->getUnsubscribeUrl($subscriber, self::getSendingQueueId($queue)); + $url = $subscriptionUrlFactory->getUnsubscribeUrl($subscriberModel, self::getSendingQueueId($queue)); break; case 'subscription_manage_url': - $url = $subscriptionUrlFactory->getManageUrl($subscriber); + $url = $subscriptionUrlFactory->getManageUrl($subscriberModel); break; case 'newsletter_view_in_browser_url': $url = NewsletterUrl::getViewInBrowserUrl( - $newsletter, - $subscriber, - $queue, + $newsletterModel, + $subscriberModel, + $queueModel, false ); break; default: $shortcode = self::getFullShortcode($shortcodeAction); - $url = WPFunctions::get()->applyFilters( + $url = $this->wp->applyFilters( 'mailpoet_newsletter_shortcode_link', $shortcode, - $newsletter, - $subscriber, - $queue, + $newsletterModel, + $subscriberModel, + $queueModel, $wpUserPreview ); - $url = ($url !== $shortcodeAction) ? $url : false; + $url = ($url !== $shortcodeAction) ? $url : null; break; } return $url; } - private static function getFullShortcode($action) { + private function getFullShortcode($action): string { return sprintf('[link:%s]', $action); } - /** - * @return int|null - */ - private static function getSendingQueueId($queue) { - if ($queue instanceof Sending) { - return (int)$queue->id; - } + private function getSendingQueueId($queue): ?int { if ($queue instanceof SendingQueueEntity) { return $queue->getId(); } return null; } + + // temporary function until Links are refactored to Doctrine + private function getSubscriberModel(SubscriberEntity $subscriber = null): ?SubscriberModel { + if (!$subscriber) return null; + $subscriberModel = SubscriberModel::where('id', $subscriber->getId())->findOne(); + if ($subscriberModel) return $subscriberModel; + return null; + } + + // temporary function until Links are refactored to Doctrine + private function getNewsletterModel(NewsletterEntity $newsletter = null): ?NewsletterModel { + if (!$newsletter) return null; + $newsletterModel = NewsletterModel::where('id', $newsletter->getId())->findOne(); + if ($newsletterModel) return $newsletterModel; + return null; + } + + // temporary function until Links are refactored to Doctrine + private function getQueueModel(SendingQueueEntity $queue = null): ?SendingQueue { + if (!$queue) return null; + $queueModel = SendingQueue::where('id', $queue->getId())->findOne(); + if ($queueModel) return $queueModel; + return null; + } } diff --git a/lib/Newsletter/Shortcodes/Categories/Newsletter.php b/lib/Newsletter/Shortcodes/Categories/Newsletter.php index 550055a22f..bc812a4597 100644 --- a/lib/Newsletter/Shortcodes/Categories/Newsletter.php +++ b/lib/Newsletter/Shortcodes/Categories/Newsletter.php @@ -2,45 +2,59 @@ namespace MailPoet\Newsletter\Shortcodes\Categories; -use MailPoet\Models\Newsletter as NewsletterModel; +use MailPoet\Entities\NewsletterEntity; +use MailPoet\Entities\SendingQueueEntity; +use MailPoet\Entities\SubscriberEntity; +use MailPoet\Newsletter\NewslettersRepository; use MailPoet\WP\Functions as WPFunctions; use MailPoet\WP\Posts as WPPosts; -class Newsletter { - public static function process( - $shortcodeDetails, - $newsletter, - $subscriber, - $queue, - $content - ) { +class Newsletter implements CategoryInterface { + /** @var NewslettersRepository */ + private $newslettersRepository; + + public function __construct(NewslettersRepository $newslettersRepository) { + $this->newslettersRepository = $newslettersRepository; + } + + public function process( + array $shortcodeDetails, + NewsletterEntity $newsletter = null, + SubscriberEntity $subscriber = null, + SendingQueueEntity $queue = null, + string $content = '', + bool $wpUserPreview = false + ): ?string { switch ($shortcodeDetails['action']) { case 'subject': - return ($newsletter) ? $newsletter->subject : false; + return ($newsletter instanceof NewsletterEntity) ? $newsletter->getSubject() : null; case 'total': - return substr_count($content, 'data-post-id'); + return (string)substr_count($content, 'data-post-id'); case 'post_title': preg_match_all('/data-post-id="(\d+)"/ism', $content, $posts); $postIds = array_unique($posts[1]); - $latestPost = (!empty($postIds)) ? self::getLatestWPPost($postIds) : false; - return ($latestPost) ? $latestPost['post_title'] : false; + $latestPost = (!empty($postIds)) ? $this->getLatestWPPost($postIds) : null; + return ($latestPost) ? $latestPost['post_title'] : null; case 'number': - if ($newsletter->type !== NewsletterModel::TYPE_NOTIFICATION_HISTORY) return false; - $sentNewsletters = - NewsletterModel::where('parent_id', $newsletter->parentId) - ->where('status', NewsletterModel::STATUS_SENT) - ->count(); - return ++$sentNewsletters; + if (!($newsletter instanceof NewsletterEntity)) return null; + if ($newsletter->getType() !== NewsletterEntity::TYPE_NOTIFICATION_HISTORY) { + return null; + } + $sentNewsletters = $this->newslettersRepository->countBy([ + 'parent' => $newsletter->getParent(), + 'status' => NewsletterEntity::STATUS_SENT, + ]); + return (string)++$sentNewsletters; default: - return false; + return null; } } - public static function ensureConsistentQueryType(\WP_Query $query) { + public function ensureConsistentQueryType(\WP_Query $query) { // Queries with taxonomies are autodetected as 'is_archive=true' and 'is_home=false' // while queries without them end up being 'is_archive=false' and 'is_home=true'. // This is to fix that by always enforcing constistent behavior. @@ -48,10 +62,10 @@ class Newsletter { $query->is_home = false; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps } - private static function getLatestWPPost($postIds) { + private function getLatestWPPost($postIds) { // set low priority to execute 'ensureConstistentQueryType' before any other filter $filterPriority = defined('PHP_INT_MIN') ? constant('PHP_INT_MIN') : ~PHP_INT_MAX; - WPFunctions::get()->addAction('pre_get_posts', [get_called_class(), 'ensureConsistentQueryType'], $filterPriority); + WPFunctions::get()->addAction('pre_get_posts', [$this, 'ensureConsistentQueryType'], $filterPriority); $posts = new \WP_Query( [ 'post_type' => WPPosts::getTypes(), @@ -62,7 +76,7 @@ class Newsletter { 'order' => 'DESC', ] ); - WPFunctions::get()->removeAction('pre_get_posts', [get_called_class(), 'ensureConsistentQueryType'], $filterPriority); + WPFunctions::get()->removeAction('pre_get_posts', [$this, 'ensureConsistentQueryType'], $filterPriority); return (!empty($posts->posts[0])) ? $posts->posts[0]->to_array() : false; diff --git a/lib/Newsletter/Shortcodes/Categories/Subscriber.php b/lib/Newsletter/Shortcodes/Categories/Subscriber.php index 5756b32941..a1fe487be7 100644 --- a/lib/Newsletter/Shortcodes/Categories/Subscriber.php +++ b/lib/Newsletter/Shortcodes/Categories/Subscriber.php @@ -2,52 +2,67 @@ namespace MailPoet\Newsletter\Shortcodes\Categories; -use MailPoet\Models\Subscriber as SubscriberModel; -use MailPoet\Models\SubscriberCustomField; +use MailPoet\Entities\NewsletterEntity; +use MailPoet\Entities\SendingQueueEntity; +use MailPoet\Entities\SubscriberCustomFieldEntity; +use MailPoet\Entities\SubscriberEntity; +use MailPoet\Subscribers\SubscriberCustomFieldRepository; +use MailPoet\Subscribers\SubscribersRepository; use MailPoet\WP\Functions as WPFunctions; -class Subscriber { - /** - * @param \MailPoet\Models\Subscriber|false|mixed $subscriber - */ - public static function process( - $shortcodeDetails, - $newsletter, - $subscriber +class Subscriber implements CategoryInterface { + + /** @var SubscribersRepository */ + private $subscribersRepository; + + /** @var SubscriberCustomFieldRepository */ + private $subscriberCustomFieldRepository; + + public function __construct( + SubscribersRepository $subscribersRepository, + SubscriberCustomFieldRepository $subscriberCustomFieldRepository ) { - if ($subscriber !== false && !($subscriber instanceof SubscriberModel)) { - return $shortcodeDetails['shortcode']; - } + $this->subscribersRepository = $subscribersRepository; + $this->subscriberCustomFieldRepository = $subscriberCustomFieldRepository; + } + + public function process( + array $shortcodeDetails, + NewsletterEntity $newsletter = null, + SubscriberEntity $subscriber = null, + SendingQueueEntity $queue = null, + string $content = '', + bool $wpUserPreview = false + ): ?string { $defaultValue = ($shortcodeDetails['action_argument'] === 'default') ? $shortcodeDetails['action_argument_value'] : ''; switch ($shortcodeDetails['action']) { case 'firstname': - return (!empty($subscriber->firstName)) ? $subscriber->firstName : $defaultValue; + return (($subscriber instanceof SubscriberEntity) && !empty($subscriber->getFirstName())) ? $subscriber->getFirstName() : $defaultValue; case 'lastname': - return (!empty($subscriber->lastName)) ? $subscriber->lastName : $defaultValue; + return (($subscriber instanceof SubscriberEntity) && !empty($subscriber->getLastName())) ? $subscriber->getLastName() : $defaultValue; case 'email': - return ($subscriber) ? $subscriber->email : false; + return ($subscriber instanceof SubscriberEntity) ? $subscriber->getEmail() : $defaultValue; case 'displayname': - if ($subscriber && $subscriber->wpUserId) { - $wpUser = WPFunctions::get()->getUserdata($subscriber->wpUserId); + if (($subscriber instanceof SubscriberEntity) && $subscriber->getWpUserId()) { + $wpUser = WPFunctions::get()->getUserdata($subscriber->getWpUserId()); return $wpUser->user_login; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps } return $defaultValue; case 'count': - return SubscriberModel::filter('subscribed') - ->count(); + return (string)$this->subscribersRepository->getTotalSubscribers(); default: if (preg_match('/cf_(\d+)/', $shortcodeDetails['action'], $customField) && - !empty($subscriber->id) + !empty($subscriber->getId()) ) { - $customField = SubscriberCustomField - ::where('subscriber_id', $subscriber->id) - ->where('custom_field_id', $customField[1]) - ->findOne(); - return ($customField instanceof SubscriberCustomField) ? $customField->value : false; + $customField = $this->subscriberCustomFieldRepository->findOneBy([ + 'subscriber' => $subscriber, + 'customField' => $customField[1], + ]); + return ($customField instanceof SubscriberCustomFieldEntity) ? $customField->getValue() : null; } - return false; + return null; } } } diff --git a/lib/Newsletter/Shortcodes/Shortcodes.php b/lib/Newsletter/Shortcodes/Shortcodes.php index 9f4d13981a..981a4c9958 100644 --- a/lib/Newsletter/Shortcodes/Shortcodes.php +++ b/lib/Newsletter/Shortcodes/Shortcodes.php @@ -5,6 +5,11 @@ namespace MailPoet\Newsletter\Shortcodes; use MailPoet\Entities\NewsletterEntity; use MailPoet\Entities\SendingQueueEntity; use MailPoet\Entities\SubscriberEntity; +use MailPoet\Newsletter\Shortcodes\Categories\CategoryInterface; +use MailPoet\Newsletter\Shortcodes\Categories\Date; +use MailPoet\Newsletter\Shortcodes\Categories\Link; +use MailPoet\Newsletter\Shortcodes\Categories\Newsletter; +use MailPoet\Newsletter\Shortcodes\Categories\Subscriber; use MailPoet\WP\Functions as WPFunctions; class Shortcodes { @@ -22,6 +27,30 @@ class Shortcodes { /** @var bool */ private $wpUserPreview = false; + /** @var Date */ + private $dateCategory; + + /** @var Link */ + private $linkCategory; + + /** @var Newsletter */ + private $newsletterCategory; + + /** @var Subscriber */ + private $subscriberCategory; + + public function __construct( + Date $dateCategory, + Link $linkCategory, + Newsletter $newsletterCategory, + Subscriber $subscriberCategory + ) { + $this->dateCategory = $dateCategory; + $this->linkCategory = $linkCategory; + $this->newsletterCategory = $newsletterCategory; + $this->subscriberCategory = $subscriberCategory; + } + public function setNewsletter(NewsletterEntity $newsletter): void { $this->newsletter = $newsletter; } @@ -65,26 +94,36 @@ class Shortcodes { return $match; } - public function process($shortcodes, $content = false) { + public function process($shortcodes, $content = '') { $processedShortcodes = []; foreach ($shortcodes as $shortcode) { $shortcodeDetails = $this->match($shortcode); $shortcodeDetails['shortcode'] = $shortcode; $shortcodeDetails['category'] = !empty($shortcodeDetails['category']) ? $shortcodeDetails['category'] : - false; + ''; $shortcodeDetails['action'] = !empty($shortcodeDetails['action']) ? $shortcodeDetails['action'] : - false; + ''; $shortcodeDetails['action_argument'] = !empty($shortcodeDetails['argument']) ? $shortcodeDetails['argument'] : - false; + ''; $shortcodeDetails['action_argument_value'] = !empty($shortcodeDetails['argument_value']) ? $shortcodeDetails['argument_value'] : false; - $shortcodeClass = - Shortcodes::SHORTCODE_CATEGORY_NAMESPACE . ucfirst($shortcodeDetails['category']); - if (!class_exists($shortcodeClass)) { + + $category = strtolower($shortcodeDetails['category']); + $categoryClass = $this->getCategoryObject($category); + if ($categoryClass instanceof CategoryInterface) { + $processedShortcodes[] = $categoryClass->process( + $shortcodeDetails, + $this->newsletter, + $this->subscriber, + $this->queue, + $content, + $this->wpUserPreview + ); + } else { $customShortcode = WPFunctions::get()->applyFilters( 'mailpoet_newsletter_shortcode', $shortcode, @@ -98,14 +137,7 @@ class Shortcodes { false : $customShortcode; } - $processedShortcodes[] = $shortcodeClass::process( - $shortcodeDetails, - $this->newsletter, - $this->subscriber, - $this->queue, - $content, - $this->wpUserPreview - ); + } return $processedShortcodes; } @@ -125,4 +157,17 @@ class Shortcodes { $shortcodes = array_intersect_key($shortcodes, $processedShortcodes); return str_replace($shortcodes, $processedShortcodes, $content); } + + private function getCategoryObject($category): ?CategoryInterface { + if ($category === 'link') { + return $this->linkCategory; + } elseif ($category === 'date') { + return $this->dateCategory; + } elseif ($category === 'newsletter') { + return $this->newsletterCategory; + } elseif ($category === 'subscriber') { + return $this->subscriberCategory; + } + return null; + } } diff --git a/lib/Router/Endpoints/Track.php b/lib/Router/Endpoints/Track.php index 8ddcf8518e..81a0f33b4e 100644 --- a/lib/Router/Endpoints/Track.php +++ b/lib/Router/Endpoints/Track.php @@ -4,6 +4,7 @@ namespace MailPoet\Router\Endpoints; use MailPoet\Config\AccessControl; use MailPoet\Cron\Workers\StatsNotifications\NewsletterLinkRepository; +use MailPoet\Entities\SendingQueueEntity; use MailPoet\Models\SendingQueue; use MailPoet\Models\Subscriber; use MailPoet\Newsletter\Links\Links; @@ -84,7 +85,10 @@ class Track { } $data->queue = $this->sendingQueuesRepository->findOneById($data->queue_id);// phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps $data->subscriber = $this->subscribersRepository->findOneById($data->subscriber_id); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps - $data->newsletter = $this->newslettersRepository->findOneById($data->newsletter_id); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps + $data->newsletter = (isset($data->newsletter_id)) ? $this->newslettersRepository->findOneById($data->newsletter_id) : null; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps + if (!$data->newsletter && ($data->queue instanceof SendingQueueEntity)) { + $data->newsletter = $data->queue->getNewsletter(); + } if (!empty($data->link_hash)) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps $data->link = $this->newsletterLinkRepository->findOneBy([ 'hash' => $data->link_hash, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps @@ -108,6 +112,7 @@ class Track { // check if the newsletter was sent to the subscriber $queue = SendingQueue::findOne($data->queue_id); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps if (!$queue instanceof SendingQueue) return false; + return ($queue->isSubscriberProcessed($data->subscriber->getId())) ? $data : false; diff --git a/lib/Statistics/Track/Clicks.php b/lib/Statistics/Track/Clicks.php index d1c59529df..518f43d846 100644 --- a/lib/Statistics/Track/Clicks.php +++ b/lib/Statistics/Track/Clicks.php @@ -7,7 +7,7 @@ use MailPoet\Entities\NewsletterLinkEntity; use MailPoet\Entities\SendingQueueEntity; use MailPoet\Entities\SubscriberEntity; use MailPoet\Models\StatisticsClicks; -use MailPoet\Newsletter\Shortcodes\Categories\Link; +use MailPoet\Newsletter\Shortcodes\Categories\Link as LinkShortcodeCategory; use MailPoet\Newsletter\Shortcodes\Shortcodes; use MailPoet\Settings\SettingsController; use MailPoet\Util\Cookies; @@ -30,14 +30,19 @@ class Clicks { /** @var Shortcodes */ private $shortcodes; + /** @var LinkShortcodeCategory */ + private $linkShortcodeCategory; + public function __construct( SettingsController $settingsController, Cookies $cookies, - Shortcodes $shortcodes + Shortcodes $shortcodes, + LinkShortcodeCategory $linkShortcodeCategory ) { $this->settingsController = $settingsController; $this->cookies = $cookies; $this->shortcodes = $shortcodes; + $this->linkShortcodeCategory = $linkShortcodeCategory; } /** @@ -96,7 +101,7 @@ class Clicks { $this->cookies->set( self::ABANDONED_CART_COOKIE_NAME, [ - 'subscriber_id' => $subscriber->id, + 'subscriber_id' => $subscriber->getId(), ], [ 'expires' => time() + self::ABANDONED_CART_COOKIE_EXPIRY, @@ -115,7 +120,7 @@ class Clicks { ) { if (preg_match('/\[link:(?P.*?)\]/', $url, $shortcode)) { if (!$shortcode['action']) $this->abort(); - $url = Link::processShortcodeAction( + $url = $this->linkShortcodeCategory->processShortcodeAction( $shortcode['action'], $newsletter, $subscriber, diff --git a/tests/integration/Cron/Workers/SendingQueue/Tasks/ShortcodesTest.php b/tests/integration/Cron/Workers/SendingQueue/Tasks/ShortcodesTest.php index 5f8a374592..220631f1c4 100644 --- a/tests/integration/Cron/Workers/SendingQueue/Tasks/ShortcodesTest.php +++ b/tests/integration/Cron/Workers/SendingQueue/Tasks/ShortcodesTest.php @@ -26,9 +26,8 @@ class ShortcodesTest extends \MailPoetTest { $queue = $newsletter = (object)[ 'id' => 1, ]; - $subscriber = Subscriber::create(); - $subscriber->hydrate([ - 'email' => 'test@xample. com', + $subscriber = Subscriber::createOrUpdate([ + 'email' => 'test@xample.com', 'first_name' => 'John', 'last_name' => 'Doe', ]); diff --git a/tests/integration/Newsletter/Preview/SendPreviewControllerTest.php b/tests/integration/Newsletter/Preview/SendPreviewControllerTest.php index b585130f7b..cc3d7bc625 100644 --- a/tests/integration/Newsletter/Preview/SendPreviewControllerTest.php +++ b/tests/integration/Newsletter/Preview/SendPreviewControllerTest.php @@ -5,6 +5,7 @@ namespace MailPoet\Newsletter\Preview; use Codeception\Stub\Expected; use Codeception\Util\Fixtures; use MailPoet\Entities\NewsletterEntity; +use MailPoet\Entities\SubscriberEntity; use MailPoet\Mailer\Mailer; use MailPoet\Mailer\MailerError; use MailPoet\Mailer\MetaInfo; @@ -25,6 +26,8 @@ class SendPreviewControllerTest extends \MailPoetTest { public function _before() { parent::_before(); + $this->truncateEntity(NewsletterEntity::class); + $this->truncateEntity(SubscriberEntity::class); $this->subscriptionUrlFactory = SubscriptionUrlFactory::getInstance(); $newsletter = new NewsletterEntity(); $newsletter->setType(NewsletterEntity::TYPE_STANDARD); @@ -33,10 +36,25 @@ class SendPreviewControllerTest extends \MailPoetTest { $newsletter->setBody(json_decode(Fixtures::get('newsletter_body_template'), true)); $newsletter->setHash(Security::generateHash()); $this->entityManager->persist($newsletter); + + $subscriber = new SubscriberEntity(); + $subscriber->setEmail('test@subscriber.com'); + $subscriber->setWpUserId(5); + $this->entityManager->persist($subscriber); $this->entityManager->flush(); + + $wpUser = new \stdClass(); + $wpUser->ID = 5; + $wp = $this->make(WPFunctions::class, ['wpGetCurrentUser' => $wpUser]); + WPFunctions::set($wp); + $this->newsletter = $newsletter; } + public function _after() { + WPFunctions::set(new WPFunctions()); + } + public function testItCanSendAPreview() { $mailer = $this->makeEmpty(Mailer::class, [ 'send' => Expected::once( @@ -71,8 +89,8 @@ class SendPreviewControllerTest extends \MailPoetTest { new MetaInfo(), $this->diContainer->get(Renderer::class), new WPFunctions(), - $this->diContainer->get(Shortcodes::class), - $this->diContainer->get(SubscribersRepository::class) + $this->diContainer->get(SubscribersRepository::class), + $this->diContainer->get(Shortcodes::class) ); $sendPreviewController->sendPreview($this->newsletter, 'test@subscriber.com'); } @@ -100,8 +118,8 @@ class SendPreviewControllerTest extends \MailPoetTest { new MetaInfo(), $this->diContainer->get(Renderer::class), new WPFunctions(), - $this->diContainer->get(Shortcodes::class), - $this->diContainer->get(SubscribersRepository::class) + $this->diContainer->get(SubscribersRepository::class), + $this->diContainer->get(Shortcodes::class) ); $sendPreviewController->sendPreview($this->newsletter, 'test@subscriber.com'); } diff --git a/tests/integration/Newsletter/ShortcodesTest.php b/tests/integration/Newsletter/ShortcodesTest.php index 2c3fb8ee47..edca471ef5 100644 --- a/tests/integration/Newsletter/ShortcodesTest.php +++ b/tests/integration/Newsletter/ShortcodesTest.php @@ -9,6 +9,7 @@ use MailPoet\Entities\SendingQueueEntity; use MailPoet\Entities\SubscriberCustomFieldEntity; use MailPoet\Entities\SubscriberEntity; use MailPoet\Models\Newsletter; +use MailPoet\Models\Newsletter as NewsletterModel; use MailPoet\Models\Subscriber; use MailPoet\Newsletter\Shortcodes\Categories\Date; use MailPoet\Newsletter\Shortcodes\Shortcodes; @@ -36,18 +37,22 @@ class ShortcodesTest extends \MailPoetTest { public function _before() { parent::_before(); + $this->cleanup(); $this->settings = SettingsController::getInstance(); $populator = $this->diContainer->get(Populator::class); $populator->up(); $this->wPUser = $this->_createWPUser(); $this->wPPost = $this->_createWPPost(); $this->subscriber = $this->_createSubscriber(); + $this->entityManager->persist($this->subscriber); $this->newsletter = $this->_createNewsletter(); + $this->entityManager->persist($this->newsletter); $this->shortcodesObject = $this->diContainer->get(Shortcodes::class); $this->shortcodesObject->setNewsletter($this->newsletter); $this->shortcodesObject->setSubscriber($this->subscriber); $this->settings->set('tracking.enabled', false); $this->subscriptionUrlFactory = new SubscriptionUrlFactory(WPFunctions::get(), $this->settings, new LinkTokens); + $this->entityManager->flush(); } public function testItCanExtractShortcodes() { @@ -98,21 +103,22 @@ class ShortcodesTest extends \MailPoetTest { } public function testItCanProcessDateShortcodes() { + $date = $this->diContainer->get(Date::class); $shortcodeDetails = ['action' => 'd']; - expect(Date::process($shortcodeDetails))->equals(date_i18n('d', WPFunctions::get()->currentTime('timestamp'))); + expect($date->process($shortcodeDetails))->equals(date_i18n('d', WPFunctions::get()->currentTime('timestamp'))); $shortcodeDetails = ['action' => 'dordinal']; - expect(Date::process($shortcodeDetails))->equals(date_i18n('jS', WPFunctions::get()->currentTime('timestamp'))); + expect($date->process($shortcodeDetails))->equals(date_i18n('jS', WPFunctions::get()->currentTime('timestamp'))); $shortcodeDetails = ['action' => 'dtext']; - expect(Date::process($shortcodeDetails))->equals(date_i18n('l', WPFunctions::get()->currentTime('timestamp'))); + expect($date->process($shortcodeDetails))->equals(date_i18n('l', WPFunctions::get()->currentTime('timestamp'))); $shortcodeDetails = ['action' => 'm']; - expect(Date::process($shortcodeDetails))->equals(date_i18n('m', WPFunctions::get()->currentTime('timestamp'))); + expect($date->process($shortcodeDetails))->equals(date_i18n('m', WPFunctions::get()->currentTime('timestamp'))); $shortcodeDetails = ['action' => 'mtext']; - expect(Date::process($shortcodeDetails))->equals(date_i18n('F', WPFunctions::get()->currentTime('timestamp'))); + expect($date->process($shortcodeDetails))->equals(date_i18n('F', WPFunctions::get()->currentTime('timestamp'))); $shortcodeDetails = ['action' => 'y']; - expect(Date::process($shortcodeDetails))->equals(date_i18n('Y', WPFunctions::get()->currentTime('timestamp'))); + expect($date->process($shortcodeDetails))->equals(date_i18n('Y', WPFunctions::get()->currentTime('timestamp'))); // allow custom date formats (http://php.net/manual/en/function.date.php) $shortcodeDetails = ['action' => 'custom', 'action_argument' => 'format', 'action_argument_value' => 'U F']; - expect(Date::process($shortcodeDetails))->equals(date_i18n('U F', WPFunctions::get()->currentTime('timestamp'))); + expect($date->process($shortcodeDetails))->equals(date_i18n('U F', WPFunctions::get()->currentTime('timestamp'))); } public function testItCanProcessNewsletterShortcodes() { @@ -186,20 +192,16 @@ class ShortcodesTest extends \MailPoetTest { $result = $shortcodesObject->process(['[subscriber:displayname]']); expect($result[0])->equals($this->wPUser->user_login); - $subscribers = Subscriber::where('status', 'subscribed') - ->findMany(); + $subscribers = Subscriber::whereIn('status', [ + SubscriberEntity::STATUS_SUBSCRIBED, + SubscriberEntity::STATUS_UNCONFIRMED, + SubscriberEntity::STATUS_INACTIVE, + ])->findMany(); $subscriberCount = count($subscribers); $result = $shortcodesObject->process(['[subscriber:count]']); expect($result[0])->equals($subscriberCount); $this->subscriber->setStatus('unsubscribed'); - $result = - $shortcodesObject->process(['[subscriber:count]']); - expect($result[0])->equals($subscriberCount - 1); - $this->subscriber->setStatus('bounced'); - $result = - $shortcodesObject->process(['[subscriber:count]']); - expect($result[0])->equals($subscriberCount - 1); } public function testItCanProcessSubscriberCustomFieldShortcodes() { @@ -213,7 +215,7 @@ class ShortcodesTest extends \MailPoetTest { $result = $shortcodesObject->process( ['[subscriber:cf_' . $customField->getId() . ']'] ); - expect($result[0])->false(); + expect($result[0])->null(); $subscriberCustomField = new SubscriberCustomFieldEntity($subscriber, $customField, 'custom_field_value'); $this->entityManager->persist($subscriberCustomField); $this->entityManager->flush(); @@ -242,6 +244,7 @@ class ShortcodesTest extends \MailPoetTest { public function testItReturnsShortcodeWhenTrackingEnabled() { $shortcodesObject = $this->shortcodesObject; + $shortcodesObject->setWpUserPreview(false); // Returns URL when tracking is not enabled $shortcode = '[link:subscription_unsubscribe_url]'; $result = @@ -278,6 +281,8 @@ class ShortcodesTest extends \MailPoetTest { public function testItReturnsDefaultLinksWhenPreviewIsEnabled() { $shortcodesObject = $this->shortcodesObject; $shortcodesObject->setWpUserPreview(true); + $shortcodesObject->setSubscriber(null); + $newsletterModel = NewsletterModel::where('id', $this->newsletter->getId())->findOne(); $shortcodes = [ '[link:subscription_unsubscribe_url]', '[link:subscription_instant_unsubscribe_url]', @@ -288,7 +293,7 @@ class ShortcodesTest extends \MailPoetTest { $this->subscriptionUrlFactory->getConfirmUnsubscribeUrl(null), $this->subscriptionUrlFactory->getUnsubscribeUrl(null), $this->subscriptionUrlFactory->getManageUrl(null), - NewsletterUrl::getViewInBrowserUrl($this->newsletter), + NewsletterUrl::getViewInBrowserUrl($newsletterModel), ]; $result = $shortcodesObject->process($shortcodes); // hash is returned @@ -299,19 +304,21 @@ class ShortcodesTest extends \MailPoetTest { public function testItCanProcessCustomLinkShortcodes() { $shortcodesObject = $this->shortcodesObject; + $shortcodesObject->setWpUserPreview(false); $shortcode = '[link:shortcode]'; $result = $shortcodesObject->process([$shortcode]); - expect($result[0])->false(); - add_filter('mailpoet_newsletter_shortcode_link', function( - $shortcode, $newsletter, $subscriber, $queue) { + expect($result[0])->null(); + remove_all_filters('mailpoet_newsletter_shortcode_link'); + add_filter('mailpoet_newsletter_shortcode_link', function($shortcode, $newsletter, $subscriber, $queue) { if ($shortcode === '[link:shortcode]') return 'success'; }, 10, 4); + $result = $shortcodesObject->process([$shortcode]); expect($result[0])->equals('success'); $this->settings->set('tracking.enabled', true); // tracking function only works during sending, so queue object must not be false $shortcodesObject->setQueue($this->_createQueue()); - $result = $shortcodesObject->process([$shortcode]); + $result = $shortcodesObject->process([$shortcode], 'x'); expect($result[0])->equals($shortcode); } @@ -359,12 +366,16 @@ class ShortcodesTest extends \MailPoetTest { } public function _after() { + $this->cleanup(); + } + + public function cleanup() { $this->truncateEntity(NewsletterEntity::class); $this->truncateEntity(SubscriberEntity::class); $this->truncateEntity(SendingQueueEntity::class); $this->truncateEntity(CustomFieldEntity::class); $this->truncateEntity(SubscriberCustomFieldEntity::class); - wp_delete_post($this->wPPost, true); - wp_delete_user($this->wPUser->ID); + if ($this->wPPost) wp_delete_post($this->wPPost, true); + if ($this->wPUser) wp_delete_user($this->wPUser->ID); } } diff --git a/tests/integration/Router/Endpoints/TrackTest.php b/tests/integration/Router/Endpoints/TrackTest.php index a95caf4d18..32fbc262fd 100644 --- a/tests/integration/Router/Endpoints/TrackTest.php +++ b/tests/integration/Router/Endpoints/TrackTest.php @@ -27,6 +27,7 @@ class TrackTest extends \MailPoetTest { public function _before() { parent::_before(); + $this->cleanup(); // create newsletter $newsletter = new NewsletterEntity(); $newsletter->setType('type'); @@ -48,12 +49,15 @@ class TrackTest extends \MailPoetTest { $queue = new SendingQueueEntity(); $queue->setTask($task); $queue->setNewsletter($newsletter); + $queue->setSubscribers((string)$subscriber->getId()); $this->queue = $queue; $this->entityManager->persist($queue); // create link $link = new NewsletterLinkEntity($newsletter, $queue, 'url', 'hash'); $this->link = $link; $this->entityManager->persist($link); + $scheduledTaskSubscriber = new ScheduledTaskSubscriberEntity($task, $subscriber, 1); + $this->entityManager->persist($scheduledTaskSubscriber); $this->entityManager->flush(); $subscriberModel = Subscriber::findOne($subscriber->getId()); $linkTokens = new LinkTokens; @@ -162,10 +166,10 @@ class TrackTest extends \MailPoetTest { public function testItProcessesTrackData() { $processedData = $this->track->_processTrackData($this->trackData); - expect($processedData->queue->id)->equals($this->queue->id); - expect($processedData->subscriber->id)->equals($this->subscriber->id); - expect($processedData->newsletter->id)->equals($this->newsletter->id); - expect($processedData->link->id)->equals($this->link->id); + expect($processedData->queue->getId())->equals($this->queue->getId()); + expect($processedData->subscriber->getId())->equals($this->subscriber->getId()); + expect($processedData->newsletter->getId())->equals($this->newsletter->getId()); + expect($processedData->link->getId())->equals($this->link->getId()); } public function testItGetsProperHashWhenDuplicateHashesExist() { @@ -175,16 +179,16 @@ class TrackTest extends \MailPoetTest { $newsletter = $newsletter->save(); $queue = SendingTask::create(); $queue->newsletterId = $newsletter->id; - $queue->setSubscribers([$this->subscriber->id]); - $queue->updateProcessedSubscribers([$this->subscriber->id]); + $queue->setSubscribers([$this->subscriber->getId()]); + $queue->updateProcessedSubscribers([$this->subscriber->getId()]); $queue->save(); $trackData = $this->trackData; $trackData['queue_id'] = $queue->id; $trackData['newsletter_id'] = $newsletter->id; // create another link with the same hash but different queue ID $link = NewsletterLink::create(); - $link->hash = $this->link->hash; - $link->url = $this->link->url; + $link->hash = $this->link->getHash(); + $link->url = $this->link->getUrl(); $link->newsletterId = $trackData['newsletter_id']; $link->queueId = $trackData['queue_id']; $link = $link->save(); @@ -194,10 +198,14 @@ class TrackTest extends \MailPoetTest { // assert that the fetched link ID belong to the newly created link $processedData = $this->track->_processTrackData($trackData); - expect($processedData->link->id)->equals($link->id); + expect($processedData->link->getId())->equals($link->id); } public function _after() { + $this->cleanup(); + } + + private function cleanup() { $this->truncateEntity(NewsletterEntity::class); $this->truncateEntity(SubscriberEntity::class); $this->truncateEntity(NewsletterLinkEntity::class); diff --git a/tests/integration/Statistics/Track/ClicksTest.php b/tests/integration/Statistics/Track/ClicksTest.php index f1f9d23b46..1263f4c91b 100644 --- a/tests/integration/Statistics/Track/ClicksTest.php +++ b/tests/integration/Statistics/Track/ClicksTest.php @@ -15,6 +15,7 @@ use MailPoet\Models\SendingQueue; use MailPoet\Models\StatisticsClicks; use MailPoet\Models\StatisticsOpens; use MailPoet\Models\Subscriber; +use MailPoet\Newsletter\Shortcodes\Categories\Link as LinkShortcodeCategory; use MailPoet\Newsletter\Shortcodes\Shortcodes; use MailPoet\Settings\SettingsController; use MailPoet\Statistics\Track\Clicks; @@ -84,12 +85,22 @@ class ClicksTest extends \MailPoetTest { $this->settingsController = Stub::makeEmpty(SettingsController::class, [ 'get' => false, ], $this); - $this->clicks = new Clicks($this->settingsController, new Cookies(), $this->diContainer->get(Shortcodes::class)); + $this->clicks = new Clicks( + $this->settingsController, + new Cookies(), + $this->diContainer->get(Shortcodes::class), + $this->diContainer->get(LinkShortcodeCategory::class) + ); } public function testItAbortsWhenTrackDataIsEmptyOrMissingLink() { // abort function should be called twice: - $clicks = Stub::construct($this->clicks, [$this->settingsController, new Cookies()], [ + $clicks = Stub::construct($this->clicks, [ + $this->settingsController, + new Cookies(), + $this->diContainer->get(Shortcodes::class), + $this->diContainer->get(LinkShortcodeCategory::class), + ], [ 'abort' => Expected::exactly(2), ], $this); $data = $this->trackData; @@ -105,7 +116,12 @@ class ClicksTest extends \MailPoetTest { $this->subscriber->setWpUserId(99); $this->entityManager->flush(); $data->preview = true; - $clicks = Stub::construct($this->clicks, [$this->settingsController, new Cookies()], [ + $clicks = Stub::construct($this->clicks, [ + $this->settingsController, + new Cookies(), + $this->diContainer->get(Shortcodes::class), + $this->diContainer->get(LinkShortcodeCategory::class), + ], [ 'redirectToUrl' => null, ], $this); $clicks->track($data); @@ -115,7 +131,12 @@ class ClicksTest extends \MailPoetTest { public function testItTracksClickAndOpenEvent() { $data = $this->trackData; - $clicks = Stub::construct($this->clicks, [$this->settingsController, new Cookies()], [ + $clicks = Stub::construct($this->clicks, [ + $this->settingsController, + new Cookies(), + $this->diContainer->get(Shortcodes::class), + $this->diContainer->get(LinkShortcodeCategory::class), + ], [ 'redirectToUrl' => null, ], $this); $clicks->track($data); @@ -124,14 +145,24 @@ class ClicksTest extends \MailPoetTest { } public function testItRedirectsToUrlAfterTracking() { - $clicks = Stub::construct($this->clicks, [$this->settingsController, new Cookies()], [ + $clicks = Stub::construct($this->clicks, [ + $this->settingsController, + new Cookies(), + $this->diContainer->get(Shortcodes::class), + $this->diContainer->get(LinkShortcodeCategory::class), + ], [ 'redirectToUrl' => Expected::exactly(1), ], $this); $clicks->track($this->trackData); } public function testItIncrementsClickEventCount() { - $clicks = Stub::construct($this->clicks, [$this->settingsController, new Cookies()], [ + $clicks = Stub::construct($this->clicks, [ + $this->settingsController, + new Cookies(), + $this->diContainer->get(Shortcodes::class), + $this->diContainer->get(LinkShortcodeCategory::class), + ], [ 'redirectToUrl' => null, ], $this); $clicks->track($this->trackData); @@ -152,7 +183,12 @@ class ClicksTest extends \MailPoetTest { } public function testItFailsToConvertsInvalidShortcodeToUrl() { - $clicks = Stub::construct($this->clicks, [$this->settingsController, new Cookies()], [ + $clicks = Stub::construct($this->clicks, [ + $this->settingsController, + new Cookies(), + $this->diContainer->get(Shortcodes::class), + $this->diContainer->get(LinkShortcodeCategory::class), + ], [ 'abort' => Expected::exactly(1), ], $this); // should call abort() method if shortcode action does not exist diff --git a/tests/integration/Statistics/Track/OpensTest.php b/tests/integration/Statistics/Track/OpensTest.php index 72651c222d..2bf8d68e99 100644 --- a/tests/integration/Statistics/Track/OpensTest.php +++ b/tests/integration/Statistics/Track/OpensTest.php @@ -4,11 +4,16 @@ namespace MailPoet\Test\Statistics\Track; use Codeception\Stub; use Codeception\Stub\Expected; +use MailPoet\Entities\NewsletterEntity; +use MailPoet\Entities\ScheduledTaskEntity; +use MailPoet\Entities\SendingQueueEntity; +use MailPoet\Entities\SubscriberEntity; use MailPoet\Models\Newsletter; use MailPoet\Models\ScheduledTask; use MailPoet\Models\SendingQueue; use MailPoet\Models\StatisticsOpens; use MailPoet\Models\Subscriber; +use MailPoet\Models\Subscriber as SubscriberModel; use MailPoet\Statistics\Track\Opens; use MailPoet\Subscribers\LinkTokens; use MailPoet\Tasks\Sending as SendingTask; @@ -23,29 +28,43 @@ class OpensTest extends \MailPoetTest { public function _before() { parent::_before(); + $this->cleanup(); // create newsletter - $newsletter = Newsletter::create(); - $newsletter->type = 'type'; - $this->newsletter = $newsletter->save(); + $newsletter = new NewsletterEntity(); + $newsletter->setType('type'); + $newsletter->setSubject('subject'); + $this->entityManager->persist($newsletter); + $this->newsletter = $newsletter; // create subscriber - $subscriber = Subscriber::create(); - $subscriber->email = 'test@example.com'; - $subscriber->firstName = 'First'; - $subscriber->lastName = 'Last'; - $this->subscriber = $subscriber->save(); + $subscriber = new SubscriberEntity(); + $subscriber->setEmail('test@example.com'); + $subscriber->setFirstName('First'); + $subscriber->setLastName('Last'); + $subscriber->setLinkToken('token'); + $this->subscriber = $subscriber; + $this->entityManager->persist($subscriber); // create queue - $queue = SendingTask::create(); - $queue->newsletterId = $newsletter->id; - $queue->setSubscribers([$subscriber->id]); - $queue->updateProcessedSubscribers([$subscriber->id]); - $this->queue = $queue->save(); + $task = new ScheduledTaskEntity(); + $task->setType(SendingTask::TASK_TYPE); + $task->setStatus(ScheduledTaskEntity::STATUS_COMPLETED); + $this->entityManager->persist($task); + + $queue = new SendingQueueEntity(); + $queue->setNewsletter($newsletter); + $queue->setTask($task); + $queue->setSubscribers((string)$subscriber->getId()); + $newsletter->getQueues()->add($queue); + $this->entityManager->persist($queue); + $this->entityManager->flush(); + + $this->queue = $queue; $linkTokens = new LinkTokens; // build track data $this->trackData = (object)[ 'queue' => $queue, 'subscriber' => $subscriber, 'newsletter' => $newsletter, - 'subscriber_token' => $linkTokens->getToken($subscriber), + 'subscriber_token' => $linkTokens->getToken(SubscriberModel::findOne('test@example.com')), 'preview' => false, ]; // instantiate class @@ -62,7 +81,7 @@ class OpensTest extends \MailPoetTest { public function testItDoesNotTrackOpenEventFromWpUserWhenPreviewIsEnabled() { $data = $this->trackData; - $data->subscriber->wp_user_id = 99; + $data->subscriber->setWpUserId(99); $data->preview = true; $opens = Stub::make($this->opens, [ 'returnResponse' => null, @@ -101,6 +120,10 @@ class OpensTest extends \MailPoetTest { } public function _after() { + $this->cleanup(); + } + + public function cleanup() { ORM::raw_execute('TRUNCATE ' . Newsletter::$_table); ORM::raw_execute('TRUNCATE ' . Subscriber::$_table); ORM::raw_execute('TRUNCATE ' . ScheduledTask::$_table);