-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[RFC][TwigBundle] Register custom functions & filters using an attribute #50016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I guess you could even go as far as even deprecating the Also be sure to include the
|
Be careful that Twig itself cannot deprecate the existing system if the new system cannot easily work when using Twig outside Symfony. And making TwigBundle expose a Symfony-only way of extending Twig might not be the best way to go. Especially when you will still need to go back to the Twig way to use some of the features as an attribute won't be able to configure the
Twig uses the extension instance. So ExtensionInterface makes sense to define its API. And I doubt we can deprecate that without breaking support for standalone usage of Twig. |
I agree that deprecating these interfaces wouldn't make sense since they are not defined nor only used in the framework but are part of the twig package itself and they are still "valid".
I was thinking of implementing that only in the framework (either in the TwigBridge or the TwigBundle).
Would it be acceptable to still offer these new attributes as an easier/faster alternative for registering the custom functions/filters when using the framework but still suggesting the Twig way when doing something more complex that wouldn't be compatible with the attribute (e.g. callback)? |
I really love the idea. I only wonder if it is going possible to use the same attribute on a lazy extension. I mean, in your example, you declare the Twig function in the same class as its implementation (in a subclass of So my question is (and sorry if it is a dumb one), if you use attributes, how it will create an extension rather than a lazy loaded one ? |
Well, what we could do in Symfony is have 1 extension implemented in TwigBundle that gets configured based on those services using those attributes (those services will be registered as runtime). |
I thought of an implementation in Twig directly, making the |
…`AsTwigTest` to ease extension development (GromNaN) This PR was squashed before being merged into the 3.x branch. Discussion ---------- Create attributes `AsTwigFilter`, `AsTwigFunction` and `AsTwigTest` to ease extension development One drawback to writing extensions at present is that the declaration of functions/filters/tests is not directly adjacent to the methods. It's worse for runtime extensions because they need to be in 2 different classes. See [`SerializerExtension`](https://github.com/symfony/symfony/blob/7.0/src/Symfony/Bridge/Twig/Extension/SerializerExtension.php) and [`SerializerRuntime`](https://github.com/symfony/symfony/blob/7.0/src/Symfony/Bridge/Twig/Extension/SerializerRuntime.php) as an example. By using attributes for filters, functions and tests definition, we can make writing extensions more expressive, and use reflection to detect particular options (`needs_environment`, `needs_context`, `is_variadic`). Example if we implemented the `formatDate` filter: https://github.com/twigphp/Twig/blob/aeeec9a5e907a79e50a6bb78979154599401726e/extra/intl-extra/IntlExtension.php#L392-L395 By using the `AsTwigFilter` attribute, it is not necessary to create the `getFilters()` method. The `needs_environment` option is detected from method signature. The name is still required as the method naming convention (camelCase) doesn't match with Twig naming convention (snake_case). ```php use Twig\Extension\Attribute\AsTwigFilter; class IntlExtension { #[AsTwigFilter(name: 'format_date')] public function formatDate(Environment $env, $date, ?string $dateFormat = 'medium', string $pattern = '', $timezone = null, string $calendar = 'gregorian', string $locale = null): string { return $this->formatDateTime($env, $date, $dateFormat, 'none', $pattern, $timezone, $calendar, $locale); } } ``` This approach does not totally replace the current definition of extensions, which is still necessary for advanced needs. It does, however, make for more pleasant reading and writing. This makes writing lazy-loaded runtime extension the easiest way to create Twig extension in Symfony: symfony/symfony#52748 Related to symfony/symfony#50016 Is there any need to cache the parsing of method attributes? They are only read at compile time, but that can have a performance impact during development or when using dynamic templates. Commits ------- 5886907 Create attributes `AsTwigFilter`, `AsTwigFunction` and `AsTwigTest` to ease extension development
Description
Currently, in order to create a custom twig function/filter, we need create a class that extends the AbstractExtension, that looks like this:
Example
I've always thought that the DX regarding twig extension could be better when working with Symfony. Today, I imagined the following:
If we don't want to modify or conflict with the existing
TwigFunction
/TwigFilter
classes, we could name them like this and store them in the twig bridge I think?#[AsTwigFilter]
#[AsTwigFunction]
What do you think?
(If the feedbacks are positive, I'll open a PR.)Hum, this seems more difficult than I initially thought.The text was updated successfully, but these errors were encountered: