Compare commits

...

3 Commits

Author SHA1 Message Date
Simon Wisselink 1ab955ada5 use eval to fix compatability of test code for all supported php versions 2026-02-15 15:20:56 +01:00
Simon Wisselink b925a91b00 fix tests on PHP <= 8.0 2026-02-15 15:15:56 +01:00
Simon Wisselink 27379ab3c4 Add support for Backed Enums
Fixes #1012

Also added docs (and docs for matches operator)
2026-02-15 15:11:29 +01:00
7 changed files with 855 additions and 603 deletions
@@ -50,6 +50,120 @@ separated from surrounding elements by spaces. Note that items listed in
| 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) |
| matches | | $a matches $b | regex pattern match | preg_match($b, $a) |
## Regex Matching Operator
The `matches` operator allows you to test if a string matches a regular expression pattern.
### Basic Usage
```smarty
{if "hello" matches "/^[a-z]+$/"}
String matches the pattern!
{/if}
{if $email matches "/^[^@]+@[^@]+\.[^@]+$/"}
Valid email format
{else}
Invalid email format
{/if}
```
### Using Variables
```smarty
{$pattern = '/^[a-zA-Z0-9]{8,}$/'}
{if $password matches $pattern}
Password meets requirements
{else}
Password must be at least 8 alphanumeric characters
{/if}
```
### Pattern Modifiers
The `matches` operator supports all standard PHP regex modifiers:
```smarty
{* Case insensitive matching *}
{if "HELLO" matches "/hello/i"}
Matches (case insensitive)
{/if}
{* Multiline mode *}
{if "line1\nline2" matches "/line2$/m"}
Matches in multiline mode
{/if}
{* Dot matches newlines *}
{if "hello\nworld" matches "/hello.world/s"}
Matches with dotall modifier
{/if}
```
### Complex Conditions
The `matches` operator can be combined with other operators:
```smarty
{if $username matches "/^[a-z]+$/" && $username|length > 3}
Valid username
{else}
Username must be lowercase letters and at least 4 characters
{/if}
{if $input matches "/^[0-9]+$/" || $input matches "/^[a-z]+$/"}
Input is either numeric or lowercase letters
{else}
Invalid input format
{/if}
```
### Practical Examples
**Email Validation:**
```smarty
{if $email matches "/^[^@\s]+@[^@\s]+\.[^@\s]+$/"}
Valid email address
{else}
Please enter a valid email address
{/if}
```
**Password Strength:**
```smarty
{if $password matches "/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/"}
Strong password
{else}
Password must contain uppercase, lowercase, numbers and be at least 8 characters
{/if}
```
**URL Validation:**
```smarty
{if $url matches "/^https?:\/\/(www\.)?[a-z0-9\-]+(\.[a-z]{2,})+/i"}
Valid URL format
{else}
Please enter a valid URL
{/if}
```
**Numeric Validation:**
```smarty
{if $input matches "/^[0-9]+$/"}
Valid numeric input
{else}
Please enter numbers only
{/if}
```
### Notes
- The `matches` operator uses PHP's `preg_match()` function internally
- Pattern delimiters must be valid regex delimiters (typically `/`)
- Invalid patterns will cause PHP warnings but won't break template execution
- For complex regex patterns, consider using variables for better readability
## Ternary
You can use the `?:` (or ternary) operator to test one expression and present the value
@@ -123,4 +123,89 @@ this will output:
```html
name: Zaphod Beeblebrox<br />
email: zaphod@slartibartfast.example.com<br />
```
```
## Backed Enums (PHP 8.1+)
Smarty supports accessing properties of [backed enums](https://www.php.net/manual/en/language.enumerations.backed.php) introduced in PHP 8.1.
### Accessing Enum Properties
You can access the `name` and `value` properties of backed enum cases:
```smarty
{* Access enum case properties *}
<option id="{MyEnum::Foo->name}">{MyEnum::Foo->value}</option>
```
### Complete Example
```php
<?php
use Smarty\Smarty;
// Define a backed enum
enum Status: string {
case Active = 'active';
case Inactive = 'inactive';
case Pending = 'pending';
}
$smarty = new Smarty();
$smarty->assign('currentStatus', Status::Active);
$smarty->display('template.tpl');
```
`template.tpl`:
```smarty
{* Display enum properties *}
Current status: {$currentStatus->name} (value: {$currentStatus->value})
{* Use in HTML attributes *}
<select name="status">
<option value="{Status::Active->value}" {if $currentStatus->name === 'Active'}selected{/if}>Active</option>
<option value="{Status::Inactive->value}" {if $currentStatus->name === 'Inactive'}selected{/if}>Inactive</option>
<option value="{Status::Pending->value}" {if $currentStatus->name === 'Pending'}selected{/if}>Pending</option>
</select>
```
This would output:
```html
Current status: Active (value: active)
<select name="status">
<option value="active" selected>Active</option>
<option value="inactive">Inactive</option>
<option value="pending">Pending</option>
</select>
```
### Integer-backed Enums
Integer-backed enums work the same way:
```php
<?php
enum Priority: int {
case Low = 1;
case Medium = 2;
case High = 3;
}
$smarty->assign('priority', Priority::High);
```
```smarty
{* Access integer enum properties *}
Priority level: {$priority->value} ({$priority->name})
```
Output:
```html
Priority level: 3 (High)
```
> **Note**: Backed enum support requires PHP 8.1 or higher. The enum must be registered or available in the current namespace.
+2
View File
@@ -22,6 +22,8 @@ Some of Smarty's features:
- [Template Inheritance](api/inheritance.md) for
easy management of template content.
- [Plugin](api/extending/introduction.md) architecture
- Regex pattern matching with the [`matches`](designers/language-basic-syntax/language-syntax-operators.md#regex-matching-operator) operator
- Support for PHP 8.1+ [backed enums](designers/language-variables/language-assigned-variables.md#backed-enums-php-81)
## Separation of presentation from application code
- This means templates can certainly contain logic under the condition
+19
View File
@@ -8,6 +8,25 @@ It allows you to write **templates**, using **variables**, **modifiers**, **func
<p>
The number of pixels is: {math equation="x * y" x=$height y=$width}.
</p>
<p>
{if $email matches "/^[^@]+@[^@]+\.[^@]+$/"}
Valid email address
{else}
Please enter a valid email
{/if}
</p>
```
```html
<h1>Hello world</h1>
<p>
The number of pixels is: 307200.
</p>
<p>
Valid email address
</p>
```
When this template is rendered, with the value "Hello world" for the variable $title, 640 for $width,
File diff suppressed because it is too large Load Diff
+5
View File
@@ -1259,6 +1259,11 @@ static_class_access(res) ::= ID(v). {
res = array(v, '');
}
// static class constant with object chain
static_class_access(res) ::= ID(v) objectchain(oc). {
res = array(v, oc);
}
// static class variables
static_class_access(res) ::= DOLLARID(v) arrayindex(a). {
res = array(v, a, 'property');
@@ -64,6 +64,21 @@ class StaticClassAccessTest extends PHPUnit_Smarty
$this->assertEquals('3', $this->smarty->fetch($tpl));
}
/**
* test static class constant chain
*/
public function testRegisteredBackedEnum()
{
if (PHP_VERSION_ID < 80100) {
$this->markTestSkipped('Enums only available after PHP >= 8.1');
return;
} else {
$this->smarty->registerClass('RegisteredBackedEnum', MyBackedEnum::class);
$tpl = $this->smarty->createTemplate('eval:{RegisteredBackedEnum::A->value}');
$this->assertEquals('3', $this->smarty->fetch($tpl));
}
}
/**
* test static class method
*/
@@ -134,3 +149,7 @@ class mystaticclass
return $i * $i;
}
}
if (PHP_VERSION_ID >= 80100) {
eval('enum MyBackedEnum: int { case A = 3; }');
}