mirror of
https://github.com/smarty-php/smarty.git
synced 2026-08-09 23:11:30 +02:00
Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b08a1d8332 | ||
|
|
a511a011cb | ||
|
|
7cab1c0c24 | ||
|
|
b7dac0306f | ||
|
|
e73aaf19b5 | ||
|
|
06c49acee4 | ||
|
|
c22d109d17 | ||
|
|
deb0b22976 | ||
|
|
cc3e9c2a20 | ||
|
|
760f4834b3 |
@@ -1,13 +1,9 @@
|
||||
# AGENTS.md
|
||||
|
||||
This file is the single source of truth for AI coding assistants working in this repo (including Claude Code, claude.ai/code).
|
||||
|
||||
## Project
|
||||
|
||||
Smarty v5 — PHP template engine. Single Composer package (`smarty/smarty`), namespace `Smarty\`, source in `src/`, autoloaded via PSR-4. Supports PHP 7.2–8.5.
|
||||
|
||||
Do not use PHP syntax newer than 7.2 in `src/` unless it is guarded for older runtimes.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
@@ -63,7 +59,6 @@ After editing a `.plex` or `.y` file, run `make -B` to regenerate. The generator
|
||||
- All tests extend `PHPUnit_Smarty` (defined in `tests/PHPUnit_Smarty.php`), which provides `setUpSmarty($dir)`.
|
||||
- Test suite root: `tests/UnitTests/`. Typical test `setUp()` calls `$this->setUpSmarty(__DIR__)`.
|
||||
- Each test directory may have its own `templates/`, `configs/` subdirectories. Compiled output goes to `templates_c/` and `cache/` (auto-created by the test harness).
|
||||
- Running the suite scatters generated `templates_c/`, `cache/`, and `templates_tmp/` directories (and empty runtime `templates/`/`configs/` dirs) throughout `tests/` and the repo root. These are not tracked — treat them as noise in `git status`, never commit them, and clean them with `git clean -fd` (exclude tool dirs like `.serena`).
|
||||
- Three test files are excluded in `phpunit.xml`: Memcache, APC, and HttpModifiedSince tests (require external services).
|
||||
- Tests needing MySQL/PDO are gated by constants in `tests/Config.php` (disabled by default).
|
||||
|
||||
|
||||
@@ -6,12 +6,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [5.8.1] - 2026-06-23
|
||||
- Re-activated unit tests for user literals, which were previously disabled due to a bug in refactoring to v5.
|
||||
- fixed a bug where child template's block content leaked into subsequent rendering of the parent template [#1189](https://github.com/smarty-php/smarty/issues/1189)
|
||||
- Moved all unit test-generated output from inside the working tree to tmp files [#1178](https://github.com/smarty-php/smarty/issues/1178)
|
||||
|
||||
|
||||
## [5.8.0] - 2026-02-15
|
||||
- Added support for Backed Enums for php versions >= 8.1 [#1171](https://github.com/smarty-php/smarty/pull/1171)
|
||||
- Added support for new 'matches' operator doing regex matching [#1169](https://github.com/smarty-php/smarty/pull/1169)
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
## include inline
|
||||
- Re-introduce merge_compiled_includes and the {include inline} attribute?
|
||||
|
||||
## Output buffering (major)
|
||||
- Fix ob_ output buffering commands being scattered around the codebase: Smarty's output model is fundamentally "echo everything, wrap in a buffer to capture". An alternative that would be where rendering returns a string rather than echoing — but that touches the entire compiled template format (the unifunc functions all echo) and is a large change.
|
||||
## Output buffering
|
||||
- Fix ob_ output buffering commands being scattered around the codebase
|
||||
|
||||
## Review public static vars (major)
|
||||
## Review public static vars
|
||||
- such as _CHARSET and _IS_WINDOWS
|
||||
|
||||
## Block / inheritance
|
||||
@@ -24,8 +24,9 @@
|
||||
## Plugin system
|
||||
- fix template security checks in one place in compiler
|
||||
|
||||
## Beatify output (major)
|
||||
## Beatify output
|
||||
- compiled templates could be proper classes, possibly using [nette/php-generator](https://packagist.org/packages/nette/php-generator)
|
||||
|
||||
## Unrelated / other
|
||||
- review (and avoid) use of 'clone' keyword
|
||||
- what is 'user literal support', why are unit tests skipped?
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
- Moved all unit test-generated output from inside the working tree to tmp files [#1178](https://github.com/smarty-php/smarty/issues/1178)
|
||||
@@ -20,6 +20,7 @@
|
||||
<testsuite name="foo">
|
||||
<directory>./tests/UnitTests/</directory>
|
||||
<exclude>./tests/UnitTests/CacheResourceTests/Memcache/CacheResourceCustomMemcacheTest.php</exclude>
|
||||
<exclude>./tests/UnitTests/CacheResourceTests/Apc/CacheResourceCustomApcTest.php</exclude>
|
||||
<exclude>./tests/UnitTests/CacheModify/ModifiedSince/HttpModifiedSinceTest.php</exclude>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
@@ -143,7 +143,7 @@ class File extends Base
|
||||
*
|
||||
* @param Template $_template template object
|
||||
*
|
||||
* @return string|false content
|
||||
* @return string content
|
||||
*/
|
||||
public function retrieveCachedContent(Template $_template)
|
||||
{
|
||||
|
||||
@@ -69,12 +69,8 @@ class InheritanceRuntime {
|
||||
* @param array $blockNames outer level block name
|
||||
*/
|
||||
public function init(Template $tpl, $initChild, $blockNames = []) {
|
||||
// if called while executing parent template it must be a sub-template with new inheritance root.
|
||||
// A new root is started either by a child template ($initChild) or by a sub-template included
|
||||
// outside of any block rendering (empty source stack); the latter must not inherit the leftover
|
||||
// block overrides of a previously completed inheritance tree (see issue #1189).
|
||||
if (($initChild || empty($this->sourceStack)) && $this->state === 3
|
||||
&& (strpos($tpl->template_resource, 'extendsall') === false)) {
|
||||
// if called while executing parent template it must be a sub-template with new inheritance root
|
||||
if ($initChild && $this->state === 3 && (strpos($tpl->template_resource, 'extendsall') === false)) {
|
||||
$tpl->setInheritance(clone $tpl->getSmarty()->getRuntime('Inheritance'));
|
||||
$tpl->getInheritance()->init($tpl, $initChild, $blockNames);
|
||||
return;
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ class Smarty extends \Smarty\TemplateBase {
|
||||
/**
|
||||
* smarty version
|
||||
*/
|
||||
const SMARTY_VERSION = '5.8.1';
|
||||
const SMARTY_VERSION = '5.8.0';
|
||||
|
||||
/**
|
||||
* define caching modes
|
||||
|
||||
@@ -17,7 +17,11 @@ class UserliteralTest extends PHPUnit_Smarty
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->setUpSmarty(__DIR__);
|
||||
if (!property_exists('Smarty', 'literals')) {
|
||||
$this->markTestSkipped('user literal support');
|
||||
} else {
|
||||
$this->setUpSmarty(__DIR__);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -65,6 +65,15 @@ class EvalResourceTest extends PHPUnit_Smarty
|
||||
$this->assertEquals('', $this->smarty->fetch($tpl));
|
||||
}
|
||||
|
||||
/**
|
||||
* test usesCompiler
|
||||
*/
|
||||
public function testUsesCompiler()
|
||||
{
|
||||
$tpl = $this->smarty->createTemplate('eval:hello world');
|
||||
$this->markTestIncomplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* test isEvaluated
|
||||
*/
|
||||
|
||||
@@ -86,6 +86,12 @@ class FileResourceTest extends PHPUnit_Smarty
|
||||
$this->assertEquals('hello world', $tpl->getSource()->getContent());
|
||||
}
|
||||
|
||||
public function testUsesCompiler()
|
||||
{
|
||||
$tpl = $this->smarty->createTemplate('helloworld.tpl');
|
||||
$this->markTestIncomplete();
|
||||
}
|
||||
|
||||
public function testIsEvaluated()
|
||||
{
|
||||
$tpl = $this->smarty->createTemplate('helloworld.tpl');
|
||||
|
||||
@@ -60,6 +60,15 @@ class StreamResourceTest extends PHPUnit_Smarty
|
||||
$this->assertEquals('hello world {$foo}', $tpl->getSource()->getContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* test usesCompiler
|
||||
*/
|
||||
public function testUsesCompiler()
|
||||
{
|
||||
$tpl = $this->smarty->createTemplate('global:mytest');
|
||||
$this->markTestIncomplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* test isEvaluated
|
||||
*/
|
||||
|
||||
@@ -73,6 +73,15 @@ class StringResourceTest extends PHPUnit_Smarty
|
||||
$this->assertEquals('hello world{$foo}', $tpl->getSource()->getContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* test usesCompiler
|
||||
*/
|
||||
public function testUsesCompiler()
|
||||
{
|
||||
$tpl = $this->smarty->createTemplate('string:hello world');
|
||||
$this->markTestIncomplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* test isEvaluated
|
||||
*/
|
||||
|
||||
+41
-43
@@ -1,52 +1,50 @@
|
||||
<?php
|
||||
// first class callables where introduced in PHP 8.1
|
||||
if (PHP_VERSION_ID >= 80100) {
|
||||
|
||||
/**
|
||||
* class for register modifier with (first class) callables tests
|
||||
*
|
||||
* @runTestsInSeparateProcess
|
||||
* @preserveGlobalState disabled
|
||||
* @backupStaticAttributes enabled
|
||||
*/
|
||||
class RegisterModifierFirstClassCallablesTest extends PHPUnit_Smarty
|
||||
{
|
||||
public function setUp(): void
|
||||
/**
|
||||
* class for register modifier with (first class) callables tests
|
||||
*
|
||||
* @runTestsInSeparateProcess
|
||||
* @preserveGlobalState disabled
|
||||
* @backupStaticAttributes enabled
|
||||
*/
|
||||
class RegisterModifierFirstClassCallablesTest extends PHPUnit_Smarty
|
||||
{
|
||||
// First-class callable syntax (Closure::fromCallable shorthand) requires PHP 8.1+
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$this->markTestSkipped('First-class callables require PHP >= 8.1');
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->setUpSmarty(__DIR__);
|
||||
}
|
||||
$this->setUpSmarty(__DIR__);
|
||||
|
||||
|
||||
|
||||
public function testRegisterFirstClassCallable()
|
||||
{
|
||||
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'testmodifier', eval('return strrev(...);'));
|
||||
$this->assertEquals('mosredna', $this->smarty->fetch('string:{"andersom"|testmodifier}'));
|
||||
}
|
||||
|
||||
public function testRegisterFirstClassCallableSameName()
|
||||
{
|
||||
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'mymodifier', eval('return strrev(...);'));
|
||||
$this->assertEquals('mosredna', $this->smarty->fetch('string:{"andersom"|mymodifier}'));
|
||||
}
|
||||
|
||||
public function testRegisterFirstClassCallableAsFunc()
|
||||
{
|
||||
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'kprint_r_out', eval('return strrev(...);'));
|
||||
$this->smarty->assign('myVar', 'andersom');
|
||||
$this->assertEquals('mosredna', $this->smarty->fetch('string:{kprint_r_out($myVar)}'));
|
||||
}
|
||||
|
||||
public function testRegisterFirstClassCallableSameNameAsPhpFunc()
|
||||
{
|
||||
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'mymodifierfcc', eval('return strrev(...);'));
|
||||
$this->assertEquals('mosredna', $this->smarty->fetch('string:{mymodifierfcc("andersom")}'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function testRegisterFirstClassCallable()
|
||||
{
|
||||
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'testmodifier', eval('return strrev(...);'));
|
||||
$this->assertEquals('mosredna', $this->smarty->fetch('string:{"andersom"|testmodifier}'));
|
||||
}
|
||||
|
||||
public function testRegisterFirstClassCallableSameName()
|
||||
{
|
||||
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'mymodifier', eval('return strrev(...);'));
|
||||
$this->assertEquals('mosredna', $this->smarty->fetch('string:{"andersom"|mymodifier}'));
|
||||
}
|
||||
|
||||
public function testRegisterFirstClassCallableAsFunc()
|
||||
{
|
||||
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'kprint_r_out', eval('return strrev(...);'));
|
||||
$this->smarty->assign('myVar', 'andersom');
|
||||
$this->assertEquals('mosredna', $this->smarty->fetch('string:{kprint_r_out($myVar)}'));
|
||||
}
|
||||
|
||||
public function testRegisterFirstClassCallableSameNameAsPhpFunc()
|
||||
{
|
||||
$this->smarty->registerPlugin(\Smarty\Smarty::PLUGIN_MODIFIER, 'mymodifierfcc', eval('return strrev(...);'));
|
||||
$this->assertEquals('mosredna', $this->smarty->fetch('string:{mymodifierfcc("andersom")}'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function mymodifierfcc($a, $b, $c)
|
||||
{
|
||||
return "$a function $b $c";
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Smarty PHPunit test reproducing issue #1189.
|
||||
*
|
||||
* When a parent template is {include}d, then a child template that {extends}
|
||||
* the parent overrides a {block}, a subsequent {include} of the parent in the
|
||||
* same render must still show the parent's block content.
|
||||
*
|
||||
* The block override from the extending child must not leak into the later
|
||||
* include of the parent template.
|
||||
*
|
||||
* @see https://github.com/smarty-php/smarty/issues/1189
|
||||
*
|
||||
* @preserveGlobalState disabled
|
||||
*/
|
||||
class IncludeExtendsBlockLeakIssue1189Test extends PHPUnit_Smarty
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->setUpSmarty(__DIR__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sequence: include parent -> include child(extends parent) -> include parent.
|
||||
* Expected: PARENT CHILD PARENT
|
||||
* Bug (#1189): PARENT CHILD CHILD
|
||||
*/
|
||||
public function testBlockOverrideDoesNotLeakIntoLaterParentInclude()
|
||||
{
|
||||
$result = $this->smarty->fetch('top.tpl');
|
||||
$this->assertSame('PARENT CHILD PARENT', preg_replace('/\s+/', ' ', trim($result)));
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
{extends file="parent.tpl"}
|
||||
{block name=message}CHILD{/block}
|
||||
@@ -1 +0,0 @@
|
||||
{block name=message}PARENT{/block}
|
||||
@@ -1 +0,0 @@
|
||||
{include file="parent.tpl"} {include file="child.tpl"} {include file="parent.tpl"}
|
||||
Reference in New Issue
Block a user