Use Newsletter entity in renderer

[MAILPOET-2899]
This commit is contained in:
Pavel Dohnal
2020-05-26 16:36:42 +02:00
committed by Veljko V
parent f8a16b5e5a
commit 7b0c5e61fe
8 changed files with 120 additions and 91 deletions

View File

@ -43,7 +43,7 @@ class SendPreviewController {
throw new SendPreviewException("Newsletter with ID '{$newsletter->getId()}' not found");
}
$renderedNewsletter = $this->renderer->render($newsletterModel, $preview = true);
$renderedNewsletter = $this->renderer->render($newsletter, $preview = true);
$divider = '***MailPoet***';
$dataForShortcodes = array_merge(
[$newsletter->getSubject()],

View File

@ -2,6 +2,7 @@
namespace MailPoet\Newsletter\Renderer\Blocks;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Models\Newsletter;
use MailPoet\Models\NewsletterPost;
use MailPoet\Newsletter\AutomatedLatestContent;
@ -59,7 +60,7 @@ class Renderer {
$this->text = $text;
}
public function render($newsletter, $data) {
public function render(NewsletterEntity $newsletter, $data) {
$columnCount = count($data['blocks']);
$columnsLayout = isset($data['columnLayout']) ? $data['columnLayout'] : null;
$columnWidths = ColumnsHelper::columnWidth($columnCount, $columnsLayout);
@ -73,7 +74,7 @@ class Renderer {
return $columnContent;
}
private function renderBlocksInColumn($newsletter, $block, $columnBaseWidth) {
private function renderBlocksInColumn(NewsletterEntity $newsletter, $block, $columnBaseWidth) {
$blockContent = '';
$_this = $this;
array_map(function($block) use (&$blockContent, $columnBaseWidth, $newsletter, $_this) {
@ -91,7 +92,7 @@ class Renderer {
return $blockContent;
}
public function createElementFromBlockType($newsletter, $block, $columnBaseWidth) {
public function createElementFromBlockType(NewsletterEntity $newsletter, $block, $columnBaseWidth) {
if ($block['type'] === 'automatedLatestContent') {
return $this->processAutomatedLatestContent($newsletter, $block, $columnBaseWidth);
}
@ -117,16 +118,20 @@ class Renderer {
return '';
}
public function automatedLatestContentTransformedPosts($newsletter, $args) {
public function automatedLatestContentTransformedPosts(NewsletterEntity $newsletter, $args) {
$newerThanTimestamp = false;
$newsletterId = false;
if ($newsletter['type'] === Newsletter::TYPE_NOTIFICATION_HISTORY) {
$newsletterId = $newsletter['parent_id'];
if ($newsletter->getType() === Newsletter::TYPE_NOTIFICATION_HISTORY) {
$parent = $newsletter->getParent();
if ($parent instanceof NewsletterEntity) {
$newsletterId = $parent->getId();
$lastPost = NewsletterPost::getNewestNewsletterPost($newsletterId);
if ($lastPost) {
$newerThanTimestamp = $lastPost->createdAt;
}
}
}
$postsToExclude = $this->getPosts();
$aLCPosts = $this->ALC->getPosts($args, $postsToExclude, $newsletterId, $newerThanTimestamp);
@ -137,7 +142,7 @@ class Renderer {
return $this->ALC->transformPosts($args, $aLCPosts);
}
public function processAutomatedLatestContent($newsletter, $args, $columnBaseWidth) {
public function processAutomatedLatestContent(NewsletterEntity $newsletter, $args, $columnBaseWidth) {
$transformedPosts = [
'blocks' => $this->automatedLatestContentTransformedPosts($newsletter, $args),
];

View File

@ -2,6 +2,7 @@
namespace MailPoet\Newsletter\Renderer;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Newsletter\Editor\LayoutHelper;
use MailPoet\Newsletter\Renderer\Blocks\Renderer as BlocksRenderer;
use MailPoet\WooCommerce\TransactionalEmails;
@ -32,10 +33,10 @@ class Preprocessor {
/**
* @param array $content
* @param array $newsletter
* @param NewsletterEntity $newsletter
* @return array
*/
public function process($newsletter, $content) {
public function process(NewsletterEntity $newsletter, $content) {
if (!array_key_exists('blocks', $content)) {
return $content;
}
@ -47,12 +48,7 @@ class Preprocessor {
return $content;
}
/**
* @param array $block
* @param array $newsletter
* @return array
*/
public function processBlock($newsletter, $block) {
public function processBlock(NewsletterEntity $newsletter, array $block): array {
switch ($block['type']) {
case 'automatedLatestContentLayout':
return $this->blocksRenderer->automatedLatestContentTransformedPosts($newsletter, $block);

View File

@ -3,14 +3,20 @@
namespace MailPoet\Newsletter\Renderer;
use MailPoet\Config\Env;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Models\Newsletter;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Newsletter\Renderer\EscapeHelper as EHelper;
use MailPoet\RuntimeException;
use MailPoet\Services\Bridge;
use MailPoet\Util\License\License;
use MailPoet\Util\pQuery\DomNode;
use MailPoet\WP\Functions as WPFunctions;
class Renderer {
const NEWSLETTER_TEMPLATE = 'Template.html';
const FILTER_POST_PROCESS = 'mailpoet_rendering_post_process';
/** @var Blocks\Renderer */
private $blocksRenderer;
@ -29,8 +35,8 @@ class Renderer {
/** @var License */
private $license;
const NEWSLETTER_TEMPLATE = 'Template.html';
const FILTER_POST_PROCESS = 'mailpoet_rendering_post_process';
/** @var NewslettersRepository */
private $newslettersRepository;
public function __construct(
Blocks\Renderer $blocksRenderer,
@ -38,6 +44,7 @@ class Renderer {
Preprocessor $preprocessor,
\MailPoetVendor\CSS $cSSInliner,
Bridge $bridge,
NewslettersRepository $newslettersRepository,
License $license
) {
$this->blocksRenderer = $blocksRenderer;
@ -46,15 +53,29 @@ class Renderer {
$this->cSSInliner = $cSSInliner;
$this->bridge = $bridge;
$this->license = $license;
$this->newslettersRepository = $newslettersRepository;
}
/**
* @param \MailPoet\Models\Newsletter|array $newsletter
* This is only temporary, when all calls are refactored to doctrine and only entity is passed we don't need this
* @param \MailPoet\Models\Newsletter|NewsletterEntity $newsletter
* @return NewsletterEntity|null
*/
private function getNewsletter($newsletter) {
if ($newsletter instanceof NewsletterEntity) return $newsletter;
if ($newsletter instanceof Newsletter) {
$newsletterId = $newsletter->id;
}
return $this->newslettersRepository->findOneById($newsletterId);
}
public function render($newsletter, $preview = false, $type = false) {
$newsletter = ($newsletter instanceof Newsletter) ? $newsletter->asArray() : $newsletter;
$body = (is_array($newsletter['body']))
? $newsletter['body']
$newsletter = $this->getNewsletter($newsletter);
if (!$newsletter instanceof NewsletterEntity) {
throw new RuntimeException('Newsletter was not found');
}
$body = (is_array($newsletter->getBody()))
? $newsletter->getBody()
: [];
$content = (array_key_exists('content', $body))
? $body['content']
@ -79,10 +100,10 @@ class Renderer {
$template = $this->injectContentIntoTemplate(
(string)file_get_contents(dirname(__FILE__) . '/' . self::NEWSLETTER_TEMPLATE),
[
htmlspecialchars($newsletter['subject']),
htmlspecialchars($newsletter->getSubject()),
$renderedStyles,
$customFontsLinks,
EHelper::escapeHtmlText($newsletter['preheader']),
EHelper::escapeHtmlText($newsletter->getPreheader()),
$renderedBody,
]
);
@ -103,11 +124,11 @@ class Renderer {
}
/**
* @param array $newsletter
* @param NewsletterEntity $newsletter
* @param array $content
* @return string
*/
private function renderBody($newsletter, $content) {
private function renderBody(NewsletterEntity $newsletter, array $content) {
$blocks = (array_key_exists('blocks', $content))
? $content['blocks']
: [];

View File

@ -3,6 +3,8 @@
namespace MailPoet\Test\Newsletter;
use Codeception\Util\Fixtures;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Newsletter\Renderer\Blocks\Button;
use MailPoet\Newsletter\Renderer\Blocks\Divider;
use MailPoet\Newsletter\Renderer\Blocks\Footer;
@ -22,8 +24,10 @@ class RendererTest extends \MailPoetTest {
public $dOMParser;
public $columnRenderer;
/** @var Renderer & MockObject */
/** @var Renderer */
public $renderer;
/** @var NewsletterEntity */
public $newsletter;
/** @var License & MockObject */
@ -35,16 +39,14 @@ class RendererTest extends \MailPoetTest {
public function _before() {
parent::_before();
$this->newsletter = [
'body' => json_decode(
$this->newsletter = new NewsletterEntity();
$this->newsletter->setBody(json_decode(
(string)file_get_contents(dirname(__FILE__) . '/RendererTestData.json'), true
),
'id' => 1,
'subject' => 'Some subject',
'preheader' => 'Some preheader',
'type' => 'standard',
'status' => 'active',
];
));
$this->newsletter->setSubject('Some subject');
$this->newsletter->setPreheader('Some preheader');
$this->newsletter->setType('standard');
$this->newsletter->setStatus('active');
$this->license = $this->createMock(License::class);
$this->bridge = $this->createMock(Bridge::class);
$this->renderer = new Renderer(
@ -53,6 +55,7 @@ class RendererTest extends \MailPoetTest {
$this->diContainer->get(Preprocessor::class),
$this->diContainer->get(\MailPoetVendor\CSS::class),
$this->bridge,
$this->diContainer->get(NewslettersRepository::class),
$this->license
);
$this->columnRenderer = new ColumnRenderer();
@ -247,7 +250,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItRendersHeader() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][0];
$DOM = $this->dOMParser->parseStr((new Header)->render($template));
// element should be properly nested, and styles should be applied
@ -258,7 +261,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItRendersImage() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][1];
$DOM = $this->dOMParser->parseStr((new Image)->render($template, self::COLUMN_BASE_WIDTH));
// element should be properly nested, it's width set and style applied
@ -266,7 +269,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItRendersAlignedImage() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][1];
// default alignment (center)
unset($template['styles']['block']['textAlign']);
@ -326,7 +329,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItRendersImageWithLink() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][1];
$template['link'] = 'http://example.com';
$DOM = $this->dOMParser->parseStr((new Image)->render($template, self::COLUMN_BASE_WIDTH));
@ -404,7 +407,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItRendersText() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][2];
$DOM = $this->dOMParser->parseStr((new Text)->render($template));
// blockquotes and paragraphs should be converted to spans and placed inside a table
@ -444,7 +447,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItRendersDivider() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][3];
$DOM = $this->dOMParser->parseStr((new Divider)->render($template));
// element should be properly nested and its border-top-width set
@ -456,7 +459,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItRendersSpacer() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][4];
$DOM = $this->dOMParser->parseStr((new Spacer)->render($template));
// element should be properly nested and its height set
@ -464,7 +467,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItSetsSpacerBackground() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][4];
$DOM = $this->dOMParser->parseStr((new Spacer)->render($template));
expect($DOM('tr > td.mailpoet_spacer', 0)->attr('bgcolor'))->null();
@ -475,7 +478,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItCalculatesButtonWidth() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][5];
$template['styles']['block']['width'] = '700px';
$buttonWidth = (new Button)->calculateWidth($template, self::COLUMN_BASE_WIDTH);
@ -483,7 +486,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItRendersButton() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][5];
$DOM = $this->dOMParser->parseStr((new Button)->render($template, self::COLUMN_BASE_WIDTH));
// element should be properly nested with arcsize/styles/fillcolor set
@ -518,7 +521,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItUsesFullFontFamilyNameInElementStyles() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][5];
$template['styles']['block']['fontFamily'] = 'Lucida';
$DOM = $this->dOMParser->parseStr((new Button)->render($template, self::COLUMN_BASE_WIDTH));
@ -530,7 +533,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItRendersSocialIcons() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][6];
$DOM = $this->dOMParser->parseStr((new Social)->render($template));
// element should be properly nested, contain social icons and
@ -558,7 +561,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItRendersFooter() {
$newsletter = $this->newsletter['body'];
$newsletter = (array)$this->newsletter->getBody();
$template = $newsletter['content']['blocks'][3]['blocks'][0]['blocks'][0];
$DOM = $this->dOMParser->parseStr((new Footer)->render($template));
// element should be properly nested, and styles should be applied
@ -569,26 +572,26 @@ class RendererTest extends \MailPoetTest {
}
public function testItSetsSubject() {
$this->newsletter['body'] = json_decode(Fixtures::get('newsletter_body_template'), true);
$this->newsletter->setBody(json_decode(Fixtures::get('newsletter_body_template'), true));
$template = $this->renderer->render($this->newsletter);
$DOM = $this->dOMParser->parseStr($template['html']);
$subject = trim($DOM('title')->text());
expect($subject)->equals($this->newsletter['subject']);
expect($subject)->equals($this->newsletter->getSubject());
}
public function testItSetsPreheader() {
$this->newsletter['body'] = json_decode(Fixtures::get('newsletter_body_template'), true);
$this->newsletter->setBody(json_decode(Fixtures::get('newsletter_body_template'), true));
$template = $this->renderer->render($this->newsletter);
$DOM = $this->dOMParser->parseStr($template['html']);
$preheader = trim($DOM('td.mailpoet_preheader')->text());
expect($preheader)->equals($this->newsletter['preheader']);
expect($preheader)->equals($this->newsletter->getPreheader());
}
public function testItDoesNotAddMailpoetLogoWhenPremiumIsActive() {
$this->bridge->method('isMailpoetSendingServiceEnabled')->willReturn(false);
$this->license->method('hasLicense')->willReturn(true);
$this->newsletter['body'] = json_decode(Fixtures::get('newsletter_body_template'), true);
$this->newsletter->setBody(json_decode(Fixtures::get('newsletter_body_template'), true));
$template = $this->renderer->render($this->newsletter, false);
expect($template['html'])->notContains('mailpoet_logo_newsletter.png');
}
@ -597,7 +600,7 @@ class RendererTest extends \MailPoetTest {
$this->license->method('hasLicense')->willReturn(false);
$this->bridge->method('isMailpoetSendingServiceEnabled')->willReturn(true);
$this->newsletter['body'] = json_decode(Fixtures::get('newsletter_body_template'), true);
$this->newsletter->setBody(json_decode(Fixtures::get('newsletter_body_template'), true));
$template = $this->renderer->render($this->newsletter, false);
expect($template['html'])->notContains('mailpoet_logo_newsletter.png');
}
@ -606,13 +609,13 @@ class RendererTest extends \MailPoetTest {
$this->bridge->method('isMailpoetSendingServiceEnabled')->willReturn(false);
$this->license->method('hasLicense')->willReturn(false);
$this->newsletter['body'] = json_decode(Fixtures::get('newsletter_body_template'), true);
$this->newsletter->setBody(json_decode(Fixtures::get('newsletter_body_template'), true));
$template = $this->renderer->render($this->newsletter, true);
expect($template['html'])->notContains('mailpoet_logo_newsletter.png');
}
public function testItAddsMailpoetLogo() {
$this->renderer->newsletter['body'] = json_decode(Fixtures::get('newsletter_body_template'), true);
$this->newsletter->setBody(json_decode(Fixtures::get('newsletter_body_template'), true));
$this->bridge->method('isMailpoetSendingServiceEnabled')->willReturn(false);
$this->license->method('hasLicense')->willReturn(false);
@ -621,7 +624,7 @@ class RendererTest extends \MailPoetTest {
}
public function testItPostProcessesTemplate() {
$this->newsletter['body'] = json_decode(Fixtures::get('newsletter_body_template'), true);
$this->newsletter->setBody(json_decode(Fixtures::get('newsletter_body_template'), true));
$template = $this->renderer->render($this->newsletter);
// !important should be stripped from everywhere except from with the <style> tag
expect(preg_match('/<style.*?important/s', $template['html']))->equals(1);

View File

@ -5,6 +5,7 @@ namespace MailPoet\WooCommerce\TransactionalEmails;
use Codeception\Stub;
use MailPoet\Models\Newsletter;
use MailPoet\Newsletter\Editor\LayoutHelper as L;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Newsletter\Renderer\Preprocessor;
use MailPoet\Newsletter\Renderer\Renderer as NewsletterRenderer;
use MailPoet\Services\Bridge;
@ -17,9 +18,7 @@ class RendererTest extends \MailPoetTest {
public function _before() {
parent::_before();
$this->newsletter = Stub::make(Newsletter::class, [
'asArray' => function() {
return [
$this->newsletter = Newsletter::createOrUpdate([
'type' => Newsletter::TYPE_WC_TRANSACTIONAL_EMAIL,
'subject' => 'WooCommerce Transactional Email',
'preheader' => '',
@ -32,8 +31,6 @@ class RendererTest extends \MailPoetTest {
L::row([L::col([['type' => 'text', 'text' => 'Some text after content']])]),
]),
],
];
},
]);
}
@ -55,6 +52,7 @@ class RendererTest extends \MailPoetTest {
),
$this->diContainer->get(\MailPoetVendor\CSS::class),
$this->diContainer->get(Bridge::class),
$this->diContainer->get(NewslettersRepository::class),
$this->diContainer->get(License::class)
);
@ -85,6 +83,7 @@ class RendererTest extends \MailPoetTest {
),
$this->diContainer->get(\MailPoetVendor\CSS::class),
$this->diContainer->get(Bridge::class),
$this->diContainer->get(NewslettersRepository::class),
$this->diContainer->get(License::class)
);
$renderer = new Renderer(new csstidy, $newsletterRenderer);

View File

@ -5,6 +5,7 @@ namespace MailPoet\WooCommerce;
use Codeception\Stub;
use MailPoet\DI\ContainerWrapper;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Entities\SettingEntity;
use MailPoet\Models\Newsletter;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Settings\SettingsController;
@ -29,6 +30,18 @@ class TransactionalEmailsTest extends \MailPoetTest {
private $newslettersRepository;
public function _before() {
$this->entityManager
->createQueryBuilder()
->delete()
->from(NewsletterEntity::class, 'n')
->getQuery()
->execute();
$this->entityManager
->createQueryBuilder()
->delete()
->from(SettingEntity::class, 's')
->getQuery()
->execute();
$this->wp = new WPFunctions();
$this->settings = SettingsController::getInstance();
$this->originalWcSettings = $this->settings->get('woocommerce');
@ -40,6 +53,7 @@ class TransactionalEmailsTest extends \MailPoetTest {
Stub::makeEmpty(WooCommerceHelper::class),
$this->newslettersRepository
);
$this->settings->set('woocommerce', $this->originalWcSettings);
}
public function testInitCreatesTransactionalEmailAndSavesItsId() {
@ -91,14 +105,4 @@ class TransactionalEmailsTest extends \MailPoetTest {
expect($footerTextBlock['text'])->equals('<p style="text-align: center;">Text <a href="http://example.com">Link</a></p>');
$this->wp->updateOption('woocommerce_email_footer_text', $optionOriginalValue);
}
public function _after() {
$this->entityManager
->createQueryBuilder()
->delete()
->from(NewsletterEntity::class, 'n')
->getQuery()
->execute();
$this->settings->set('woocommerce', $this->originalWcSettings);
}
}

View File

@ -3,6 +3,7 @@
namespace MailPoet\Test\Newsletter;
use Codeception\Stub;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Newsletter\Renderer\Blocks\Renderer;
use MailPoet\Newsletter\Renderer\Preprocessor;
use MailPoet\WooCommerce\TransactionalEmails;
@ -17,7 +18,7 @@ class PreprocessorTest extends \MailPoetUnitTest {
],
]);
$preprocessor = new Preprocessor($renderer, $transactionalEmails);
expect($preprocessor->processBlock([], ['type' => 'woocommerceHeading']))->equals([[
expect($preprocessor->processBlock(new NewsletterEntity(), ['type' => 'woocommerceHeading']))->equals([[
'type' => 'container',
'orientation' => 'horizontal',
'styles' => [
@ -42,7 +43,7 @@ class PreprocessorTest extends \MailPoetUnitTest {
public function testProcessWooCommerceContentBlock() {
$renderer = Stub::make(Renderer::class);
$preprocessor = new Preprocessor($renderer, Stub::make(TransactionalEmails::class));
expect($preprocessor->processBlock([], ['type' => 'woocommerceContent']))->equals([[
expect($preprocessor->processBlock(new NewsletterEntity(), ['type' => 'woocommerceContent']))->equals([[
'type' => 'container',
'orientation' => 'horizontal',
'styles' => [