Documented support for is in, added support for is not in. (#955)

* Documented support for `is in`, added support for `is not in`.
Fixes #937
* minor docs improvement
This commit is contained in:
Simon Wisselink
2024-03-25 13:54:02 +01:00
committed by GitHub
parent 58348c38ef
commit 1da30e76e8
9 changed files with 944 additions and 900 deletions

2
changelog/937.md Normal file
View File

@@ -0,0 +1,2 @@
- Documented support for `{if $element is in $array}` syntax [#937](https://github.com/smarty-php/smarty/issues/937)
- Added support for `{if $element is not in $array}` syntax [#937](https://github.com/smarty-php/smarty/issues/937)

View File

@@ -27,6 +27,30 @@ Various basic operators can be applied directly to variable values.
> complex, it may be a good idea to move the bits that do not deal > complex, it may be a good idea to move the bits that do not deal
> explicitly with presentation to PHP by way of plugins or modifiers. > explicitly with presentation to PHP by way of plugins or modifiers.
## List
The following is a list of recognized operators, which must be
separated from surrounding elements by spaces. Note that items listed in
\[brackets\] are optional. PHP equivalents are shown where applicable.
| Operator | Alternates | Syntax Example | Meaning | PHP Equivalent |
|--------------------|------------|----------------------|--------------------------------|--------------------|
| == | eq | $a eq $b | equals | == |
| != | ne, neq | $a neq $b | not equals | != |
| > | gt | $a gt $b | greater than | > |
| < | lt | $a lt $b | less than | < |
| >= | gte, ge | $a ge $b | greater than or equal | >= |
| <= | lte, le | $a le $b | less than or equal | <= |
| === | | $a === 0 | check for identity | === |
| ! | not | not $a | negation (unary) | ! |
| % | mod | $a mod $b | modulo | % |
| is \[not\] div by | | $a is not div by 4 | divisible by | $a % $b == 0 |
| is \[not\] even | | $a is not even | \[not\] an even number (unary) | $a % 2 == 0 |
| is \[not\] even by | | $a is not even by $b | grouping level \[not\] even | ($a / $b) % 2 == 0 |
| is \[not\] odd | | $a is not odd | \[not\] an odd number (unary) | $a % 2 != 0 |
| is \[not\] odd by | | $a is not odd by $b | \[not\] an odd grouping | ($a / $b) % 2 != 0 |
| is in | | $a is in $b | exists in array | in_array($a, $b) |
| is \[not\] in | | $a is not in $b | does not exist in array | !in_array($a, $b) |
## Ternary ## Ternary
You can use the `?:` (or ternary) operator to test one expression and present the value You can use the `?:` (or ternary) operator to test one expression and present the value
of the second or third expression, based on the result of the test. of the second or third expression, based on the result of the test.

View File

@@ -3,32 +3,8 @@
`{if}` statements in Smarty have much the same flexibility as PHP `{if}` statements in Smarty have much the same flexibility as PHP
[if](https://www.php.net/if) statements, with a few added features for the [if](https://www.php.net/if) statements, with a few added features for the
template engine. Every `{if}` must be paired with a matching `{/if}`. template engine. Every `{if}` must be paired with a matching `{/if}`.
`{else}` and `{elseif}` are also permitted. All PHP conditionals and `{else}` and `{elseif}` are also permitted. All [operators](../language-basic-syntax/language-syntax-operators.md) are recognized, such as *==*,
functions are recognized, such as *\|\|*, *or*, *&&*, *and*, *\|\|*, *or*, *&&*, *and*, etc and you can use modifiers as functions, such as *is_array()*.
*is_array()*, etc.
The following is a list of recognized qualifiers, which must be
separated from surrounding elements by spaces. Note that items listed in
\[brackets\] are optional. PHP equivalents are shown where applicable.
## Qualifiers
| Qualifier | Alternates | Syntax Example | Meaning | PHP Equivalent |
|--------------------|------------|----------------------|--------------------------------|--------------------|
| == | eq | $a eq $b | equals | == |
| != | ne, neq | $a neq $b | not equals | != |
| > | gt | $a gt $b | greater than | > |
| < | lt | $a lt $b | less than | < |
| >= | gte, ge | $a ge $b | greater than or equal | >= |
| <= | lte, le | $a le $b | less than or equal | <= |
| === | | $a === 0 | check for identity | === |
| ! | not | not $a | negation (unary) | ! |
| % | mod | $a mod $b | modulo | % |
| is \[not\] div by | | $a is not div by 4 | divisible by | $a % $b == 0 |
| is \[not\] even | | $a is not even | \[not\] an even number (unary) | $a % 2 == 0 |
| is \[not\] even by | | $a is not even by $b | grouping level \[not\] even | ($a / $b) % 2 == 0 |
| is \[not\] odd | | $a is not odd | \[not\] an odd number (unary) | $a % 2 != 0 |
| is \[not\] odd by | | $a is not odd by $b | \[not\] an odd grouping | ($a / $b) % 2 != 0 |
## Examples ## Examples
```smarty ```smarty

View File

@@ -3,31 +3,8 @@
`{while}` loops in Smarty have much the same flexibility as PHP `{while}` loops in Smarty have much the same flexibility as PHP
[while](https://www.php.net/while) statements, with a few added features for [while](https://www.php.net/while) statements, with a few added features for
the template engine. Every `{while}` must be paired with a matching the template engine. Every `{while}` must be paired with a matching
`{/while}`. All PHP conditionals and functions are recognized, such as `{/while}`. All [operators](../language-basic-syntax/language-syntax-operators.md) are recognized, such as *==*,
*\|\|*, *or*, *&&*, *and*, *is_array()*, etc. *\|\|*, *or*, *&&*, *and*, etc and you can use modifiers as functions, such as *is_array()*.
The following is a list of recognized qualifiers, which must be
separated from surrounding elements by spaces. Note that items listed in
\[brackets\] are optional. PHP equivalents are shown where applicable.
## Qualifiers
| Qualifier | Alternates | Syntax Example | Meaning | PHP Equivalent |
|--------------------|------------|----------------------|--------------------------------|--------------------|
| == | eq | $a eq $b | equals | == |
| != | ne, neq | $a neq $b | not equals | != |
| > | gt | $a gt $b | greater than | > |
| < | lt | $a lt $b | less than | < |
| >= | gte, ge | $a ge $b | greater than or equal | >= |
| <= | lte, le | $a le $b | less than or equal | <= |
| === | | $a === 0 | check for identity | === |
| ! | not | not $a | negation (unary) | ! |
| % | mod | $a mod $b | modulo | % |
| is \[not\] div by | | $a is not div by 4 | divisible by | $a % $b == 0 |
| is \[not\] even | | $a is not even | \[not\] an even number (unary) | $a % 2 == 0 |
| is \[not\] even by | | $a is not even by $b | grouping level \[not\] even | ($a / $b) % 2 == 0 |
| is \[not\] odd | | $a is not odd | \[not\] an odd number (unary) | $a % 2 != 0 |
| is \[not\] odd by | | $a is not odd by $b | \[not\] an odd grouping | ($a / $b) % 2 != 0 |
## Examples ## Examples
```smarty ```smarty

View File

@@ -567,7 +567,7 @@ class TemplateLexer
public function yylex3() public function yylex3()
{ {
if (!isset($this->yy_global_pattern3)) { if (!isset($this->yy_global_pattern3)) {
$this->yy_global_pattern3 = $this->replace("/\G(\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal)|\G([\"])|\G('[^'\\\\]*(?:\\\\.[^'\\\\]*)*')|\G([$][0-9]*[a-zA-Z_]\\w*)|\G([$])|\G(\\s+is\\s+in\\s+)|\G(\\s+as\\s+)|\G(\\s+to\\s+)|\G(\\s+step\\s+)|\G(\\s+instanceof\\s+)|\G(\\s*([!=][=]{1,2}|[<][=>]?|[>][=]?|[&|]{2})\\s*)|\G(\\s+(eq|ne|neq|gt|ge|gte|lt|le|lte|mod|and|or|xor)\\s+)|\G(\\s+is\\s+(not\\s+)?(odd|even|div)\\s+by\\s+)|\G(\\s+is\\s+(not\\s+)?(odd|even))|\G([!]\\s*|not\\s+)|\G([(](int(eger)?|bool(ean)?|float|double|real|string|binary|array|object)[)]\\s*)|\G(\\s*[(]\\s*)|\G(\\s*[)])|\G(\\[\\s*)|\G(\\s*\\])|\G(\\s*[-][>]\\s*)|\G(\\s*[=][>]\\s*)|\G(\\s*[=]\\s*)|\G(([+]|[-]){2})|\G(\\s*([+]|[-])\\s*)|\G(\\s*([*]{1,2}|[%\/^&]|[<>]{2})\\s*)|\G([@])|\G(array\\s*[(]\\s*)|\G([#])|\G(\\s+[0-9]*[a-zA-Z_][a-zA-Z0-9_\-:]*\\s*[=]\\s*)|\G(([0-9]*[a-zA-Z_]\\w*)?(\\\\[0-9]*[a-zA-Z_]\\w*)+)|\G([0-9]*[a-zA-Z_]\\w*)|\G(\\d+)|\G([`])|\G([|][@]?)|\G([.])|\G(\\s*[,]\\s*)|\G(\\s*[;]\\s*)|\G([:]{2})|\G(\\s*[:]\\s*)|\G(\\s*[?]\\s*)|\G(0[xX][0-9a-fA-F]+)|\G(\\s+)|\G([\S\s])/isS"); $this->yy_global_pattern3 = $this->replace("/\G(\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal)|\G([\"])|\G('[^'\\\\]*(?:\\\\.[^'\\\\]*)*')|\G([$][0-9]*[a-zA-Z_]\\w*)|\G([$])|\G(\\s+is\\s+(not\\s+)?in\\s+)|\G(\\s+as\\s+)|\G(\\s+to\\s+)|\G(\\s+step\\s+)|\G(\\s+instanceof\\s+)|\G(\\s*([!=][=]{1,2}|[<][=>]?|[>][=]?|[&|]{2})\\s*)|\G(\\s+(eq|ne|neq|gt|ge|gte|lt|le|lte|mod|and|or|xor)\\s+)|\G(\\s+is\\s+(not\\s+)?(odd|even|div)\\s+by\\s+)|\G(\\s+is\\s+(not\\s+)?(odd|even))|\G([!]\\s*|not\\s+)|\G([(](int(eger)?|bool(ean)?|float|double|real|string|binary|array|object)[)]\\s*)|\G(\\s*[(]\\s*)|\G(\\s*[)])|\G(\\[\\s*)|\G(\\s*\\])|\G(\\s*[-][>]\\s*)|\G(\\s*[=][>]\\s*)|\G(\\s*[=]\\s*)|\G(([+]|[-]){2})|\G(\\s*([+]|[-])\\s*)|\G(\\s*([*]{1,2}|[%\/^&]|[<>]{2})\\s*)|\G([@])|\G(array\\s*[(]\\s*)|\G([#])|\G(\\s+[0-9]*[a-zA-Z_][a-zA-Z0-9_\-:]*\\s*[=]\\s*)|\G(([0-9]*[a-zA-Z_]\\w*)?(\\\\[0-9]*[a-zA-Z_]\\w*)+)|\G([0-9]*[a-zA-Z_]\\w*)|\G(\\d+)|\G([`])|\G([|][@]?)|\G([.])|\G(\\s*[,]\\s*)|\G(\\s*[;]\\s*)|\G([:]{2})|\G(\\s*[:]\\s*)|\G(\\s*[?]\\s*)|\G(0[xX][0-9a-fA-F]+)|\G(\\s+)|\G([\S\s])/isS");
} }
if (!isset($this->dataLength)) { if (!isset($this->dataLength)) {
$this->dataLength = strlen($this->data); $this->dataLength = strlen($this->data);
@@ -659,122 +659,122 @@ class TemplateLexer
$this->token = \Smarty\Parser\TemplateParser::TP_ISIN; $this->token = \Smarty\Parser\TemplateParser::TP_ISIN;
} }
public function yy_r3_9() public function yy_r3_10()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_AS; $this->token = \Smarty\Parser\TemplateParser::TP_AS;
} }
public function yy_r3_10() public function yy_r3_11()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_TO; $this->token = \Smarty\Parser\TemplateParser::TP_TO;
} }
public function yy_r3_11() public function yy_r3_12()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_STEP; $this->token = \Smarty\Parser\TemplateParser::TP_STEP;
} }
public function yy_r3_12() public function yy_r3_13()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_INSTANCEOF; $this->token = \Smarty\Parser\TemplateParser::TP_INSTANCEOF;
} }
public function yy_r3_13() public function yy_r3_14()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_LOGOP; $this->token = \Smarty\Parser\TemplateParser::TP_LOGOP;
} }
public function yy_r3_15() public function yy_r3_16()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_SLOGOP; $this->token = \Smarty\Parser\TemplateParser::TP_SLOGOP;
} }
public function yy_r3_17() public function yy_r3_18()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_TLOGOP; $this->token = \Smarty\Parser\TemplateParser::TP_TLOGOP;
} }
public function yy_r3_20() public function yy_r3_21()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_SINGLECOND; $this->token = \Smarty\Parser\TemplateParser::TP_SINGLECOND;
} }
public function yy_r3_23() public function yy_r3_24()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_NOT; $this->token = \Smarty\Parser\TemplateParser::TP_NOT;
} }
public function yy_r3_24() public function yy_r3_25()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_TYPECAST; $this->token = \Smarty\Parser\TemplateParser::TP_TYPECAST;
} }
public function yy_r3_28() public function yy_r3_29()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_OPENP; $this->token = \Smarty\Parser\TemplateParser::TP_OPENP;
} }
public function yy_r3_29() public function yy_r3_30()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_CLOSEP; $this->token = \Smarty\Parser\TemplateParser::TP_CLOSEP;
} }
public function yy_r3_30() public function yy_r3_31()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_OPENB; $this->token = \Smarty\Parser\TemplateParser::TP_OPENB;
} }
public function yy_r3_31() public function yy_r3_32()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_CLOSEB; $this->token = \Smarty\Parser\TemplateParser::TP_CLOSEB;
} }
public function yy_r3_32() public function yy_r3_33()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_PTR; $this->token = \Smarty\Parser\TemplateParser::TP_PTR;
} }
public function yy_r3_33() public function yy_r3_34()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_APTR; $this->token = \Smarty\Parser\TemplateParser::TP_APTR;
} }
public function yy_r3_34() public function yy_r3_35()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_EQUAL; $this->token = \Smarty\Parser\TemplateParser::TP_EQUAL;
} }
public function yy_r3_35() public function yy_r3_36()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_INCDEC; $this->token = \Smarty\Parser\TemplateParser::TP_INCDEC;
} }
public function yy_r3_37() public function yy_r3_38()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_UNIMATH; $this->token = \Smarty\Parser\TemplateParser::TP_UNIMATH;
} }
public function yy_r3_39() public function yy_r3_40()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_MATH; $this->token = \Smarty\Parser\TemplateParser::TP_MATH;
} }
public function yy_r3_41() public function yy_r3_42()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_AT; $this->token = \Smarty\Parser\TemplateParser::TP_AT;
} }
public function yy_r3_42() public function yy_r3_43()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_ARRAYOPEN; $this->token = \Smarty\Parser\TemplateParser::TP_ARRAYOPEN;
} }
public function yy_r3_43() public function yy_r3_44()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_HATCH; $this->token = \Smarty\Parser\TemplateParser::TP_HATCH;
} }
public function yy_r3_44() public function yy_r3_45()
{ {
// resolve conflicts with shorttag and right_delimiter starting with '=' // resolve conflicts with shorttag and right_delimiter starting with '='
@@ -786,73 +786,73 @@ class TemplateLexer
$this->token = \Smarty\Parser\TemplateParser::TP_ATTR; $this->token = \Smarty\Parser\TemplateParser::TP_ATTR;
} }
} }
public function yy_r3_45() public function yy_r3_46()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_NAMESPACE; $this->token = \Smarty\Parser\TemplateParser::TP_NAMESPACE;
} }
public function yy_r3_48() public function yy_r3_49()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_ID; $this->token = \Smarty\Parser\TemplateParser::TP_ID;
} }
public function yy_r3_49() public function yy_r3_50()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_INTEGER; $this->token = \Smarty\Parser\TemplateParser::TP_INTEGER;
} }
public function yy_r3_50() public function yy_r3_51()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_BACKTICK; $this->token = \Smarty\Parser\TemplateParser::TP_BACKTICK;
$this->yypopstate(); $this->yypopstate();
} }
public function yy_r3_51() public function yy_r3_52()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_VERT; $this->token = \Smarty\Parser\TemplateParser::TP_VERT;
} }
public function yy_r3_52() public function yy_r3_53()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_DOT; $this->token = \Smarty\Parser\TemplateParser::TP_DOT;
} }
public function yy_r3_53() public function yy_r3_54()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_COMMA; $this->token = \Smarty\Parser\TemplateParser::TP_COMMA;
} }
public function yy_r3_54() public function yy_r3_55()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_SEMICOLON; $this->token = \Smarty\Parser\TemplateParser::TP_SEMICOLON;
} }
public function yy_r3_55() public function yy_r3_56()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_DOUBLECOLON; $this->token = \Smarty\Parser\TemplateParser::TP_DOUBLECOLON;
} }
public function yy_r3_56() public function yy_r3_57()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_COLON; $this->token = \Smarty\Parser\TemplateParser::TP_COLON;
} }
public function yy_r3_57() public function yy_r3_58()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_QMARK; $this->token = \Smarty\Parser\TemplateParser::TP_QMARK;
} }
public function yy_r3_58() public function yy_r3_59()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_HEX; $this->token = \Smarty\Parser\TemplateParser::TP_HEX;
} }
public function yy_r3_59() public function yy_r3_60()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_SPACE; $this->token = \Smarty\Parser\TemplateParser::TP_SPACE;
} }
public function yy_r3_60() public function yy_r3_61()
{ {
$this->token = \Smarty\Parser\TemplateParser::TP_TEXT; $this->token = \Smarty\Parser\TemplateParser::TP_TEXT;

View File

@@ -324,7 +324,7 @@ class TemplateLexer
slop = ~\s+(eq|ne|neq|gt|ge|gte|lt|le|lte|mod|and|or|xor)\s+~ slop = ~\s+(eq|ne|neq|gt|ge|gte|lt|le|lte|mod|and|or|xor)\s+~
tlop = ~\s+is\s+(not\s+)?(odd|even|div)\s+by\s+~ tlop = ~\s+is\s+(not\s+)?(odd|even|div)\s+by\s+~
scond = ~\s+is\s+(not\s+)?(odd|even)~ scond = ~\s+is\s+(not\s+)?(odd|even)~
isin = ~\s+is\s+in\s+~ isin = ~\s+is\s+(not\s+)?in\s+~
as = ~\s+as\s+~ as = ~\s+as\s+~
to = ~\s+to\s+~ to = ~\s+to\s+~
step = ~\s+step\s+~ step = ~\s+step\s+~

File diff suppressed because it is too large Load Diff

View File

@@ -663,12 +663,21 @@ expr(res) ::= expr(e1) scond(c). {
res = c . e1 . ')'; res = c . e1 . ')';
} }
expr(res) ::= expr(e1) ISIN array(a). { isin(res) ::= ISIN(o). {
res = 'in_array('.e1.','.a.')'; static $isin = [
'isin' => 'in_array(',
'isnotin' => '!in_array(',
];
$op = strtolower(str_replace(' ', '', o));
res = $isin[$op];
} }
expr(res) ::= expr(e1) ISIN value(v). { expr(res) ::= expr(e1) isin(c) array(a). {
res = 'in_array('.e1.',(array)'.v.')'; res = c . e1.','.a.')';
}
expr(res) ::= expr(e1) isin(c) value(v). {
res = c . e1.',(array)'.v.')';
} }
// null coalescing // null coalescing

View File

@@ -169,6 +169,12 @@ class CompileIfTest extends PHPUnit_Smarty
array('{if {counter start=1} == 1}yes{else}no{/if}', 'yes', 'Tag1', $i ++), array('{if {counter start=1} == 1}yes{else}no{/if}', 'yes', 'Tag1', $i ++),
array('{if false}false{elseif {counter start=1} == 1}yes{else}no{/if}', 'yes', 'Tag2', $i ++), array('{if false}false{elseif {counter start=1} == 1}yes{else}no{/if}', 'yes', 'Tag2', $i ++),
array('{if {counter start=1} == 0}false{elseif {counter} == 2}yes{else}no{/if}', 'yes', 'Tag3', $i ++), array('{if {counter start=1} == 0}false{elseif {counter} == 2}yes{else}no{/if}', 'yes', 'Tag3', $i ++),
array('{if 2 is in ["foo", 2]}yes{else}no{/if}', 'yes', 'IsIn', $i++),
array('{if 2 is in ["foo", "bar"]}yes{else}no{/if}', 'no', 'IsIn2', $i++),
array('{if 2 is not in ["foo", "bar"]}yes{else}no{/if}', 'yes', 'IsNotIn', $i++),
array('{if 2 is not in ["foo", 2]}yes{else}no{/if}', 'no', 'IsNotIn2', $i++),
); );
} }