Search code examples
phpsymfonytwigsandbox

How to properly enable the twig's sandbox extension in Symfony2?


In Symfony2, there is some Twig module disabled by default. One of them is the debug extension, that adds {% debug %} tag (useful on a development environment).

To enable it, nothing really difficult, you add this service to your configuration :

  debug.twig.extension:
    class: Twig_Extensions_Extension_Debug
    tags:
      - { name: 'twig.extension' }

But how to enable the {% sandbox %} tag?

My issue is that the extension's constructor takes security policies :

public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
{
    $this->policy            = $policy;
    $this->sandboxedGlobally = $sandboxed;
}

By reading the twig documentation, I seen the way to do it natively (without Symfony2) :

$tags = array('if');
$filters = array('upper');
$methods = array(
    'Article' => array('getTitle', 'getBody'),
);
$properties = array(
    'Article' => array('title', 'body'),
);
$functions = array('range');
$policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
$sandbox = new Twig_Extension_Sandbox($policy);
$twig->addExtension($sandbox);

I can do something like that inside a service just before using the sandbox, but that's not as clear as the dependancy injection we're used to.

Is there a better / proper way to enable the twig's sandbox extension in Symfony2?


Solution

  • Why not create a private service of the security policy:

    parameters:
        twig.sandbox.tags:
            - if
        twig.sandbox.filters:
            - upper
        twig.sandbox.methods:
            Article: [getTitle, getBody]
        twig.sandbox.properties:
            Article: [title, body]
        twig.sandbox.functions:
            - range
    
    twig.sandbox.policy:
        class: Twig_Sandbox_SecurityPolicy
        arguments:
            - %twig.sandbox.tags%
            - %twig.sandbox.filters%
            - %twig.sandbox.methods%
            - %twig.sandbox.properties%
            - %twig.sandbox.functions%
        public: false
    

    You can then inject this service into the twig.sandbox.extension service:

    twig.sandbox.extension:
        class: Twig_Extension_Sandbox
        arguments:
            - @twig.sandbox.policy
        tags:
            - { name: twig.extension }
    

    Done. Marking the twig.sandbox.policy private ensures it won't be accessible using the container (it can still be injected into other services, but I think that's not an issue).

    Disclaimer: I haven't tested this and it probably needs some tweaking before it actually works so don't copy paste!