symfony/symfony — pull request #7818 by bschussek (2013-04-23 13:45:41+00:00)
Title: [FrameworkBundle] Made TemplateNameParser able to parse templates in the @-notation (#5660)

| Q | A
| ------------- | ---
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #6918
| License | MIT
| Doc PR | TODO

This PR adds the ability to handle Twig's new template name syntax (see fabpot/Twig#772 and #5660) to the `TemplateNameParser` class. Before, the syntax could only be used in Twig's own functionality, such as the `extend` or `include` statements. Now, the syntax can be used anywhere in a Symfony application, such as when returning from a Controller, the `@Template` annotation or with PHP Templating. The old syntax "bundle:controller:template" is still supported, but can be completely replaced*.

Examples:

| New Syntax | Old Syntax (still supported) |
| --- | --- |
| `index.html.twig` | `::index.html.twig` |
| `Foo/bar.html.php` | `:Foo:bar.html.php` |
| `@AcmeDemo/test.html.twig` | `AcmeDemoBundle::test.html.twig` |
| `@AcmeDemo/Post/create.html.php` | `AcmeDemoBundle:Post:create.html.php` |

\* The support for bundle inheritance is still missing for Twig: #6918

###### Benchmarks

Performance benchmark:

| | Old paths | New paths (leading @) | New paths (no leading @) |
| --- | --- | --- | --- |
| Before | ~3.20ms | - | - |
| After | ~3.20ms | ~3.25ms | ~2.90ms |

Scripts:

benchmark-old.php

```php
boot();
$parser = new TemplateNameParser($kernel);

$time = microtime(true);

for ($i = 0; $i < 50; ++$i) {
$parser->parse("AcmeDemoBundle:Foo:bar$i.html.twig");
}

echo "Time: " . (microtime(true)-$time)*1000 . "ms\n";
echo "Memory: " . memory_get_peak_usage(true)/(1024*1024) . "MB\n";
```

benchmark-new.php

```php
boot();
$parser = new TemplateNameParser($kernel);

$time = microtime(true);

for ($i = 0; $i < 50; ++$i) {
$parser->parse("@AcmeDemo/Foo/bar$i.html.twig");
}

echo "Time: " . (microtime(true)-$time)*1000 . "ms\n";
echo "Memory: " . memory_get_peak_usage(true)/(1024*1024) . "MB\n";
```

benchmark-new2.php

```php
boot();
$parser = new TemplateNameParser($kernel);

$time = microtime(true);

for ($i = 0; $i < 50; ++$i) {
$parser->parse("AcmeDemoBundle/Foo/bar$i.html.twig");
}

echo "Time: " . (microtime(true)-$time)*1000 . "ms\n";
echo "Memory: " . memory_get_peak_usage(true)/(1024*1024) . "MB\n";
```

###### Remaining Concerns

My remaining concern is about the convention to drop the bundle suffix in the new syntax. I dislike it for three reasons:

* it is inconsistent with the resource import syntax ('@AcmeDemo/index.html.twig` vs. `@AcmeDemoBundle/Resources/config/routing.yml`)
* the paths for templates from a bundle vs. globally overridden templates are inconsistent (`@AcmeDemo/index.html.twig` vs. `AcmeDemoBundle/index.html.twig`)
* when an author creates both a library and some bundle to integrate it, he can't easily add namespaces for both of them (e.g. library "Monolog" and bundle "MonologBundle" - the namespace for the first would be `@Monolog/template.html.twig` but for the second as well, creating a conflict)

@fabpot stated in #5660 that an advantage of dropping the "Bundle" suffix is making the namespaces

> more agnostic for when the templates are used outside of the full-stack framework

I disagree. When I load MonologBundle into my non-Symfony application, it makes sense that the namespace is "MonologBundle".

The second question we have to solve is whether we change the logical template name (`TemplateReference::getLogicalName()`) to the new syntax as well. I left it at the old syntax for now because I don't know what the BC implications would be.