Comments (7)
Reproducer:
<?php
require_once __DIR__.'/vendor/autoload.php';
use Twig\Compiler;
use Twig\Environment;
use Twig\Extension\AbstractExtension;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Node;
use Twig\Node\PrintNode;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
error_reporting(-1);
class EchoNode extends Node
{
public function compile(Compiler $compiler): void
{
$compiler
->addDebugInfo($this)
->write("ob_start();\n")
->subcompile($this->getNode('content1'))
->write('echo "\n";', "\n")
->write("echo 'foo';\n")
->write('echo "\n";', "\n")
->subcompile($this->getNode('content2'))
->write('echo "\n";', "\n")
->write("echo ob_get_clean();\n")
;
}
}
class EchoTokenParser extends AbstractTokenParser
{
public function parse(Token $token): Node
{
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
return new EchoNode([
'content1' => new PrintNode(new ConstantExpression('content1', -1), -1),
'content2' => new PrintNode(new ConstantExpression('content2', -1), -1),
]);
}
public function getTag(): string
{
return 'echo';
}
}
class EchoExtension extends AbstractExtension
{
public function getTokenParsers(): array
{
return [
new EchoTokenParser(),
];
}
}
$twig = new Environment(new Twig\Loader\ArrayLoader(['_bug.twig' => "HERE\n{% echo %}\nHERE"]), [
'strict_variables' => true,
'debug' => true,
'cache' => false,
'autoescape' => false,
'use_yield' => false,
]);
$twig->addExtension(new EchoExtension());
$template = '_bug.twig';
echo $twig->parse($twig->tokenize(new Twig\Source($twig->getLoader()->getSourceContext($template)->getCode(), $template)))."\n\n";
echo $twig->compile($twig->parse($twig->tokenize(new Twig\Source($twig->getLoader()->getSourceContext($template)->getCode(), $template))))."\n\n";
$template = $twig->load($template);
echo $template->render([]);
from twig.
Can you please check if #4216 fixes the issue with nodes that use output buffering?
from twig.
This is still not quite working for nodes that call subcompile()
and expect any raw output to be echoed out, and captured in an output buffer, e.g. like this:
You’ll end up with yield
statements rather than echo
statements:
// line 87
ob_start();
// line 90
yield " ";
…
from twig.
Please open a new issue and provide a reproducer if possible.
from twig.
Isn’t it the same issue? I specifically referenced PrintNode
in the OP.
from twig.
OK, reopening. But I'm missing a realworld description: the fix involves echoing strings that where yielded, so that ob_start() should catch yielded strings. Which means that as is, the updated report is incomplete. Can you please share a reproducer?
from twig.
@fabpot Still seeing an issue after #4221 when macros are involved.
Here’s an example:
{% macro button() %}
{% tag 'button' %}
Button Label
{% endtag %}
{% endmacro %}
{{ _self.button() }}
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
class TagTokenParser extends AbstractTokenParser
{
public function getTag(): string
{
return 'tag';
}
public function parse(Token $token): TagNode
{
$lineno = $token->getLine();
$expressionParser = $this->parser->getExpressionParser();
$stream = $this->parser->getStream();
$nodes = [
'name' => $expressionParser->parseExpression(),
];
$stream->expect(Token::BLOCK_END_TYPE);
$nodes['content'] = $this->parser->subparse(function(Token $token) {
return $token->test('endtag');
}, true);
$stream->expect(Token::BLOCK_END_TYPE);
return new TagNode($nodes, [], $lineno, $this->getTag());
}
}
use Twig\Compiler;
use Twig\Node\Node;
class TagNode extends Node
{
public function compile(Compiler $compiler): void
{
$compiler
->addDebugInfo($this)
->write("ob_start();\n")
->subcompile($this->getNode('content'))
->write("\$content = ob_get_clean();\n")
->write("echo '<' . ")
->subcompile($this->getNode('name'))
->raw(" . '>';\n")
->write("echo \$content;\n")
->write("echo '</' . ")
->subcompile($this->getNode('name'))
->raw(" . '>';\n");
}
}
On Twig 3.8.0 that results in:
protected function doDisplay(array $context, array $blocks = [])
{
$macros = $this->macros;
// line 6
echo twig_call_macro($macros["_self"], "macro_button", [], 6, $context, $this->getSourceContext());
echo "
";
}
// line 1
public function macro_button(...$__varargs__)
{
$macros = $this->macros;
$context = $this->env->mergeGlobals([
"varargs" => $__varargs__,
]);
$blocks = [];
ob_start();
try {
// line 2
echo " ";
ob_start();
// line 3
echo " Button Label
";
$content = ob_get_clean();
echo '<' . "button" . '>';
echo $content;
echo '</' . "button" . '>';
return ('' === $tmp = ob_get_contents()) ? '' : new Markup($tmp, $this->env->getCharset());
} finally {
ob_end_clean();
}
}
<button> Button Label
</button>
But on 7173182 that gives me:
protected function doDisplay(array $context, array $blocks = [])
{
$macros = $this->macros;
// line 6
yield CoreExtension::callMacro($macros["_self"], "macro_button", [], 6, $context, $this->getSourceContext());
yield "
";
return; yield '';
}
// line 1
public function macro_button(...$__varargs__)
{
$macros = $this->macros;
$context = $this->env->mergeGlobals([
"varargs" => $__varargs__,
]);
$blocks = [];
return ('' === $tmp = \Twig\Extension\CoreExtension::captureOutput((function () use (&$context, $macros, $blocks) {
// line 2
yield " ";
ob_start();
// line 3
yield " Button Label
";
$content = ob_get_clean();
echo '<' . "button" . '>';
echo $content;
echo '</' . "button" . '>';
return; yield '';
})())) ? '' : new Markup($tmp, $this->env->getCharset());
}
Button Label
<button></button>
from twig.
Related Issues (20)
- Inconsistency between EscaperExtension and EscaperRuntime HOT 5
- Performance regression since v3.9.0 HOT 2
- Element at index of filtered array throws exception HOT 3
- Twig Extension no longer rendering output HOT 20
- providing locale hangs php
- EscaperRuntime::setSafeClasses() implementation HOT 2
- Ability to mark nodes as implicitly safe HOT 4
- Site Repository ? HOT 1
- Add tree tag to Twig 4.0 HOT 1
- ranged for loop HOT 4
- Is the `_parent` value present in the context supposed to be iterated on by the `for` tag? HOT 3
- Fix behaviour of `cycle` function & mappings ?
- Add tag to declare variable types [WIP] HOT 65
- Deprecated functions in Resources directory cause collisions HOT 5
- `IntegrationTestCase` does not trigger deprecation checks for multiple `--DATA--` HOT 3
- [v4] Uncomment `/* Token::X */` references HOT 1
- [Twig\Loader\ChainLoader] Constructor could accept iterable instead of array. HOT 3
- Port Number Not Included in `absolute_url()` and `url()` Functions HOT 2
- Twig Documentation format_currency error HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from twig.