Repository navigation
Conversation
|
The PR title and description don't reflect the implementation. |
Sorry, I forgot to push. The only disadvantage is the exposed |
0c0108d to
d534ef7
Compare
|
The commit message (description) is not accurate anymore :) |
fabpot
left a comment
There was a problem hiding this comment.
Note that Symfony's LazyExtensionPass won't register subclasses of AttributeExtension lazily, because AttributeExtension::getLastModified() redeclares an AbstractExtension method that its check doesn't allow; it'll need a follow-up PR on Symfony as well.
d534ef7 to
0ff3c86
Compare
|
All the extension methods are now final:
The Symfony PR that relies on this change is open: symfony/symfony#67135. |
| * @author Jérôme Tamarelle <jerome@tamarelle.net> | ||
| */ | ||
| final class AttributeExtension extends AbstractExtension | ||
| class AttributeExtension implements LastModifiedExtensionInterface |
There was a problem hiding this comment.
Dropping extends AbstractExtension is a BC break. I would add it back as removing it is not needed.
| throw new \InvalidArgumentException(\sprintf('Do not call the parent constructor when extending "%s", the attributes are read from the extension class itself.', self::class)); | ||
| } | ||
|
|
||
| if ($this instanceof GlobalsInterface) { |
There was a problem hiding this comment.
This is bypassed if a subclass implements GlobalsInterface and has its own constructor.
What about checking is_a($extension->getClass(), GlobalsInterface::class, true) in ExtensionSet::addExtension() for AttributeExtension instances?
There was a problem hiding this comment.
Updated: getGlobals() is now final and throws, so a subclass cannot declare globals of its own. Being final, the guard needs no reflection and does not load the class.
I first tried a check in ExtensionSet::addExtension(), but that would have forced loading the extension class even when it is never used.
c1a248c to
7a22012
Compare
Make AttributeExtension extendable so an extension class can extend it and declare its filters, functions, and tests with the #[AsTwigFilter], #[AsTwigFunction], and #[AsTwigTest] attributes. All the extension methods are final, so a subclass declares nothing else than the callables to read from the attributes. getClass() returns the class passed to the constructor, or static::class when the extension is extended. The constructor enforces the two usages. An AttributeExtension that is not extended must be given the name of the class to read the attributes from, and cannot use AttributeExtension::class. An extended AttributeExtension cannot be given another class than its own. Globals cannot be declared with attributes: getGlobals() is final and throws, so a subclass cannot provide globals of its own. Environment::getExtension() checks that the registered extension is AttributeExtension itself instead of any AttributeExtension instance.
7a22012 to
bf3f355
Compare
Follows #4989.
An existing extension can declare its filters, functions, and tests with PHP attributes instead of implementing
getFilters(),getFunctions(), andgetTests(). Add the#[AsTwigFilter],#[AsTwigFunction], and#[AsTwigTest]attributes on the methods, extendAttributeExtension, and remove the three getters:The class is still a regular extension, so it is registered as usual:
It also works with lazy registration:
AttributeExtensionis registered with the class that holds the attributes, and a runtime loader builds that class on demand:All the extension methods are final, so a subclass declares nothing else than the attributes to read. Globals cannot be declared with attributes:
getGlobals()is final and throws, so a subclass cannot provide globals of its own.Symfony counterpart: symfony/symfony#67135.