Commit 15b098d8 authored by Fabien Potencier's avatar Fabien Potencier

bug #1576 Namespaces for Twig paths (Adrien)

This PR was merged into the 2.2.x-dev branch.

Discussion
----------

Namespaces for Twig paths

Hello,

Recently, I had to use Symfony project's pieces of code in a Silex project, extending parent templates through submodules. These submodules, on which I had no control, used namespaced templates in their Twig files, such as:
```twig
{% import "@FooModule/macros.html.twig" as macros %}
```

____

### Problem
Silex cannot resolve namespaces by default, since you have to register paths as following:
```php
$app->register(new TwigServiceProvider(), array(
    'twig.path' => [
        '../app/Resources/views',
        '../common/foo-module/Resources/views'
    ]
));
```

### Temporary solution
What I had to do in order to get it working in the project was to "hack" the `\Twig_Loader_Filesystem` class (*PHP 7+*):
```php
$paths = [
    '../app/Resources/views',
    'FooModule' => '../common/foo-module/Resources/views',
];
$app->register(new TwigServiceProvider());
$app['twig.loader.filesystem'] = (function() use (&$paths): \Twig_Loader_Filesystem {
    $fileSystem = new \Twig_Loader_Filesystem();
    foreach ($paths as $namespace => $path) {
        if (is_string($namespace)) {
            $fileSystem->addPath($path, $namespace);
        } else {
            $fileSystem->addPath($path);
        }
    }

     return $fileSystem;
})();
```
This works fine. Other solutions crossed my minds, but this was one of the best alternatives I figured in order to use Twig namespaces in Silex.

### Code modification
Though this solution works, it may seem a bit dirty to have to do this in the project's code and not having the `TwigServiceProvider` providing this possibility. So I added this little piece of algorithm directly at the `\Twig_Loader_Filesystem` instanciation, which now looks like this as you will see in changes:
```php
$app['twig.loader.filesystem'] = function ($app) {
    if (!is_array($app['twig.path'])) {
        $app['twig.path'] = array($app['twig.path']);
    }

    $fileSystem = new \Twig_Loader_Filesystem();
    foreach ($app['twig.path'] as $namespace => $path) {
        if (is_string($namespace)) {
            $fileSystem->addPath($path, $namespace);
        } else {
            $fileSystem->addPath($path);
        }
    }

    return $fileSystem;
};
```
So you can simply register your `TwigServiceProvider` as following:
```php
$app->register(new TwigServiceProvider(), [
    'twig.path' => [
        '../app/Resources/views',
        'FooModule' => '../common/foo-module/Resources/views',
    ]
]);
```

___

English not being my native language, I hope I was clear enough. I stay around to answer any question about this potential contribution. (:

A

Commits
-------

d1f29680 [change] Namespaces for Twig paths
parents bc3eec7b d1f29680
...@@ -154,7 +154,17 @@ class TwigServiceProvider implements ServiceProviderInterface ...@@ -154,7 +154,17 @@ class TwigServiceProvider implements ServiceProviderInterface
}; };
$app['twig.loader.filesystem'] = function ($app) { $app['twig.loader.filesystem'] = function ($app) {
return new \Twig_Loader_Filesystem($app['twig.path']); $paths = is_array($app['twig.path']) ? $app['twig.path'] : array($app['twig.path']);
$fileSystem = new \Twig_Loader_Filesystem();
foreach ($paths as $key => $val) {
if (is_string($key)) {
$fileSystem->addPath($key, $val);
} else {
$fileSystem->addPath($val);
}
}
return $fileSystem;
}; };
$app['twig.loader.array'] = function ($app) { $app['twig.loader.array'] = function ($app) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment