Add minimalistic WpPostEntity for fetching basic post data for listing

[MAILPOET-5646]
This commit is contained in:
Rostislav Wolny
2023-11-06 16:51:06 +01:00
committed by Aschepikov
parent c9c7146ef1
commit 8be034822e
10 changed files with 107 additions and 41 deletions

View File

@@ -28,7 +28,7 @@ class EmailApiController {
* @return array - MailPoet specific email data that will be attached to the post API response
*/
public function getEmailData($postEmailData): array {
$newsletter = $this->newsletterRepository->findOneBy(['wpPostId' => $postEmailData['id']]);
$newsletter = $this->newsletterRepository->findOneBy(['wpPost' => $postEmailData['id']]);
return [
'id' => $newsletter ? $newsletter->getId() : null,
'subject' => $newsletter ? $newsletter->getSubject() : '',

View File

@@ -3,10 +3,12 @@
namespace MailPoet\EmailEditor\Integrations\MailPoet;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Entities\WpPostEntity;
use MailPoet\Features\FeaturesController;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Util\Security;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Doctrine\ORM\EntityManager;
class EmailEditor {
const MAILPOET_EMAIL_POST_TYPE = 'mailpoet_email';
@@ -23,16 +25,21 @@ class EmailEditor {
/** @var EmailApiController */
private $emailApiController;
/** @var EntityManager */
private $entityManager;
public function __construct(
WPFunctions $wp,
FeaturesController $featuresController,
NewslettersRepository $newsletterRepository,
EmailApiController $emailApiController
EmailApiController $emailApiController,
EntityManager $entityManager
) {
$this->wp = $wp;
$this->featuresController = $featuresController;
$this->newsletterRepository = $newsletterRepository;
$this->emailApiController = $emailApiController;
$this->entityManager = $entityManager;
}
public function initialize(): void {
@@ -66,13 +73,13 @@ class EmailEditor {
if ($post->post_type !== self::MAILPOET_EMAIL_POST_TYPE) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
return;
}
$newsletter = $this->newsletterRepository->findOneBy(['wpPostId' => $postId]);
$newsletter = $this->newsletterRepository->findOneBy(['wpPost' => $postId]);
if ($newsletter) {
return;
}
$newsletter = new NewsletterEntity();
$newsletter->setWpPostId($postId);
$newsletter->setSubject('New Editor Email ' . $postId);
$newsletter->setWpPost($this->entityManager->getReference(WpPostEntity::class, $postId));
$newsletter->setSubject(__('Subject', 'mailpoet'));
$newsletter->setType(NewsletterEntity::TYPE_STANDARD); // We allow only standard emails in the new editor for now
$newsletter->setHash(Security::generateHash());
$this->newsletterRepository->persist($newsletter);

View File

@@ -113,12 +113,6 @@ class NewsletterEntity {
*/
private $preheader = '';
/**
* @ORM\Column(type="integer", nullable=true)
* @var int|null
*/
private $wpPostId;
/**
* @ORM\Column(type="json", nullable=true)
* @var array|null
@@ -173,6 +167,13 @@ class NewsletterEntity {
*/
private $queues;
/**
* @ORM\OneToOne(targetEntity="MailPoet\Entities\WpPostEntity")
* @ORM\JoinColumn(name="wp_post_id", referencedColumnName="ID", nullable=true)
* @var WpPostEntity|null
*/
private $wpPost;
public function __construct() {
$this->children = new ArrayCollection();
$this->newsletterSegments = new ArrayCollection();
@@ -278,14 +279,6 @@ class NewsletterEntity {
return $this->status;
}
public function getWpPostId(): ?int {
return $this->wpPostId;
}
public function setWpPostId(?int $wpPostId): void {
$this->wpPostId = $wpPostId;
}
/**
* @param string $status
*/
@@ -573,23 +566,25 @@ class NewsletterEntity {
return in_array($this->getType(), [self::TYPE_NOTIFICATION_HISTORY, self::TYPE_STANDARD], true);
}
/**
* We don't use typehint for now because doctrine cache generator would fail as it doesn't know the class.
* @return \WP_Post|null
*/
public function getWpPost() {
if ($this->wpPostId === null) {
return null;
public function getWpPost(): ?WpPostEntity {
$this->safelyLoadToOneAssociation('wpPost');
return $this->wpPost;
}
$post = \WP_Post::get_instance($this->wpPostId);
return $post ?: null;
public function setWpPost(?WpPostEntity $wpPostEntity): void {
$this->wpPost = $wpPostEntity;
}
public function getWpPostId(): ?int {
$wpPost = $this->wpPost;
return $wpPost ? $wpPost->getId() : null;
}
public function getCampaignName(): ?string {
$post = $this->getWpPost();
if (!$post) {
$wpPost = $this->getWpPost();
if (!$wpPost) {
return null;
}
return $post->post_title; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
return $wpPost->getPostTitle();
}
}

View File

@@ -0,0 +1,50 @@
<?php declare(strict_types = 1);
namespace MailPoet\Entities;
use MailPoetVendor\Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
* @ORM\Table(name="posts")
*/
class WpPostEntity {
/**
* @ORM\Column(type="integer", name="ID")
* @ORM\Id
* @ORM\GeneratedValue
* @var int
*/
private $id;
/**
* @ORM\Column(type="string", name="post_title")
* @var string
*/
private $postTitle;
public function __construct(
int $id,
string $postTitle
) {
$this->id = $id;
$this->$postTitle = $postTitle;
}
public function getId(): int {
return $this->id;
}
public function getPostTitle(): string {
return $this->postTitle;
}
/**
* We don't use typehint for now because doctrine cache generator would fail as it doesn't know the class.
* @return \WP_Post|null
*/
public function getWpPostInstance() {
$post = \WP_Post::get_instance($this->id);
return $post ?: null;
}
}

View File

@@ -9,6 +9,7 @@ use MailPoet\Entities\NewsletterOptionFieldEntity;
use MailPoet\Entities\NewsletterSegmentEntity;
use MailPoet\Entities\ScheduledTaskEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\WpPostEntity;
use MailPoet\InvalidStateException;
use MailPoet\Models\Newsletter;
use MailPoet\Newsletter\Options\NewsletterOptionFieldsRepository;
@@ -201,8 +202,10 @@ class NewsletterSaveController {
$newPostId = $this->wp->wpInsertPost([
'post_content' => $post->post_content, // @phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
'post_type' => $post->post_type, // @phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
// translators: %s is the campaign name of the mail which has been copied.
'post_title' => sprintf(__('Copy of %s', 'mailpoet'), $post->post_title), // @phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
]);
$duplicate->setWpPostId($newPostId);
$duplicate->setWpPost($this->entityManager->getReference(WpPostEntity::class, $newPostId));
}
// create relationships between duplicate and segments

View File

@@ -468,10 +468,10 @@ class NewslettersRepository extends Repository {
// Fetch WP Posts IDs and delete them
/** @var int[] $wpPostsIds */
$wpPostsIds = $entityManager->createQueryBuilder()->select('n.wpPostId')
$wpPostsIds = $entityManager->createQueryBuilder()->select('wpp.id')
->from(NewsletterEntity::class, 'n')
->join('n.wpPost', 'wpp')
->where('n.id IN (:ids)')
->andWhere('n.wpPostId IS NOT NULL')
->setParameter('ids', $ids)
->getQuery()->getSingleColumnResult();
foreach ($wpPostsIds as $wpPostId) {

View File

@@ -87,7 +87,8 @@ class Renderer {
$language = $this->wp->getBloginfo('language');
$metaRobots = $preview ? '<meta name="robots" content="noindex, nofollow" />' : '';
$subject = $subject ?: $newsletter->getSubject();
$wpPost = $newsletter->getWpPost();
$wpPostEntity = $newsletter->getWpPost();
$wpPost = $wpPostEntity ? $wpPostEntity->getWpPostInstance() : null;
if ($this->featuresController->isSupported(FeaturesController::GUTENBERG_EMAIL_EDITOR) && $wpPost instanceof \WP_Post) {
$renderedNewsletter = $this->guntenbergRenderer->render($wpPost, $subject, $newsletter->getPreheader(), $language, $metaRobots);
} else {

View File

@@ -12,6 +12,7 @@ use MailPoet\Entities\ScheduledTaskSubscriberEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Entities\WpPostEntity;
use MailPoet\Util\Security;
use MailPoetVendor\Carbon\Carbon;
use MailPoetVendor\Doctrine\ORM\EntityManager;
@@ -420,7 +421,10 @@ class Newsletter {
if (isset($this->data['parent'])) $newsletter->setParent($this->data['parent']);
if (isset($this->data['deleted_at'])) $newsletter->setDeletedAt($this->data['deleted_at']);
if (isset($this->data['ga_campaign'])) $newsletter->setGaCampaign($this->data['ga_campaign']);
if (isset($this->data['wp_post_id'])) $newsletter->setWpPostId($this->data['wp_post_id']);
$entityManager = ContainerWrapper::getInstance()->get(EntityManager::class);
if (isset($this->data['wp_post_id'])) {
$newsletter->setWpPost($entityManager->getReference(WpPostEntity::class, intval($this->data['wp_post_id'])));
}
if (isset($this->data['unsubscribeToken'])) {
$newsletter->setUnsubscribeToken($this->data['unsubscribeToken']);

View File

@@ -20,6 +20,7 @@ use MailPoet\Entities\StatisticsOpenEntity;
use MailPoet\Entities\StatisticsWooCommercePurchaseEntity;
use MailPoet\Entities\StatsNotificationEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Entities\WpPostEntity;
use MailPoet\Newsletter\Sending\ScheduledTaskSubscribersRepository;
use MailPoet\Tasks\Sending as SendingTask;
use MailPoet\Test\DataFactories\NewsletterOptionField;
@@ -248,12 +249,14 @@ class NewsletterRepositoryTest extends \MailPoetTest {
public function testItDeletesWpPostsBulkDelete() {
$newsletter1 = $this->createNewsletter(NewsletterEntity::TYPE_STANDARD, NewsletterEntity::STATUS_SENDING);
$post1Id = $this->wp->wpInsertPost(['post_title' => 'Post 1']);
$newsletter1->setWpPostId($post1Id);
$newsletter1->setWpPost($this->entityManager->getReference(WpPostEntity::class, $post1Id));
$newsletter2 = $this->createNewsletter(NewsletterEntity::TYPE_WELCOME, NewsletterEntity::STATUS_SENDING);
$post2Id = $this->wp->wpInsertPost(['post_title' => 'Post 2']);
$newsletter2->setWpPostId($post2Id);
$newsletter2->setWpPost($this->entityManager->getReference(WpPostEntity::class, $post2Id));
$newsletter3 = $this->createNewsletter(NewsletterEntity::TYPE_STANDARD, NewsletterEntity::STATUS_SENDING);
$blogPost = $this->wp->wpInsertPost(['post_title' => 'Regular blog post']);
verify($this->wp->getPost($post1Id))->instanceOf(\WP_Post::class);
verify($this->wp->getPost($post2Id))->instanceOf(\WP_Post::class);
@@ -263,6 +266,7 @@ class NewsletterRepositoryTest extends \MailPoetTest {
$this->repository->bulkDelete([$newsletter1->getId(), $newsletter2->getId(), $newsletter3->getId()]);
verify($this->wp->getPost($post1Id))->null();
verify($this->wp->getPost($post2Id))->null();
verify($this->wp->getPost($blogPost))->instanceOf(\WP_Post::class);
}
public function testItGetsArchiveNewslettersForSegments() {

View File

@@ -10,6 +10,7 @@ use MailPoet\Entities\NewsletterSegmentEntity;
use MailPoet\Entities\ScheduledTaskEntity;
use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Entities\WpPostEntity;
use MailPoet\Newsletter\Scheduler\PostNotificationScheduler;
use MailPoet\Newsletter\Scheduler\Scheduler;
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
@@ -336,12 +337,13 @@ class NewsletterSaveControllerTest extends \MailPoetTest {
public function testItDuplicatesNewsletterWithAssociatedPost() {
$newsletter = $this->createNewsletter(NewsletterEntity::TYPE_STANDARD, NewsletterEntity::STATUS_SENT);
$wp = $this->diContainer->get(WPFunctions::class);
$postId = $wp->wpInsertPost(['post_content' => 'newsletter content']);
$newsletter->setWpPostId($postId);
$postId = $wp->wpInsertPost(['post_content' => 'newsletter content', 'post_title' => 'Newsletter Title']);
$newsletter->setWpPost($this->entityManager->getReference(WpPostEntity::class, $postId));
$this->entityManager->flush();
$duplicate = $this->saveController->duplicate($newsletter);
verify($duplicate->getWpPostId())->notEquals($postId);
$post = $wp->getPost($duplicate->getWpPostId());
verify($duplicate->getCampaignName())->equals('Copy of Newsletter Title');
verify($post->post_content)->equals('newsletter content'); // @phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
}