Skip to content

Instantly share code, notes, and snippets.

@daniel-ifrim
Last active April 10, 2022 15:37
Show Gist options
  • Save daniel-ifrim/74a0310c6acd9f664381c895bf0fcb35 to your computer and use it in GitHub Desktop.
Save daniel-ifrim/74a0310c6acd9f664381c895bf0fcb35 to your computer and use it in GitHub Desktop.
Extend Magento 2 templates. Add operators equal, greater than, lower than and other. Add 2 more if.

Usage:

{{outer_if myVar!=="ipsum"}}
    {{if customer.getGroupId()==2}}
        Public text
    {{else}}
        {{inner_if order.getTotal()>1000}}
            Good deal
        {{inner_else}}
            Marketing
        {{/inner_if}}
    {{/if}}
{{outer_else}}
    nothing
{{outer_if}}
<!-- app/code/MyNamespace/MyModule/etc/di.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Framework\Filter\Template" type="MyNamespace\MyModule\Framework\Filter\Template" />
<!-- TO DO: is bellow this optional? Email Filter class extends Template Filter. Will Email Filter inherit our rewritten class without bellow prefference ? -->
<preference for="Magento\Email\Model\Template\Filter" type="MyNamespace\MyModule\Model\Template\Filter" />
</config>
<?php
// app/code/MyNamespace/MyModule/Model/Template/Filter.php
namespace MyModule\MyNamespace\Model\Template;
/**
* Class Filter
*
* @note Contains redundat code with \LS\EmailExtend\Framework\Filter\Template
* @see \MyModule\MyNamespace\Framework\Filter\Template
* @see \Magento\Email\Model\Template\Filter
* @see \Magento\Framework\Filter\Template
*/
class Filter extends \Magento\Email\Model\Template\Filter
{
const CONSTRUCTION_IF_CONDITION_OPERANDS = "/([^\s=><!]+)\s*((?:>=)|(?:<=)|\>|<|(?:===)|(?:!==)|(?:==)|(?:!=)){1}\s*(.*+)/si";
/**#@+
* Construction logic regular expression
*/
const CONSTRUCTION_OUTER_IF_PATTERN = '/{{outer_if\s*(.*?)}}(.*?)({{outer_else}}(.*?))?{{\\/outer_if\s*}}/si';
const CONSTRUCTION_INNER_IF_PATTERN = '/{{inner_if\s*(.*?)}}(.*?)({{inner_else}}(.*?))?{{\\/inner_if\s*}}/si';
const CONSTRUCTION_DEPEND_PATTERN = '/{{depend\s*(.*?)}}(.*?){{\\/depend\s*}}/si';
//const CONSTRUCTION_IF_PATTERN = '/{{if\s*(.*?)}}(.*?)({{else}}(.*?))?{{\\/if\s*}}/si';
/**
* Add inner_if, outer_if and operands inside if(s) statements from function ifExtendedDirective
*
* Filter the string as template.
*
* @param string $value
* @return string
* @throws \Exception
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function filter($value)
{
// "outer_if" operand should be first
foreach ([
self::CONSTRUCTION_OUTER_IF_PATTERN => 'ifExtendedDirective',
] as $pattern => $directive) {
if (preg_match_all($pattern, $value, $constructions, PREG_SET_ORDER)) {
foreach($constructions as $construction) {
$replacedValue = '';
$expression = null;
if ($pattern == self::CONSTRUCTION_OUTER_IF_PATTERN)
if (!preg_match(self::CONSTRUCTION_IF_CONDITION_OPERANDS, $construction[1], $expression))
continue;
$callback = [$this, $directive];
if (!is_callable($callback)) {
continue;
}
try {
$replacedValue = call_user_func($callback, $construction, $expression);
} catch (\Exception $e) {
throw $e;
}
$value = str_replace($construction[0], $replacedValue, $value);
}
}
}
// "inner_if" operand should be second
foreach ([
self::CONSTRUCTION_INNER_IF_PATTERN => 'ifExtendedDirective',
] as $pattern => $directive) {
if (preg_match_all($pattern, $value, $constructions, PREG_SET_ORDER)) {
foreach($constructions as $construction) {
$replacedValue = '';
$expression = null;
if ($pattern == self::CONSTRUCTION_INNER_IF_PATTERN)
if (!preg_match(self::CONSTRUCTION_IF_CONDITION_OPERANDS, $construction[1], $expression))
continue;
$callback = [$this, $directive];
if (!is_callable($callback)) {
continue;
}
try {
$replacedValue = call_user_func($callback, $construction, $expression);
} catch (\Exception $e) {
throw $e;
}
$value = str_replace($construction[0], $replacedValue, $value);
}
}
}
// "depend", "if", and "template" directives should be third
foreach ([
self::CONSTRUCTION_DEPEND_PATTERN => 'dependDirective',
self::CONSTRUCTION_IF_PATTERN => 'ifDirective',
self::CONSTRUCTION_TEMPLATE_PATTERN => 'templateDirective',
] as $pattern => $directive) {
if (preg_match_all($pattern, $value, $constructions, PREG_SET_ORDER)) {
foreach ($constructions as $construction) {
$replacedValue = '';
$expression = null;
if ($pattern == self::CONSTRUCTION_IF_PATTERN) {
if (preg_match(self::CONSTRUCTION_IF_CONDITION_OPERANDS, $construction[1], $expression)) {
$directive = "ifExtendedDirective";
}
}
$callback = [$this, $directive];
if (!is_callable($callback)) {
continue;
}
try {
if ($expression != null) {
$replacedValue = call_user_func($callback, $construction, $expression);
} else {
$replacedValue = call_user_func($callback, $construction);
}
} catch (\Exception $e) {
throw $e;
}
$value = str_replace($construction[0], $replacedValue, $value);
}
}
}
// Magento 2.3+ compatibility
if (method_exists($this,'filterFor')) {
$value = $this->filterFor($value);
}
if (preg_match_all(self::CONSTRUCTION_PATTERN, $value, $constructions, PREG_SET_ORDER)) {
foreach ($constructions as $construction) {
$replacedValue = '';
$callback = [$this, $construction[1] . 'Directive'];
if (!is_callable($callback)) {
continue;
}
try {
$replacedValue = call_user_func($callback, $construction);
} catch (\Exception $e) {
throw $e;
}
$value = str_replace($construction[0], $replacedValue, $value);
}
}
$value = $this->afterFilter($value);
return $value;
}
/**
* Extend if directive
*
* @param array $construction
* @param array $expression
* @return string
*/
public function ifExtendedDirective($construction, $expression)
{
if (count($this->templateVars) == 0) {
return $construction[0];
}
$expression[3] = trim($expression[3], "'");
$expression[3] = trim($expression[3], "\"");
switch ($expression[2]) {
case '>=':
$condition = ($this->getVariable($expression[1], '') >= $expression[3]);
break;
case '<=':
$condition = ($this->getVariable($expression[1], '') <= $expression[3]);
break;
case '>':
$condition = ($this->getVariable($expression[1], '') > $expression[3]);
break;
case '<':
$condition = ($this->getVariable($expression[1], '') < $expression[3]);
break;
case '===':
$condition = ($this->getVariable($expression[1], '') === $expression[3]);
break;
case '!==':
$condition = ($this->getVariable($expression[1], '') !== $expression[3]);
break;
case '==':
$condition = ($this->getVariable($expression[1], '') == $expression[3]);
break;
case '!=':
$condition = ($this->getVariable($expression[1], '') != $expression[3]);
break;
default:
$condition = false;
}
if ($condition) {
return $construction[2];
} else {
if (isset($construction[3]) && isset($construction[4])) {
return $construction[4];
} else {
return '';
}
}
}
}
<!-- app/code/MyNamespace/MyModule/etc/module.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="MyNamespace_MyModule" setup_version="1.0.0">
<sequence>
<module name="Magento_Email"/>
</sequence>
</module>
</config>
<?php
// app/code/MyNamespace/MyModule/registration.php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'MyNamespace_MyModule',
__DIR__
);
<?php
// app/code/MyNamespace/MyModule/Framework/Filter/Template.php
namespace MyNamespace\MyModule\Framework\Filter;
/**
* Class Template
*/
class Template extends \Magento\Framework\Filter\Template
{
const CONSTRUCTION_IF_CONDITION_OPERANDS = "/([^\s=><!]+)\s*((?:>=)|(?:<=)|\>|<|(?:===)|(?:!==)|(?:==)|(?:!=)){1}\s*(.*+)/si";
/**#@+
* Construction logic regular expression
*/
const CONSTRUCTION_OUTER_IF_PATTERN = '/{{outer_if\s*(.*?)}}(.*?)({{outer_else}}(.*?))?{{\\/outer_if\s*}}/si';
const CONSTRUCTION_INNER_IF_PATTERN = '/{{inner_if\s*(.*?)}}(.*?)({{inner_else}}(.*?))?{{\\/inner_if\s*}}/si';
const CONSTRUCTION_DEPEND_PATTERN = '/{{depend\s*(.*?)}}(.*?){{\\/depend\s*}}/si';
//const CONSTRUCTION_IF_PATTERN = '/{{if\s*(.*?)}}(.*?)({{else}}(.*?))?{{\\/if\s*}}/si';
/**
* Add inner_if, outer_if and operands inside if(s) statements from function ifExtendedDirective
*
* Filter the string as template.
*
* @param string $value
* @return string
* @throws \Exception
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function filter($value)
{
// "outer_if" operand should be first
foreach ([
self::CONSTRUCTION_OUTER_IF_PATTERN => 'ifExtendedDirective',
] as $pattern => $directive) {
if (preg_match_all($pattern, $value, $constructions, PREG_SET_ORDER)) {
foreach($constructions as $construction) {
$replacedValue = '';
$expression = null;
if ($pattern == self::CONSTRUCTION_OUTER_IF_PATTERN)
if (!preg_match(self::CONSTRUCTION_IF_CONDITION_OPERANDS, $construction[1], $expression))
continue;
$callback = [$this, $directive];
if (!is_callable($callback)) {
continue;
}
try {
$replacedValue = call_user_func($callback, $construction, $expression);
} catch (\Exception $e) {
throw $e;
}
$value = str_replace($construction[0], $replacedValue, $value);
}
}
}
// "inner_if" operand should be second
foreach ([
self::CONSTRUCTION_INNER_IF_PATTERN => 'ifExtendedDirective',
] as $pattern => $directive) {
if (preg_match_all($pattern, $value, $constructions, PREG_SET_ORDER)) {
foreach($constructions as $construction) {
$replacedValue = '';
$expression = null;
if ($pattern == self::CONSTRUCTION_INNER_IF_PATTERN)
if (!preg_match(self::CONSTRUCTION_IF_CONDITION_OPERANDS, $construction[1], $expression))
continue;
$callback = [$this, $directive];
if (!is_callable($callback)) {
continue;
}
try {
$replacedValue = call_user_func($callback, $construction, $expression);
} catch (\Exception $e) {
throw $e;
}
$value = str_replace($construction[0], $replacedValue, $value);
}
}
}
// "depend", "if", and "template" directives should be third
foreach ([
self::CONSTRUCTION_DEPEND_PATTERN => 'dependDirective',
self::CONSTRUCTION_IF_PATTERN => 'ifDirective',
self::CONSTRUCTION_TEMPLATE_PATTERN => 'templateDirective',
] as $pattern => $directive) {
if (preg_match_all($pattern, $value, $constructions, PREG_SET_ORDER)) {
foreach ($constructions as $construction) {
$replacedValue = '';
$expression = null;
if ($pattern == self::CONSTRUCTION_IF_PATTERN) {
if (preg_match(self::CONSTRUCTION_IF_CONDITION_OPERANDS, $construction[1], $expression)) {
$directive = "ifExtendedDirective";
}
}
$callback = [$this, $directive];
if (!is_callable($callback)) {
continue;
}
try {
if ($expression != null) {
$replacedValue = call_user_func($callback, $construction, $expression);
} else {
$replacedValue = call_user_func($callback, $construction);
}
} catch (\Exception $e) {
throw $e;
}
$value = str_replace($construction[0], $replacedValue, $value);
}
}
}
// Magento 2.3+ compatibility
if (method_exists($this,'filterFor')) {
$value = $this->filterFor($value);
}
if (preg_match_all(self::CONSTRUCTION_PATTERN, $value, $constructions, PREG_SET_ORDER)) {
foreach ($constructions as $construction) {
$replacedValue = '';
$callback = [$this, $construction[1] . 'Directive'];
if (!is_callable($callback)) {
continue;
}
try {
$replacedValue = call_user_func($callback, $construction);
} catch (\Exception $e) {
throw $e;
}
$value = str_replace($construction[0], $replacedValue, $value);
}
}
$value = $this->afterFilter($value);
return $value;
}
/**
* Extend if directive
*
* @param array $construction
* @param array $expression
* @return string
*/
public function ifExtendedDirective($construction, $expression)
{
if (count($this->templateVars) == 0) {
return $construction[0];
}
$expression[3] = trim($expression[3], "'");
$expression[3] = trim($expression[3], "\"");
switch ($expression[2]) {
case '>=':
$condition = ($this->getVariable($expression[1], '') >= $expression[3]);
break;
case '<=':
$condition = ($this->getVariable($expression[1], '') <= $expression[3]);
break;
case '>':
$condition = ($this->getVariable($expression[1], '') > $expression[3]);
break;
case '<':
$condition = ($this->getVariable($expression[1], '') < $expression[3]);
break;
case '===':
$condition = ($this->getVariable($expression[1], '') === $expression[3]);
break;
case '!==':
$condition = ($this->getVariable($expression[1], '') !== $expression[3]);
break;
case '==':
$condition = ($this->getVariable($expression[1], '') == $expression[3]);
break;
case '!=':
$condition = ($this->getVariable($expression[1], '') != $expression[3]);
break;
default:
$condition = false;
}
if ($condition) {
return $construction[2];
} else {
if (isset($construction[3]) && isset($construction[4])) {
return $construction[4];
} else {
return '';
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment