twigphp / Twig

Twig, the flexible, fast, and secure template language for PHP
https://twig.symfony.com/
BSD 3-Clause "New" or "Revised" License
8.15k stars 1.25k forks source link

EscaperRuntime::setSafeClasses() implementation #4113

Closed joeworkman closed 2 days ago

joeworkman commented 3 months ago

My Twig extension implements a global that is an adapter for my CMS.

public function getGlobals(): array
{
    return [
            'cms' => $this->adapter,
    ];
}

I would like to set all functions for this class to be safe. I thought that I could use EscaperRuntime::setSafeClasses() for this.

$this->twig->getRuntime(EscaperRuntime::class)->setSafeClasses([
    TotalForm::class           => ['html'],
    TotalCMSTwigAdapter::class => ['html'],
]);

It's not working. Am I close?

fabpot commented 3 months ago

Can you tell us more about what does not work? I've just tried and it works well. I realize that setSafeClasses() might be a confusing method name. This is only to avoid escaping the return value for __toString() methods.

joeworkman commented 3 months ago

Let me explain what I am trying to accomplish. The TotalForm class is essentially a form builder for my CMS. Its still a work in progress, but the twig currently looks like this...

{% set form  = cms.objectFormBuilder('blog', {}) %}

{{ form.addField('text', 'mytext', {}) }}
{{ form.build() }}

The problem that I was trying to overcome was the need to add | raw to the build statement since it outputs HTML. I thought setting the TotalForm class (the form variable is an instance of TotalForm) to be "safe" would fix that.

stof commented 1 month ago

What you are displaying is not the form variable but the output of form.build()

joeworkman commented 1 month ago

Yes. That is correct. For now, I have globally disabled the need to use raw. Not ideal but I have to admit that it's nice since so much of my implementation displays HTML from my CMS.

stof commented 1 month ago

Make your build method return a stringable object from a class configured as safe class (which could be the \Twig\Markup object).

When you return a string, you have no way to mark it as safe.

An alternative method is to create a Twig function that would do this build (as Twig functions can tell Twig whether they output a safe value or no), making it look like {{ render_form(form) }}

stof commented 2 days ago

I'm closing this issue as it was based on a misunderstanding of what safe classes are about. The phpdoc type of the method has been improved to make it more likely for such mistake to be detected.