-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expose a way to access template data and methods in a portable way #2236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
8d98933
to
827f22d
Compare
Comparison of how to do it now (but does not really work well), and the new safe way: $parameters = array(
'customer' => $customer
);
// old unsafe way
$template = $twig->loadTemplate('mail.twig');
$subject = $template->renderBlock('subject', $parameters);
$bodyHtml = $template->renderBlock('body_html', $parameters);
$bodyText = $template->renderBlock('body_text', $parameters);
// new safe way
$template = $twig->load('mail.twig');
$subject = $template->renderBlock('subject', $parameters);
$bodyHtml = $template->renderBlock('body_html', $parameters);
$bodyText = $template->renderBlock('body_text', $parameters); |
9d32db7
to
7b86197
Compare
7b86197
to
cf19660
Compare
{ | ||
if ($this->getAttribute('output')) { | ||
$compiler | ||
->addDebugInfo($this) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this always be added ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't add this for inlined code (except for context accesses)
$compiler | ||
->raw('$this->env->load(') | ||
->subcompile($this->getNode('template')) | ||
->raw(')->displayBlock(') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should it really use display here ? I think it should be renderBlock
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
@@ -650,8 +656,7 @@ protected function getAttribute($object, $item, array $arguments = array(), $typ | |||
throw $e; | |||
} | |||
|
|||
// useful when calling a template method from a template | |||
// this is not supported but unfortunately heavily used in the Symfony profiler | |||
// @deprecated in 1.28 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should it throw a deprecation warning ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
+1 for public api |
@Koc What do you mean by "internal implementation" vs "public API"? |
599a32e
to
dbfc800
Compare
I mean that is useful for end twig user and solves my issue but I have nothing to say about implementation. |
dbfc800
to
8cba0b3
Compare
if ($this->getAttribute('output')) { | ||
$compiler | ||
->addDebugInfo($this) | ||
->write('$this->env->load(') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, the compiled code could avoid using the Twig_TemplateWrapper layer, as you don't need the output buffer cleanup logic here (it will be cleaned by the rendering of the template using the function already when the exception bubbles to it). This will avoid this level of call stack (and of try/catch). And the Twig code can relies on the Twig internal API.
Btw, this is why rendering blocks directly in the form theming was safe regarding the output buffer: it was always called inside a Twig call cleaning the buffer (unless someone was doing a crazy thing to call the TwigFormRenderer from a different templating engine than Twig). The email rendering use case was the unsafe one, but this one will not rely on template_block
eca75e3
to
0e42931
Compare
I've extracted the second commit to #2245 and removed comments about it here. |
8d37844
to
5843bd6
Compare
* | ||
* @author Fabien Potencier <fabien@symfony.com> | ||
*/ | ||
final class Twig_TemplateWrapper |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we really call it a wrapper ? The fact that it is a wrapper around a Twig_Template object is also an implementation detail. I'm wondering whether we can find a better name here (I have no good idea though)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have loved to use Twig_Template
, but that's not possible. So, I used a descriptive name instead. But I agree that the name is not ideal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to use Twig_Template
for 2.0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing the meaning of Twig_Template between 1.x and 2.x means it is very hard to write forward-compatible code. So -1 for this.
*/ | ||
public function getBlocks() | ||
{ | ||
// FIXME |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be done, or should be removed
return ob_get_clean(); | ||
} | ||
|
||
public function getSourceContext() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add the phpdoc for the return type, as this is the public API
…tion (fabpot) This PR was merged into the 1.x branch. Discussion ---------- added support for a custom template on the block() function `block()` allows one to render a block of the current template. This PR adds the possibility to use `block()` to render a block of another template: ```twig {{ block('footer', template_name) }} ``` As it uses the same logic as for the regular `block()`, you can also use it in a test: ```twig {% if block('footer', template_name) is defined %} ... {% endif %} ``` This removes the needs to use the internal `Twig_Template::renderBlock()` method in the Symfony Web Profiler for instance. And combined with #2236, it allows us to really mark the whole `Twig_Template` class as being internal. I'm aware that #1302 asked for being able to pass a context to `block()` (implemented in #1433), but I prefer not to in favor of adding the `with` tag (see #719 and #1054). When the `with` will be implemented, the code in the Symfony Web Profiler will become something along the lines of: ```twig {% with { 'collector': profile.getcollector(name), 'profiler_url': profiler_url, 'token': profile.token, 'name': name } %} {{ block('toolbar', template) }} {% endwith %} ``` Commits ------- 5ed59be added support for a custom template on the block() function
6f4e006
to
a244308
Compare
This one is finished now (docs and tests added). If nobody has a better name than |
a244308
to
9ab1523
Compare
9ab1523
to
d7062f3
Compare
…ortable way (fabpot) This PR was merged into the 1.x branch. Discussion ---------- Expose a way to access template data and methods in a portable way `Twig_Template` is an internal class, and most of its methods are marked as being `@internal` as they are not "safe" to use by end users. But some of its features are interesting like `renderBlock()` which is very useful when rendering emails for instance (see #1873). This PR tries to address both issues by marking the whole `Twig_Template` class as being internal and by exposing a new way to safely interact with a template besides the obvious `render()`/`display()` methods via `$twig->load("...")`. If also add some convenient methods like `hasBlock()` or `getBlocks()` (see ~#1831~ and #1882): ```php $template = $twig->load('index'); echo $template->render($context); $template->display($context); if ($template->hasBlock('name') { $template->displayBlock('name', $context); } foreach ($template->getBlocks() as $block) { echo $template->render($block, $context); } ``` Commits ------- d7062f3 exposed a way to access template data and methods in a portable way
awesome, thanks! |
This PR was merged into the 2.7 branch. Discussion ---------- bumped min version of Twig to 1.28 | Q | A | ------------- | --- | Branch? | 2.7 | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | see twigphp/Twig#2236 | License | MIT | Doc PR | n/a Commits ------- b8f7614 bumped min version of Twig to 1.28
if ($object instanceof Twig_TemplateInterface) { | ||
@trigger_error('Using the dot notation on an instance of '.__CLASS.' is deprecated since version 1.28 and won\'t be supported anymore in 2.0.', E_USER_DEPRECATED); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: __CLASS
-> __CLASS__
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Twig_Template
is an internal class, and most of its methods are marked as being@internal
as they are not "safe" to use by end users.But some of its features are interesting like
renderBlock()
which is very useful when rendering emails for instance (see #1873).This PR tries to address both issues by marking the whole
Twig_Template
class as being internal and by exposing a new way to safely interact with a template besides the obviousrender()
/display()
methods via$twig->load("...")
.If also add some convenient methods like
hasBlock()
orgetBlocks()
(see#1831and #1882):