• Fabien Potencier's avatar
    bug #1576 Namespaces for Twig paths (Adrien) · 15b098d8
    Fabien Potencier authored
    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
    15b098d8
Name
Last commit
Last update
doc Loading commit data...
src/Silex Loading commit data...
tests/Silex/Tests Loading commit data...
.gitignore Loading commit data...
.travis.yml Loading commit data...
LICENSE Loading commit data...
README.rst Loading commit data...
composer.json Loading commit data...
phpunit.xml.dist Loading commit data...