Change to mail partial syntax

This commit is contained in:
Samuel Georges 2017-07-26 17:48:00 +10:00
parent f1ac7eea3b
commit 18b9253bcb
15 changed files with 73 additions and 171 deletions

View File

@ -6,15 +6,15 @@ Hi {{ name }}
A user account has been created for you on **{{ appName }}**.
{% component 'panel' %}
{% partial 'panel' body %}
- Login: `{{ login ?: 'sample' }}`
- Password: `{{ password ?: '********' }}`
{% endcomponent %}
{% endpartial %}
You can use the following link to sign in:
{% component 'button' url=link %}
{% partial 'button' url=link body %}
Sign in to admin area
{% endcomponent %}
{% endpartial %}
After signing in you should change your password by clicking your name on the top right corner of the administration area.

View File

@ -8,6 +8,6 @@ Somebody has requested a password reset for your account, if this was not you, p
You can use the following link to restore your password:
{% component 'button' url=link type='positive' %}
{% partial 'button' url=link type='positive' body %}
Restore password
{% endcomponent %}
{% endpartial %}

View File

@ -49,7 +49,7 @@ class ComponentTokenParser extends Twig_TokenParser
throw new Twig_Error_Syntax(
sprintf('Invalid syntax in the component tag. Line %s', $lineno),
$stream->getCurrent()->getLine(),
$stream->getFilename()
$stream->getSourceContext()
);
break;
}

View File

@ -53,7 +53,7 @@ class ContentTokenParser extends Twig_TokenParser
throw new Twig_Error_Syntax(
sprintf('Invalid syntax in the content tag. Line %s', $lineno),
$stream->getCurrent()->getLine(),
$stream->getFilename()
$stream->getSourceContext()
);
break;
}

View File

@ -53,7 +53,7 @@ class PartialTokenParser extends Twig_TokenParser
throw new Twig_Error_Syntax(
sprintf('Invalid syntax in the partial tag. Line %s', $lineno),
$stream->getCurrent()->getLine(),
$stream->getFilename()
$stream->getSourceContext()
);
break;
}

View File

@ -14,9 +14,11 @@ class PlaceholderNode extends Twig_Node
public function __construct($name, $paramValues, $body, $lineno, $tag = 'placeholder')
{
$nodes = [];
if ($body) {
$nodes['default'] = $body;
}
$attributes = $paramValues;
$attributes['name'] = $name;

View File

@ -75,9 +75,9 @@ class PlaceholderTokenParser extends Twig_TokenParser
default:
throw new Twig_Error_Syntax(
sprintf('Invalid syntax in the placeholder tag. Line %s', $lineno),
sprintf('Invalid syntax in the placeholder tag. Line %s', $stream->getCurrent()->getLine()),
$stream->getCurrent()->getLine(),
$stream->getFilename()
$stream->getSourceContext()
);
break;
}

View File

