parent
52e61f6a3b
commit
4663531de2
|
|
@ -51,10 +51,10 @@ class ServiceProvider extends ModuleServiceProvider
|
||||||
*/
|
*/
|
||||||
protected function registerMailer()
|
protected function registerMailer()
|
||||||
{
|
{
|
||||||
MailManager::instance()->registerCallback(function ($template) {
|
MailManager::instance()->registerCallback(function ($manager) {
|
||||||
$template->registerMailTemplates([
|
$manager->registerMailTemplates([
|
||||||
'backend::mail.invite' => 'Invitation for newly created administrators.',
|
'backend::mail.invite',
|
||||||
'backend::mail.restore' => 'Password reset instructions for backend-end administrators.',
|
'backend::mail.restore',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
subject = "Welcome to October CMS"
|
subject = "Welcome to October CMS"
|
||||||
layout = "system"
|
layout = "system"
|
||||||
|
description = "Invite new admin to the site"
|
||||||
==
|
==
|
||||||
|
|
||||||
Hi {{ name }},
|
Hi {{ name }},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
subject = "Password Reset"
|
subject = "Password Reset"
|
||||||
layout = "system"
|
layout = "system"
|
||||||
|
description = "Reset an admin password"
|
||||||
==
|
==
|
||||||
|
|
||||||
Hello {{ name }},
|
Hello {{ name }},
|
||||||
|
|
|
||||||
|
|
@ -287,6 +287,21 @@ class ServiceProvider extends ModuleServiceProvider
|
||||||
*/
|
*/
|
||||||
protected function registerMailer()
|
protected function registerMailer()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Register system layouts
|
||||||
|
*/
|
||||||
|
MailManager::instance()->registerCallback(function ($manager) {
|
||||||
|
$manager->registerMailLayouts([
|
||||||
|
'default' => 'system::mail.default',
|
||||||
|
'system' => 'system::mail.system',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$manager->registerMailPartials([
|
||||||
|
'button' => 'system::mail.button',
|
||||||
|
'table' => 'system::mail.table',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Override system mailer with mail settings
|
* Override system mailer with mail settings
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,13 @@
|
||||||
|
|
||||||
use Twig;
|
use Twig;
|
||||||
use Markdown;
|
use Markdown;
|
||||||
|
use System\Models\MailPartial;
|
||||||
use System\Models\MailTemplate;
|
use System\Models\MailTemplate;
|
||||||
use System\Helpers\View as ViewHelper;
|
use System\Helpers\View as ViewHelper;
|
||||||
use System\Classes\PluginManager;
|
use System\Classes\PluginManager;
|
||||||
|
use System\Classes\MarkupManager;
|
||||||
|
use System\Twig\MailPartialTokenParser;
|
||||||
|
use System\Twig\MailComponentTokenParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class manages Mail sending functions
|
* This class manages Mail sending functions
|
||||||
|
|
@ -31,6 +35,21 @@ class MailManager
|
||||||
*/
|
*/
|
||||||
protected $registeredTemplates;
|
protected $registeredTemplates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array List of registered partials in the system
|
||||||
|
*/
|
||||||
|
protected $registeredPartials;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array List of registered layouts in the system
|
||||||
|
*/
|
||||||
|
protected $registeredLayouts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool Internal marker for rendering mode
|
||||||
|
*/
|
||||||
|
protected $isHtmlRenderMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function hijacks the `addContent` method of the `October\Rain\Mail\Mailer`
|
* This function hijacks the `addContent` method of the `October\Rain\Mail\Mailer`
|
||||||
* class, using the `mailer.beforeAddContent` event.
|
* class, using the `mailer.beforeAddContent` event.
|
||||||
|
|
@ -44,6 +63,16 @@ class MailManager
|
||||||
$this->templateCache[$code] = $template = MailTemplate::findOrMakeTemplate($code);
|
$this->templateCache[$code] = $template = MailTemplate::findOrMakeTemplate($code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start twig transaction
|
||||||
|
*/
|
||||||
|
$markupManager = MarkupManager::instance();
|
||||||
|
$markupManager->beginTransaction();
|
||||||
|
$markupManager->registerTokenParsers([
|
||||||
|
new MailPartialTokenParser,
|
||||||
|
new MailComponentTokenParser
|
||||||
|
]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Inject global view variables
|
* Inject global view variables
|
||||||
*/
|
*/
|
||||||
|
|
@ -63,6 +92,31 @@ class MailManager
|
||||||
/*
|
/*
|
||||||
* HTML contents
|
* HTML contents
|
||||||
*/
|
*/
|
||||||
|
$html = $this->renderHtmlContents($template, $data);
|
||||||
|
|
||||||
|
$message->setBody($html, 'text/html');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Text contents
|
||||||
|
*/
|
||||||
|
$text = $this->renderTextContents($template, $data);
|
||||||
|
|
||||||
|
$message->addPart($text, 'text/plain');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* End twig transaction
|
||||||
|
*/
|
||||||
|
$markupManager->endTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Rendering
|
||||||
|
//
|
||||||
|
|
||||||
|
public function renderHtmlContents($template, $data)
|
||||||
|
{
|
||||||
|
$this->isHtmlRenderMode = true;
|
||||||
|
|
||||||
$templateHtml = $template->content_html;
|
$templateHtml = $template->content_html;
|
||||||
|
|
||||||
$html = Twig::parse($templateHtml, $data);
|
$html = Twig::parse($templateHtml, $data);
|
||||||
|
|
@ -75,11 +129,13 @@ class MailManager
|
||||||
] + (array) $data);
|
] + (array) $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
$message->setBody($html, 'text/html');
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderTextContents($template, $data)
|
||||||
|
{
|
||||||
|
$this->isHtmlRenderMode = false;
|
||||||
|
|
||||||
/*
|
|
||||||
* Text contents
|
|
||||||
*/
|
|
||||||
$templateText = $template->content_text;
|
$templateText = $template->content_text;
|
||||||
|
|
||||||
if (!strlen($template->content_text)) {
|
if (!strlen($template->content_text)) {
|
||||||
|
|
@ -93,7 +149,45 @@ class MailManager
|
||||||
] + (array) $data);
|
] + (array) $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
$message->addPart($text, 'text/plain');
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderPartial($code, $params)
|
||||||
|
{
|
||||||
|
if (!$partial = MailPartial::whereCode($code)->first()) {
|
||||||
|
return '<!-- Missing partial: '.$code.' -->';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isHtmlRenderMode) {
|
||||||
|
return $this->renderHtmlPartial($partial, $params);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return $this->renderTextPartial($partial, $params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderHtmlPartial($partial, $params)
|
||||||
|
{
|
||||||
|
$content = $partial->content_html;
|
||||||
|
|
||||||
|
if (!strlen(trim($content))) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$params['body'] = Markdown::parse(array_get($params, 'body'));
|
||||||
|
|
||||||
|
return Twig::parse($content, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderTextPartial($partial, $params)
|
||||||
|
{
|
||||||
|
$content = $partial->content_text ?: $partial->content_html;
|
||||||
|
|
||||||
|
if (!strlen(trim($content))) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return Twig::parse($content, $params);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -134,6 +228,32 @@ class MailManager
|
||||||
return $this->registeredTemplates;
|
return $this->registeredTemplates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of the registered partials.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function listRegisteredPartials()
|
||||||
|
{
|
||||||
|
if ($this->registeredPartials === null) {
|
||||||
|
$this->loadRegisteredTemplates();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->registeredPartials;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of the registered layouts.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function listRegisteredLayouts()
|
||||||
|
{
|
||||||
|
if ($this->registeredLayouts === null) {
|
||||||
|
$this->loadRegisteredTemplates();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->registeredLayouts;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a callback function that defines mail templates.
|
* Registers a callback function that defines mail templates.
|
||||||
* The callback function should register templates by calling the manager's
|
* The callback function should register templates by calling the manager's
|
||||||
|
|
@ -160,6 +280,37 @@ class MailManager
|
||||||
$this->registeredTemplates = [];
|
$this->registeredTemplates = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->registeredTemplates = array_merge($this->registeredTemplates, $definitions);
|
// Prior sytax where (key) code => (value) description
|
||||||
|
if (!isset($definitions[0])) {
|
||||||
|
$definitions = array_keys($definitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
$definitions = array_combine($definitions, $definitions);
|
||||||
|
|
||||||
|
$this->registeredTemplates = $definitions + $this->registeredTemplates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers mail views and manageable layouts.
|
||||||
|
*/
|
||||||
|
public function registerMailPartials(array $definitions)
|
||||||
|
{
|
||||||
|
if (!$this->registeredPartials) {
|
||||||
|
$this->registeredPartials = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->registeredPartials = $definitions + $this->registeredPartials;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers mail views and manageable layouts.
|
||||||
|
*/
|
||||||
|
public function registerMailLayouts(array $definitions)
|
||||||
|
{
|
||||||
|
if (!$this->registeredLayouts) {
|
||||||
|
$this->registeredLayouts = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->registeredLayouts = $definitions + $this->registeredLayouts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ class MarkupManager
|
||||||
protected $callbacks = [];
|
protected $callbacks = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array Registered extension items
|
* @var array Globally registered extension items
|
||||||
*/
|
*/
|
||||||
protected $items;
|
protected $items;
|
||||||
|
|
||||||
|
|
@ -36,6 +36,16 @@ class MarkupManager
|
||||||
*/
|
*/
|
||||||
protected $pluginManager;
|
protected $pluginManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Transaction based extension items
|
||||||
|
*/
|
||||||
|
protected $tranItems;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool Manager is in transaction mode
|
||||||
|
*/
|
||||||
|
protected $transactionMode = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize this singleton.
|
* Initialize this singleton.
|
||||||
*/
|
*/
|
||||||
|
|
@ -71,7 +81,6 @@ class MarkupManager
|
||||||
|
|
||||||
$this->registerExtensions($type, $definitions);
|
$this->registerExtensions($type, $definitions);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,23 +114,25 @@ class MarkupManager
|
||||||
*/
|
*/
|
||||||
public function registerExtensions($type, array $definitions)
|
public function registerExtensions($type, array $definitions)
|
||||||
{
|
{
|
||||||
if (is_null($this->items)) {
|
$items = $this->transactionMode ? 'tranItems' : 'items';
|
||||||
$this->items = [];
|
|
||||||
|
if (is_null($this->$items)) {
|
||||||
|
$this->$items = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!array_key_exists($type, $this->items)) {
|
if (!array_key_exists($type, $this->$items)) {
|
||||||
$this->items[$type] = [];
|
$this->$items[$type] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($definitions as $name => $definition) {
|
foreach ($definitions as $name => $definition) {
|
||||||
|
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case self::EXTENSION_TOKEN_PARSER:
|
case self::EXTENSION_TOKEN_PARSER:
|
||||||
$this->items[$type][] = $definition;
|
$this->$items[$type][] = $definition;
|
||||||
break;
|
break;
|
||||||
case self::EXTENSION_FILTER:
|
case self::EXTENSION_FILTER:
|
||||||
case self::EXTENSION_FUNCTION:
|
case self::EXTENSION_FUNCTION:
|
||||||
$this->items[$type][$name] = $definition;
|
$this->$items[$type][$name] = $definition;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -161,15 +172,21 @@ class MarkupManager
|
||||||
*/
|
*/
|
||||||
public function listExtensions($type)
|
public function listExtensions($type)
|
||||||
{
|
{
|
||||||
|
$results = [];
|
||||||
|
|
||||||
if ($this->items === null) {
|
if ($this->items === null) {
|
||||||
$this->loadExtensions();
|
$this->loadExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($this->items[$type]) || !is_array($this->items[$type])) {
|
if (isset($this->items[$type]) && is_array($this->items[$type])) {
|
||||||
return [];
|
$results = $this->items[$type];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->items[$type];
|
if ($this->tranItems !== null && isset($this->tranItems[$type])) {
|
||||||
|
$results = array_merge($results, $this->tranItems[$type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -329,4 +346,41 @@ class MarkupManager
|
||||||
|
|
||||||
return $isWild;
|
return $isWild;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Transactions
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a single serving transaction, containing filters, functions,
|
||||||
|
* and token parsers that are disposed of afterwards.
|
||||||
|
* @param \Closure $callback
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function transaction(Closure $callback)
|
||||||
|
{
|
||||||
|
$this->beginTransaction();
|
||||||
|
$callback($this);
|
||||||
|
$this->endTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a new transaction.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function beginTransaction()
|
||||||
|
{
|
||||||
|
$this->transactionMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ends an active transaction.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function endTransaction()
|
||||||
|
{
|
||||||
|
$this->transactionMode = false;
|
||||||
|
|
||||||
|
$this->tranItems = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php namespace System\Controllers;
|
||||||
|
|
||||||
|
use Str;
|
||||||
|
use Lang;
|
||||||
|
use File;
|
||||||
|
use Flash;
|
||||||
|
use Backend;
|
||||||
|
use Redirect;
|
||||||
|
use BackendMenu;
|
||||||
|
use Backend\Classes\Controller;
|
||||||
|
use ApplicationException;
|
||||||
|
use System\Classes\SettingsManager;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mail partials controller
|
||||||
|
*
|
||||||
|
* @package october\system
|
||||||
|
* @author Alexey Bobkov, Samuel Georges
|
||||||
|
*/
|
||||||
|
class MailPartials extends Controller
|
||||||
|
{
|
||||||
|
public $implement = [
|
||||||
|
'Backend.Behaviors.FormController',
|
||||||
|
];
|
||||||
|
|
||||||
|
public $requiredPermissions = ['system.manage_mail_templates'];
|
||||||
|
|
||||||
|
public $formConfig = 'config_form.yaml';
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
BackendMenu::setContext('October.System', 'system', 'settings');
|
||||||
|
SettingsManager::setContext('October.System', 'mail_templates');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,7 +29,12 @@ class MailTemplates extends Controller
|
||||||
|
|
||||||
public $requiredPermissions = ['system.manage_mail_templates'];
|
public $requiredPermissions = ['system.manage_mail_templates'];
|
||||||
|
|
||||||
public $listConfig = ['templates' => 'config_templates_list.yaml', 'layouts' => 'config_layouts_list.yaml'];
|
public $listConfig = [
|
||||||
|
'templates' => 'config_templates_list.yaml',
|
||||||
|
'layouts' => 'config_layouts_list.yaml',
|
||||||
|
'partials' => 'config_partials_list.yaml'
|
||||||
|
];
|
||||||
|
|
||||||
public $formConfig = 'config_form.yaml';
|
public $formConfig = 'config_form.yaml';
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,4 @@ create:
|
||||||
|
|
||||||
update:
|
update:
|
||||||
redirect: system/mailtemplates
|
redirect: system/mailtemplates
|
||||||
redirectClose: system/mailtemplates
|
redirectClose: system/mailtemplates
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
# ===================================
|
||||||
|
# Form Behavior Config
|
||||||
|
# ===================================
|
||||||
|
|
||||||
|
name: system::lang.mail_templates.partial
|
||||||
|
form: ~/modules/system/models/mailpartial/fields.yaml
|
||||||
|
modelClass: System\Models\MailPartial
|
||||||
|
defaultRedirect: system/mailtemplates
|
||||||
|
|
||||||
|
create:
|
||||||
|
redirect: system/mailpartials/update/:id
|
||||||
|
redirectClose: system/mailtemplates
|
||||||
|
|
||||||
|
update:
|
||||||
|
redirect: system/mailtemplates
|
||||||
|
redirectClose: system/mailtemplates
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php Block::put('breadcrumb') ?>
|
||||||
|
<ul>
|
||||||
|
<li><a href="<?= Backend::url('system/mailtemplates') ?>"><?= e(trans('system::lang.mail_templates.menu_partials_label')) ?></a></li>
|
||||||
|
<li><?= e(trans($this->pageTitle)) ?></li>
|
||||||
|
</ul>
|
||||||
|
<?php Block::endPut() ?>
|
||||||
|
|
||||||
|
<?php if (!$this->fatalError): ?>
|
||||||
|
|
||||||
|
<?= Form::open(['class'=>'layout']) ?>
|
||||||
|
|
||||||
|
<div class="layout-row">
|
||||||
|
<?= $this->formRender() ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-buttons p-t">
|
||||||
|
<div class="loading-indicator-container">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
data-request="onSave"
|
||||||
|
data-hotkey="ctrl+s, cmd+s"
|
||||||
|
data-load-indicator="<?= e(trans('system::lang.mail_templates.creating_partial')) ?>"
|
||||||
|
class="btn btn-primary">
|
||||||
|
<?= e(trans('backend::lang.form.create')) ?>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
data-request="onSave"
|
||||||
|
data-request-data="close:1"
|
||||||
|
data-hotkey="ctrl+enter, cmd+enter"
|
||||||
|
data-load-indicator="<?= e(trans('system::lang.mail_templates.creating_partial')) ?>"
|
||||||
|
class="btn btn-default">
|
||||||
|
<?= e(trans('backend::lang.form.create_and_close')) ?>
|
||||||
|
</button>
|
||||||
|
<span class="btn-text">
|
||||||
|
<?= e(trans('backend::lang.form.or')) ?> <a href="<?= Backend::url('system/mailtemplates') ?>"><?= e(trans('backend::lang.form.close')) ?></a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?= Form::close() ?>
|
||||||
|
|
||||||
|
<?php else: ?>
|
||||||
|
|
||||||
|
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||||
|
<p><a href="<?= Backend::url('system/mailtemplates') ?>" class="btn btn-default"><?= e(trans('system::lang.mail_templates.return')) ?></a></p>
|
||||||
|
|
||||||
|
<?php endif ?>
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?php Block::put('breadcrumb') ?>
|
||||||
|
<ul>
|
||||||
|
<li><a href="<?= Backend::url('system/mailtemplates') ?>"><?= e(trans('system::lang.mail_templates.menu_partials_label')) ?></a></li>
|
||||||
|
<li><?= e(trans($this->pageTitle)) ?></li>
|
||||||
|
</ul>
|
||||||
|
<?php Block::endPut() ?>
|
||||||
|
|
||||||
|
<?php if (!$this->fatalError): ?>
|
||||||
|
|
||||||
|
<?= Form::open(['class'=>'layout']) ?>
|
||||||
|
|
||||||
|
<div class="layout-row min-size">
|
||||||
|
<div class="scoreboard">
|
||||||
|
<div data-control="toolbar">
|
||||||
|
<div class="scoreboard-item title-value">
|
||||||
|
<h4><?= e(trans('system::lang.mail_templates.layout')) ?></h4>
|
||||||
|
<p><?= $formModel->code ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layout-row">
|
||||||
|
<?= $this->formRender() ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-buttons p-t">
|
||||||
|
<div class="loading-indicator-container">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
data-request="onSave"
|
||||||
|
data-request-data="redirect:0"
|
||||||
|
data-hotkey="ctrl+s, cmd+s"
|
||||||
|
data-load-indicator="<?= e(trans('system::lang.mail_templates.saving_layout')) ?>"
|
||||||
|
class="btn btn-primary">
|
||||||
|
<?= e(trans('backend::lang.form.save')) ?>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
data-request="onSave"
|
||||||
|
data-request-data="close:1"
|
||||||
|
data-hotkey="ctrl+enter, cmd+enter"
|
||||||
|
data-load-indicator="<?= e(trans('system::lang.mail_templates.saving_layout')) ?>"
|
||||||
|
class="btn btn-default">
|
||||||
|
<?= e(trans('backend::lang.form.save_and_close')) ?>
|
||||||
|
</button>
|
||||||
|
<?php if (!$formModel->is_locked): ?>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="oc-icon-trash-o btn-icon danger pull-right"
|
||||||
|
data-request="onDelete"
|
||||||
|
data-load-indicator="<?= e(trans('system::lang.mail_templates.deleting_layout')) ?>"
|
||||||
|
data-request-confirm="<?= e(trans('system::lang.mail_templates.delete_layout_confirm')) ?>">
|
||||||
|
</button>
|
||||||
|
<?php endif ?>
|
||||||
|
<span class="btn-text">
|
||||||
|
<?= e(trans('backend::lang.form.or')) ?> <a href="<?= Backend::url('system/mailtemplates') ?>"><?= e(trans('backend::lang.form.cancel')) ?></a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?= Form::close() ?>
|
||||||
|
|
||||||
|
<?php else: ?>
|
||||||
|
|
||||||
|
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||||
|
<p><a href="<?= Backend::url('system/mailtemplates') ?>" class="btn btn-default"><?= e(trans('system::lang.mail_templates.return')) ?></a></p>
|
||||||
|
|
||||||
|
<?php endif ?>
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<div data-control="toolbar">
|
||||||
|
<a
|
||||||
|
href="<?= Backend::url('system/mailpartials/create') ?>"
|
||||||
|
class="btn btn-primary oc-icon-plus">
|
||||||
|
<?= e(trans('system::lang.mail_templates.new_partial')) ?>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
# ===================================
|
||||||
|
# List Behavior Config
|
||||||
|
# ===================================
|
||||||
|
|
||||||
|
title: system::lang.mail_partials.menu_label
|
||||||
|
list: ~/modules/system/models/mailpartial/columns.yaml
|
||||||
|
modelClass: System\Models\MailPartial
|
||||||
|
recordUrl: system/mailpartials/update/:id
|
||||||
|
noRecordsMessage: backend::lang.list.no_records
|
||||||
|
recordsPerPage: 20
|
||||||
|
showSetup: true
|
||||||
|
|
||||||
|
toolbar:
|
||||||
|
buttons: list_partials_toolbar
|
||||||
|
search:
|
||||||
|
prompt: backend::lang.list.search_prompt
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
<li class="active"><a href="#templates"><?= e(trans('system::lang.mail_templates.templates')) ?></a></li>
|
<li class="active"><a href="#templates"><?= e(trans('system::lang.mail_templates.templates')) ?></a></li>
|
||||||
<li><a href="#layouts"><?= e(trans('system::lang.mail_templates.layouts')) ?></a></li>
|
<li><a href="#layouts"><?= e(trans('system::lang.mail_templates.layouts')) ?></a></li>
|
||||||
|
<li><a href="#partials"><?= e(trans('system::lang.mail_templates.partials')) ?></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane active">
|
<div class="tab-pane active">
|
||||||
|
|
@ -10,5 +11,8 @@
|
||||||
<div class="tab-pane">
|
<div class="tab-pane">
|
||||||
<?= $this->listRender('layouts') ?>
|
<?= $this->listRender('layouts') ?>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tab-pane">
|
||||||
|
<?= $this->listRender('partials') ?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use October\Rain\Database\Schema\Blueprint;
|
||||||
|
use October\Rain\Database\Updates\Migration;
|
||||||
|
|
||||||
|
class DbSystemMailPartials extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('system_mail_partials', function (Blueprint $table) {
|
||||||
|
$table->engine = 'InnoDB';
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('name')->nullable();
|
||||||
|
$table->string('code')->nullable();
|
||||||
|
$table->text('content_html')->nullable();
|
||||||
|
$table->text('content_text')->nullable();
|
||||||
|
$table->boolean('is_custom')->default(0);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('system_mail_partials');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,74 +5,8 @@ use System\Models\MailLayout;
|
||||||
|
|
||||||
class SeedSetupMailLayouts extends Seeder
|
class SeedSetupMailLayouts extends Seeder
|
||||||
{
|
{
|
||||||
|
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
|
MailLayout::createLayouts();
|
||||||
$css = 'a, a:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #0862A2;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
td, tr, th, table {
|
|
||||||
padding: 0px;
|
|
||||||
margin: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 10px 0;
|
|
||||||
}';
|
|
||||||
|
|
||||||
$html = '<html>
|
|
||||||
<head>
|
|
||||||
<style type="text/css" media="screen">
|
|
||||||
{{ css|raw }}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{{ content|raw }}
|
|
||||||
</body>
|
|
||||||
</html>';
|
|
||||||
|
|
||||||
$text = '{{ content|raw }}';
|
|
||||||
|
|
||||||
MailLayout::create([
|
|
||||||
'is_locked' => true,
|
|
||||||
'name' => 'Default',
|
|
||||||
'code' => 'default',
|
|
||||||
'content_html' => $html,
|
|
||||||
'content_css' => $css,
|
|
||||||
'content_text' => $text,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$html = '<html>
|
|
||||||
<head>
|
|
||||||
<style type="text/css" media="screen">
|
|
||||||
{{ css|raw }}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{{ content|raw }}
|
|
||||||
<hr />
|
|
||||||
<p>This is an automatic message. Please do not reply to it.</p>
|
|
||||||
</body>
|
|
||||||
</html>';
|
|
||||||
|
|
||||||
$text = '{{ content|raw }}
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
This is an automatic message. Please do not reply to it.
|
|
||||||
';
|
|
||||||
|
|
||||||
MailLayout::create([
|
|
||||||
'is_locked' => true,
|
|
||||||
'name' => 'System',
|
|
||||||
'code' => 'system',
|
|
||||||
'content_html' => $html,
|
|
||||||
'content_css' => $css,
|
|
||||||
'content_text' => $text,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -190,9 +190,13 @@ return [
|
||||||
'menu_description' => 'Modify the mail templates that are sent to users and administrators, manage email layouts.',
|
'menu_description' => 'Modify the mail templates that are sent to users and administrators, manage email layouts.',
|
||||||
'new_template' => 'New Template',
|
'new_template' => 'New Template',
|
||||||
'new_layout' => 'New Layout',
|
'new_layout' => 'New Layout',
|
||||||
|
'new_partial' => 'New Partial',
|
||||||
'template' => 'Template',
|
'template' => 'Template',
|
||||||
'templates' => 'Templates',
|
'templates' => 'Templates',
|
||||||
|
'partial' => 'Partial',
|
||||||
|
'partials' => 'Partials',
|
||||||
'menu_layouts_label' => 'Mail Layouts',
|
'menu_layouts_label' => 'Mail Layouts',
|
||||||
|
'menu_partials_label' => 'Mail Partials',
|
||||||
'layout' => 'Layout',
|
'layout' => 'Layout',
|
||||||
'layouts' => 'Layouts',
|
'layouts' => 'Layouts',
|
||||||
'no_layout' => '-- No layout --',
|
'no_layout' => '-- No layout --',
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
<?php namespace System\Models;
|
<?php namespace System\Models;
|
||||||
|
|
||||||
|
use File;
|
||||||
|
use View;
|
||||||
use Model;
|
use Model;
|
||||||
|
use System\Classes\MailManager;
|
||||||
|
use October\Rain\Mail\MailParser;
|
||||||
use ApplicationException;
|
use ApplicationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -18,6 +22,19 @@ class MailLayout extends Model
|
||||||
*/
|
*/
|
||||||
protected $table = 'system_mail_layouts';
|
protected $table = 'system_mail_layouts';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Guarded fields
|
||||||
|
*/
|
||||||
|
protected $guarded = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Fillable fields
|
||||||
|
*/
|
||||||
|
protected $fillable = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Validation rules
|
||||||
|
*/
|
||||||
public $rules = [
|
public $rules = [
|
||||||
'code' => 'required|unique:system_mail_layouts',
|
'code' => 'required|unique:system_mail_layouts',
|
||||||
'name' => 'required',
|
'name' => 'required',
|
||||||
|
|
@ -47,4 +64,64 @@ class MailLayout extends Model
|
||||||
return array_get(self::listCodes(), $code);
|
return array_get(self::listCodes(), $code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loops over each mail layout and ensures the system has a layout,
|
||||||
|
* if the layout does not exist, it will create one.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function createLayouts()
|
||||||
|
{
|
||||||
|
$dbLayouts = self::lists('code', 'code');
|
||||||
|
|
||||||
|
$definitions = MailManager::instance()->listRegisteredLayouts();
|
||||||
|
foreach ($definitions as $code => $path) {
|
||||||
|
if (array_key_exists($code, $dbLayouts)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::createLayoutFromFile($code, $path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a layout using the contents of a specified file.
|
||||||
|
* @param string $code New Layout code
|
||||||
|
* @param string $viewPath View path
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function createLayoutFromFile($code, $viewPath)
|
||||||
|
{
|
||||||
|
$sections = self::getTemplateSections($viewPath);
|
||||||
|
|
||||||
|
$name = array_get($sections, 'settings.name', '???');
|
||||||
|
|
||||||
|
$css = 'a, a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #0862A2;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
td, tr, th, table {
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 10px 0;
|
||||||
|
}';
|
||||||
|
|
||||||
|
self::create([
|
||||||
|
'is_locked' => true,
|
||||||
|
'name' => $name,
|
||||||
|
'code' => $code,
|
||||||
|
'content_css' => $css,
|
||||||
|
'content_html' => array_get($sections, 'html'),
|
||||||
|
'content_text' => array_get($sections, 'text')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getTemplateSections($code)
|
||||||
|
{
|
||||||
|
return MailParser::parse(File::get(View::make($code)->getPath()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
<?php namespace System\Models;
|
||||||
|
|
||||||
|
use Twig;
|
||||||
|
use File;
|
||||||
|
use View;
|
||||||
|
use Model;
|
||||||
|
use Markdown;
|
||||||
|
use System\Classes\MailManager;
|
||||||
|
use October\Rain\Mail\MailParser;
|
||||||
|
use ApplicationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mail partial
|
||||||
|
*
|
||||||
|
* @package october\system
|
||||||
|
* @author Alexey Bobkov, Samuel Georges
|
||||||
|
*/
|
||||||
|
class MailPartial extends Model
|
||||||
|
{
|
||||||
|
use \October\Rain\Database\Traits\Validation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The database table used by the model.
|
||||||
|
*/
|
||||||
|
protected $table = 'system_mail_partials';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Guarded fields
|
||||||
|
*/
|
||||||
|
protected $guarded = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Fillable fields
|
||||||
|
*/
|
||||||
|
protected $fillable = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Validation rules
|
||||||
|
*/
|
||||||
|
public $rules = [
|
||||||
|
'code' => 'required|unique:system_mail_partials',
|
||||||
|
'name' => 'required',
|
||||||
|
'content_html' => 'required',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loops over each mail layout and ensures the system has a layout,
|
||||||
|
* if the layout does not exist, it will create one.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function createPartials()
|
||||||
|
{
|
||||||
|
$dbPartials = self::lists('code', 'code');
|
||||||
|
|
||||||
|
$definitions = MailManager::instance()->listRegisteredPartials();
|
||||||
|
foreach ($definitions as $code => $path) {
|
||||||
|
if (array_key_exists($code, $dbPartials)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::createPartialFromFile($code, $path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a layout using the contents of a specified file.
|
||||||
|
* @param string $code New Partial code
|
||||||
|
* @param string $viewPath View path
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function createPartialFromFile($code, $viewPath)
|
||||||
|
{
|
||||||
|
$sections = self::getTemplateSections($viewPath);
|
||||||
|
|
||||||
|
$name = array_get($sections, 'settings.name', '???');
|
||||||
|
|
||||||
|
self::create([
|
||||||
|
'name' => $name,
|
||||||
|
'code' => $code,
|
||||||
|
'is_custom' => 0,
|
||||||
|
'content_html' => array_get($sections, 'html'),
|
||||||
|
'content_text' => array_get($sections, 'text')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getTemplateSections($code)
|
||||||
|
{
|
||||||
|
return MailParser::parse(File::get(View::make($code)->getPath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,19 @@ class MailTemplate extends Model
|
||||||
*/
|
*/
|
||||||
protected $table = 'system_mail_templates';
|
protected $table = 'system_mail_templates';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Guarded fields
|
||||||
|
*/
|
||||||
|
protected $guarded = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Fillable fields
|
||||||
|
*/
|
||||||
|
protected $fillable = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Validation rules
|
||||||
|
*/
|
||||||
public $rules = [
|
public $rules = [
|
||||||
'code' => 'required|unique:system_mail_templates',
|
'code' => 'required|unique:system_mail_templates',
|
||||||
'subject' => 'required',
|
'subject' => 'required',
|
||||||
|
|
@ -40,7 +53,7 @@ class MailTemplate extends Model
|
||||||
public static function listAllTemplates()
|
public static function listAllTemplates()
|
||||||
{
|
{
|
||||||
$fileTemplates = (array) MailManager::instance()->listRegisteredTemplates();
|
$fileTemplates = (array) MailManager::instance()->listRegisteredTemplates();
|
||||||
$dbTemplates = (array) self::lists('description', 'code');
|
$dbTemplates = (array) self::lists('code', 'code');
|
||||||
$templates = $fileTemplates + $dbTemplates;
|
$templates = $fileTemplates + $dbTemplates;
|
||||||
ksort($templates);
|
ksort($templates);
|
||||||
return $templates;
|
return $templates;
|
||||||
|
|
@ -52,6 +65,9 @@ class MailTemplate extends Model
|
||||||
*/
|
*/
|
||||||
public static function syncAll()
|
public static function syncAll()
|
||||||
{
|
{
|
||||||
|
MailLayout::createLayouts();
|
||||||
|
MailPartial::createPartials();
|
||||||
|
|
||||||
$templates = MailManager::instance()->listRegisteredTemplates();
|
$templates = MailManager::instance()->listRegisteredTemplates();
|
||||||
$dbTemplates = self::lists('is_custom', 'code');
|
$dbTemplates = self::lists('is_custom', 'code');
|
||||||
$newTemplates = array_diff_key($templates, $dbTemplates);
|
$newTemplates = array_diff_key($templates, $dbTemplates);
|
||||||
|
|
@ -59,8 +75,8 @@ class MailTemplate extends Model
|
||||||
/*
|
/*
|
||||||
* Clean up non-customized templates
|
* Clean up non-customized templates
|
||||||
*/
|
*/
|
||||||
foreach ($dbTemplates as $code => $is_custom) {
|
foreach ($dbTemplates as $code => $isCustom) {
|
||||||
if ($is_custom) {
|
if ($isCustom) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,9 +88,10 @@ class MailTemplate extends Model
|
||||||
/*
|
/*
|
||||||
* Create new templates
|
* Create new templates
|
||||||
*/
|
*/
|
||||||
foreach ($newTemplates as $code => $description) {
|
foreach ($newTemplates as $code) {
|
||||||
$sections = self::getTemplateSections($code);
|
$sections = self::getTemplateSections($code);
|
||||||
$layoutCode = array_get($sections, 'settings.layout', 'default');
|
$layoutCode = array_get($sections, 'settings.layout', 'default');
|
||||||
|
$description = array_get($sections, 'settings.description');
|
||||||
|
|
||||||
$template = self::make();
|
$template = self::make();
|
||||||
$template->code = $code;
|
$template->code = $code;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
# ===================================
|
||||||
|
# Column Definitions
|
||||||
|
# ===================================
|
||||||
|
|
||||||
|
columns:
|
||||||
|
|
||||||
|
name:
|
||||||
|
label: system::lang.mail_templates.name
|
||||||
|
searchable: true
|
||||||
|
|
||||||
|
code:
|
||||||
|
label: system::lang.mail_templates.code
|
||||||
|
searchable: true
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
# ===================================
|
||||||
|
# Field Definitions
|
||||||
|
# ===================================
|
||||||
|
|
||||||
|
fields:
|
||||||
|
|
||||||
|
code:
|
||||||
|
label: system::lang.mail_templates.code
|
||||||
|
comment: system::lang.mail_templates.code_comment
|
||||||
|
span: left
|
||||||
|
context: create
|
||||||
|
|
||||||
|
name@create:
|
||||||
|
label: system::lang.mail_templates.name
|
||||||
|
span: right
|
||||||
|
|
||||||
|
name@update:
|
||||||
|
label: system::lang.mail_templates.name
|
||||||
|
|
||||||
|
secondaryTabs:
|
||||||
|
fields:
|
||||||
|
|
||||||
|
content_html:
|
||||||
|
type: codeeditor
|
||||||
|
size: giant
|
||||||
|
tab: system::lang.mail_templates.content_html
|
||||||
|
language: html
|
||||||
|
stretch: true
|
||||||
|
|
||||||
|
content_text:
|
||||||
|
type: textarea
|
||||||
|
size: giant
|
||||||
|
tab: system::lang.mail_templates.content_text
|
||||||
|
stretch: true
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php namespace System\Twig;
|
||||||
|
|
||||||
|
use Twig_Node;
|
||||||
|
use Twig_Compiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a component node
|
||||||
|
*
|
||||||
|
* @package october\cms
|
||||||
|
* @author Alexey Bobkov, Samuel Georges
|
||||||
|
*/
|
||||||
|
class MailComponentNode extends Twig_Node
|
||||||
|
{
|
||||||
|
public function __construct(Twig_Node $nodes, $paramNames, $body, $lineno, $tag = 'component')
|
||||||
|
{
|
||||||
|
parent::__construct(['nodes' => $nodes, 'body' => $body], ['names' => $paramNames], $lineno, $tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles the node to PHP.
|
||||||
|
*
|
||||||
|
* @param Twig_Compiler $compiler A Twig_Compiler instance
|
||||||
|
*/
|
||||||
|
public function compile(Twig_Compiler $compiler)
|
||||||
|
{
|
||||||
|
$compiler->addDebugInfo($this);
|
||||||
|
|
||||||
|
$compiler->write("\$context['__system_component_params'] = [];\n");
|
||||||
|
|
||||||
|
$compiler
|
||||||
|
->addDebugInfo($this)
|
||||||
|
->write('ob_start();')
|
||||||
|
->subcompile($this->getNode('body'))
|
||||||
|
->write("\$context['__system_component_params']['body'] = ob_get_clean();");
|
||||||
|
|
||||||
|
for ($i = 1; $i < count($this->getNode('nodes')); $i++) {
|
||||||
|
$compiler->write("\$context['__system_component_params']['".$this->getAttribute('names')[$i-1]."'] = ");
|
||||||
|
$compiler->subcompile($this->getNode('nodes')->getNode($i));
|
||||||
|
$compiler->write(";\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
$compiler
|
||||||
|
->write("echo \System\Classes\MailManager::instance()->renderPartial(")
|
||||||
|
->subcompile($this->getNode('nodes')->getNode(0))
|
||||||
|
->write(", \$context['__system_component_params']")
|
||||||
|
->write(");\n")
|
||||||
|
;
|
||||||
|
|
||||||
|
$compiler->write("unset(\$context['__system_component_params']);\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
<?php namespace System\Twig;
|
||||||
|
|
||||||
|
use Twig_Node;
|
||||||
|
use Twig_Token;
|
||||||
|
use Twig_TokenParser;
|
||||||
|
use Twig_Error_Syntax;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parser for the `{% component %}` Twig tag.
|
||||||
|
*
|
||||||
|
* {% component "sidebar" %}
|
||||||
|
*
|
||||||
|
* {% component "sidebar" name='John' %}
|
||||||
|
*
|
||||||
|
* {% component "sidebar" name='John', year=2013 %}
|
||||||
|
*
|
||||||
|
* @package october\system
|
||||||
|
* @author Alexey Bobkov, Samuel Georges
|
||||||
|
*/
|
||||||
|
class MailComponentTokenParser extends Twig_TokenParser
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Parses a token and returns a node.
|
||||||
|
*
|
||||||
|
* @param Twig_Token $token A Twig_Token instance
|
||||||
|
* @return Twig_Node A Twig_Node instance
|
||||||
|
*/
|
||||||
|
public function parse(Twig_Token $token)
|
||||||
|
{
|
||||||
|
$lineno = $token->getLine();
|
||||||
|
$stream = $this->parser->getStream();
|
||||||
|
|
||||||
|
$name = $this->parser->getExpressionParser()->parseExpression();
|
||||||
|
$paramNames = [];
|
||||||
|
$nodes = [$name];
|
||||||
|
|
||||||
|
$end = false;
|
||||||
|
while (!$end) {
|
||||||
|
$current = $stream->next();
|
||||||
|
|
||||||
|
switch ($current->getType()) {
|
||||||
|
case Twig_Token::NAME_TYPE:
|
||||||
|
$paramNames[] = $current->getValue();
|
||||||
|
$stream->expect(Twig_Token::OPERATOR_TYPE, '=');
|
||||||
|
$nodes[] = $this->parser->getExpressionParser()->parseExpression();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Twig_Token::BLOCK_END_TYPE:
|
||||||
|
$end = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Twig_Error_Syntax(
|
||||||
|
sprintf('Invalid syntax in the partial tag. Line %s', $lineno),
|
||||||
|
$stream->getCurrent()->getLine(),
|
||||||
|
$stream->getFilename()
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = $this->parser->subparse([$this, 'decideComponentEnd'], true);
|
||||||
|
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
||||||
|
|
||||||
|
return new MailComponentNode(new Twig_Node($nodes), $paramNames, $body, $token->getLine(), $this->getTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function decideComponentEnd(Twig_Token $token)
|
||||||
|
{
|
||||||
|
return $token->test('endcomponent');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the tag name associated with this token parser.
|
||||||
|
*
|
||||||
|
* @return string The tag name
|
||||||
|
*/
|
||||||
|
public function getTag()
|
||||||
|
{
|
||||||
|
return 'component';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php namespace System\Twig;
|
||||||
|
|
||||||
|
use Twig_Node;
|
||||||
|
use Twig_Compiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a partial node
|
||||||
|
*
|
||||||
|
* @package october\cms
|
||||||
|
* @author Alexey Bobkov, Samuel Georges
|
||||||
|
*/
|
||||||
|
class MailPartialNode extends Twig_Node
|
||||||
|
{
|
||||||
|
public function __construct(Twig_Node $nodes, $paramNames, $lineno, $tag = 'partial')
|
||||||
|
{
|
||||||
|
parent::__construct(['nodes' => $nodes], ['names' => $paramNames], $lineno, $tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles the node to PHP.
|
||||||
|
*
|
||||||
|
* @param Twig_Compiler $compiler A Twig_Compiler instance
|
||||||
|
*/
|
||||||
|
public function compile(Twig_Compiler $compiler)
|
||||||
|
{
|
||||||
|
$compiler->addDebugInfo($this);
|
||||||
|
|
||||||
|
$compiler->write("\$context['__system_partial_params'] = [];\n");
|
||||||
|
|
||||||
|
for ($i = 1; $i < count($this->getNode('nodes')); $i++) {
|
||||||
|
$compiler->write("\$context['__system_partial_params']['".$this->getAttribute('names')[$i-1]."'] = ");
|
||||||
|
$compiler->subcompile($this->getNode('nodes')->getNode($i));
|
||||||
|
$compiler->write(";\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
$compiler
|
||||||
|
->write("echo \$this->env->getExtension('Cms\Twig\Extension')->partialFunction(")
|
||||||
|
->subcompile($this->getNode('nodes')->getNode(0))
|
||||||
|
->write(", \$context['__system_partial_params']")
|
||||||
|
->write(");\n")
|
||||||
|
;
|
||||||
|
|
||||||
|
$compiler->write("unset(\$context['__system_partial_params']);\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?php namespace System\Twig;
|
||||||
|
|
||||||
|
use Twig_Node;
|
||||||
|
use Twig_Token;
|
||||||
|
use Twig_TokenParser;
|
||||||
|
use Twig_Error_Syntax;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parser for the `{% partial %}` Twig tag.
|
||||||
|
*
|
||||||
|
* {% partial "sidebar" %}
|
||||||
|
*
|
||||||
|
* {% partial "sidebar" name='John' %}
|
||||||
|
*
|
||||||
|
* {% partial "sidebar" name='John', year=2013 %}
|
||||||
|
*
|
||||||
|
* @package october\system
|
||||||
|
* @author Alexey Bobkov, Samuel Georges
|
||||||
|
*/
|
||||||
|
class MailPartialTokenParser extends Twig_TokenParser
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Parses a token and returns a node.
|
||||||
|
*
|
||||||
|
* @param Twig_Token $token A Twig_Token instance
|
||||||
|
* @return Twig_Node A Twig_Node instance
|
||||||
|
*/
|
||||||
|
public function parse(Twig_Token $token)
|
||||||
|
{
|
||||||
|
$lineno = $token->getLine();
|
||||||
|
$stream = $this->parser->getStream();
|
||||||
|
|
||||||
|
$name = $this->parser->getExpressionParser()->parseExpression();
|
||||||
|
$paramNames = [];
|
||||||
|
$nodes = [$name];
|
||||||
|
|
||||||
|
$end = false;
|
||||||
|
while (!$end) {
|
||||||
|
$current = $stream->next();
|
||||||
|
|
||||||
|
switch ($current->getType()) {
|
||||||
|
case Twig_Token::NAME_TYPE:
|
||||||
|
$paramNames[] = $current->getValue();
|
||||||
|
$stream->expect(Twig_Token::OPERATOR_TYPE, '=');
|
||||||
|
$nodes[] = $this->parser->getExpressionParser()->parseExpression();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Twig_Token::BLOCK_END_TYPE:
|
||||||
|
$end = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Twig_Error_Syntax(
|
||||||
|
sprintf('Invalid syntax in the partial tag. Line %s', $lineno),
|
||||||
|
$stream->getCurrent()->getLine(),
|
||||||
|
$stream->getFilename()
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MailPartialNode(new Twig_Node($nodes), $paramNames, $token->getLine(), $this->getTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the tag name associated with this token parser.
|
||||||
|
*
|
||||||
|
* @return string The tag name
|
||||||
|
*/
|
||||||
|
public function getTag()
|
||||||
|
{
|
||||||
|
return 'partial';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
name = "Button"
|
||||||
|
==
|
||||||
|
{{ body|raw }}
|
||||||
|
==
|
||||||
|
<button>{{ body|raw }}</button>
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
name = "Default layout"
|
||||||
|
==
|
||||||
|
{{ content|raw }}
|
||||||
|
==
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style type="text/css" media="screen">
|
||||||
|
{{ css|raw }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{{ content|raw }}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
name = "System layout"
|
||||||
|
==
|
||||||
|
{{ content|raw }}
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
This is an automatic message. Please do not reply to it.
|
||||||
|
==
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style type="text/css" media="screen">
|
||||||
|
{{ css|raw }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{{ content|raw }}
|
||||||
|
<hr />
|
||||||
|
<p>This is an automatic message. Please do not reply to it.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
name = "Table"
|
||||||
|
==
|
||||||
|
{{ body|raw }}
|
||||||
|
==
|
||||||
|
<div class="table">{{ body|raw }}</div>
|
||||||
Loading…
Reference in New Issue