8000 Expose a way to access template data and methods in a portable way by fabpot · Pull Request #2236 · twigphp/Twig · GitHub
[go: up one dir, main page]

Skip to content

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

Merged
merged 1 commit into from
Nov 15, 2016

Conversation

fabpot
Copy link
Contributor
@fabpot fabpot commented Nov 10, 2016

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):

$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);
}

@fabpot fabpot force-pushed the expose-render-block branch 3 times, most recently from 8d98933 to 827f22d Compare November 10, 2016 22:09
@fabpot
Copy link
Contributor Author
fabpot commented Nov 10, 2016

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);

@fabpot fabpot force-pushed the expose-render-block branch 4 times, most recently from 9d32db7 to 7b86197 Compare November 10, 2016 22:24
@fabpot fabpot force-pushed the expose-render-block branch from 7b86197 to cf19660 Compare November 10, 2016 22:34
{
if ($this->getAttribute('output')) {
$compiler
->addDebugInfo($this)
Copy link
Member

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 ?

Copy link
Contributor Author

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(')
Copy link
Member

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

Copy link
Contributor Author

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
Copy link
Member

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 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@Koc
Copy link
Contributor
Koc commented Nov 11, 2016

+1 for public api
+0 for internal implementation

@fabpot
Copy link
Contributor Author
fabpot commented Nov 11, 2016

@Koc What do you mean by "internal implementation" vs "public API"?

@fabpot fabpot force-pushed the expose-render-block branch from 599a32e to dbfc800 Compare November 11, 2016 15:49
@Koc
Copy link
Contributor
Koc commented Nov 11, 2016

I mean that is useful for end twig user and solves my issue but I have nothing to say about implementation.

@fabpot fabpot force-pushed the expose-render-block branch from dbfc800 to 8cba0b3 Compare November 11, 2016 16:33
if ($this->getAttribute('output')) {
$compiler
->addDebugInfo($this)
->write('$this->env->load(')
Copy link
Member

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

@fabpot fabpot force-pushed the expose-render-block branch 6 times, most recently from eca75e3 to 0e42931 Compare November 12, 2016 16:54
@fabpot
Copy link
Contributor Author
fabpot commented Nov 12, 2016

I've extracted the second commit to #2245 and removed comments about it here.

@fabpot fabpot force-pushed the expose-render-block branch 3 times, most recently from 8d37844 to 5843bd6 Compare November 12, 2016 19:13
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class Twig_TemplateWrapper
Copy link
Member

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)

Copy link
Contributor Author

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.

Copy link
Contributor

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?

Copy link
Member

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
Copy link
Member

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()
Copy link
Member

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

fabpot added a commit that referenced this pull request Nov 13, 2016
…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
@fabpot fabpot force-pushed the expose-render-block branch 5 times, most recently from 6f4e006 to a244308 Compare November 13, 2016 03:14
@fabpot fabpot changed the title [RFC][WIP] exposed a way to access template data and methods in a portable way Expose a way to access template data and methods in a portable way Nov 13, 2016
@fabpot
Copy link
Contributor Author
fabpot commented Nov 13, 2016

This one is finished now (docs and tests added). If nobody has a better name than Twig_TemplateWrapper, I will merge this one as is.

@fabpot fabpot force-pushed the expose-render-block branch from a244308 to 9ab1523 Compare November 13, 2016 03:20
@fabpot fabpot force-pushed the expose-render-block branch from 9ab1523 to d7062f3 Compare November 13, 2016 03:45
@fabpot fabpot merged commit d7062f3 into twigphp:1.x Nov 15, 2016
fabpot added a commit that referenced this pull request Nov 15, 2016
…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
@SpacePossum
Copy link
Contributor

awesome, thanks!

fabpot added a commit to symfony/symfony that referenced this pull request Nov 16, 2016
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
@fabpot fabpot deleted the expose-render-block branch November 17, 2016 14:45
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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: __CLASS -> __CLASS__

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
0