@ -9,7 +9,6 @@ use System\Helpers\View as ViewHelper;
use System\Classes\PluginManager;
use System\Classes\MarkupManager;
use System\Twig\MailPartialTokenParser;
use System\Twig\MailComponentTokenParser;
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;
/**
@ -206,6 +205,7 @@ class MailManager
public function renderPartial($code, array $params = [])
{
traceLog($params);
if (!$partial = MailPartial::findOrMakePartial($code)) {
return '<!-- Missing partial: '.$code.' -->';
}
@ -257,8 +257,7 @@ class MailManager
$markupManager = MarkupManager::instance();
$markupManager->beginTransaction();
$markupManager->registerTokenParsers([
new MailPartialTokenParser,
new MailComponentTokenParser
new MailPartialTokenParser
]);
}

View File

@ -5,43 +5,43 @@ Cumque dicta <a>doloremque eaque</a>, enim error laboriosam pariatur possimus te
## Heading 2
{% component 'table' %}
{% partial 'table' body %}
| Item | Description | Price |
|:------------- |:-------------:| --------:|
| Item 1 | Centered | $10 |
| Item 2 | Right-Aligned | $20 |
{% endcomponent %}
{% endpartial %}
### Heading 3
This is a paragraph filled with Lorem Ipsum and a link.
Cumque dicta <a>doloremque eaque</a>, enim error laboriosam pariatur possimus tenetur veritatis voluptas.
{% component 'button' url='javascript:;' %}
{% partial 'button' url='javascript:;' body %}
Primary button
{% endcomponent %}
{% endpartial %}
{% component 'button' type='positive' url='javascript:;' %}
{% partial 'button' type='positive' url='javascript:;' body %}
Positive button
{% endcomponent %}
{% endpartial %}
{% component 'button' type='negative' url='javascript:;' %}
{% partial 'button' type='negative' url='javascript:;' body %}
Negative button
{% endcomponent %}
{% endpartial %}
{% component 'panel' %}
{% partial 'panel' body %}
How awesome is this panel?
{% endcomponent %}
{% endpartial %}
Some more text
{% component 'promotion' %}
{% partial 'promotion' body %}
Coupon code: OCTOBER
{% endcomponent %}
{% endpartial %}
Thanks,
{{ appName }}
{% component 'subcopy' %}
{% partial 'subcopy' body %}
This is the subcopy of the email
{% endcomponent %}
{% endpartial %}

View File

@ -1,51 +0,0 @@
<?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");
}
}

View File

@ -1,82 +0,0 @@
<?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';
}
}

View File

@ -11,9 +11,15 @@ use Twig_Compiler;
*/
class MailPartialNode extends Twig_Node
{
public function __construct(Twig_Node $nodes, $paramNames, $lineno, $tag = 'partial')
public function __construct(Twig_Node $nodes, $paramNames, $body, $lineno, $tag = 'partial')
{
parent::__construct(['nodes' => $nodes], ['names' => $paramNames], $lineno, $tag);
$nodes = ['nodes' => $nodes];
if ($body) {
$nodes['body'] = $body;
}
parent::__construct($nodes, ['names' => $paramNames], $lineno, $tag);
}
/**
@ -27,6 +33,14 @@ class MailPartialNode extends Twig_Node
$compiler->write("\$context['__system_partial_params'] = [];\n");
if ($this->hasNode('body')) {
$compiler
->addDebugInfo($this)
->write('ob_start();')
->subcompile($this->getNode('body'))
->write("\$context['__system_partial_params']['body'] = ob_get_clean();");
}
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));

View File

@ -33,11 +33,21 @@ class MailPartialTokenParser extends Twig_TokenParser
$name = $this->parser->getExpressionParser()->parseExpression();
$paramNames = [];
$nodes = [$name];
$hasBody = false;
$body = null;
$end = false;
while (!$end) {
$current = $stream->next();
if (
$current->test(Twig_Token::NAME_TYPE, 'body') &&
!$stream->test(Twig_Token::OPERATOR_TYPE, '=')
) {
$hasBody = true;
$current = $stream->next();
}
switch ($current->getType()) {
case Twig_Token::NAME_TYPE:
$paramNames[] = $current->getValue();
@ -53,13 +63,23 @@ class MailPartialTokenParser extends Twig_TokenParser
throw new Twig_Error_Syntax(
sprintf('Invalid syntax in the partial tag. Line %s', $lineno),
$stream->getCurrent()->getLine(),
$stream->getFilename()
$stream->getSourceContext()
);
break;
}
}
return new MailPartialNode(new Twig_Node($nodes), $paramNames, $token->getLine(), $this->getTag());
if ($hasBody) {
$body = $this->parser->subparse([$this, 'decidePartialEnd'], true);
$stream->expect(Twig_Token::BLOCK_END_TYPE);
}
return new MailPartialNode(new Twig_Node($nodes), $paramNames, $body, $token->getLine(), $this->getTag());
}
public function decidePartialEnd(Twig_Token $token)
{
return $token->test('endpartial');
}
/**

View File

@ -17,9 +17,9 @@ name = "Default layout"
<table class="wrapper layout-default" width="100%" cellpadding="0" cellspacing="0">
<!-- Header -->
{% component 'header' %}
{% partial 'header' body %}
{{ subject }}
{% endcomponent %}
{% endpartial %}
<tr>
<td align="center">
@ -42,9 +42,9 @@ name = "Default layout"
</tr>
<!-- Footer -->
{% component 'footer' %}
{% partial 'footer' body %}
&copy; {{ "now"|date("Y") }} {{ appName }}. All rights reserved.
{% endcomponent %}
{% endpartial %}
</table>

View File

@ -32,9 +32,9 @@ This is an automatic message. Please do not reply to it.
{{ content|raw }}
<!-- Subcopy -->
{% component 'subcopy' %}
{% partial 'subcopy' body %}
**This is an automatic message. Please do not reply to it.**
{% endcomponent %}
{% endpartial %}
</td>
</tr>
</table>