Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork1.3k
added runtime extensions#1913
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Conversation
lib/Twig/Environment.php Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
the variable name is weird. It is not a callable
stof commentedNov 10, 2015
how would this work to lazy-load extensions ? |
a4b51ce to76c1f04Compareeb3435e toa6324e5Comparefabpot commentedNov 10, 2015
Just done some renames. |
fabpot commentedNov 10, 2015
@stof the goal is to lazy-load the runtime not the extension. An extension is just about declaring which functions/tests/tags/... are available, and they must not depend on any other dependencies. So, the dependencies are part of the runtime, and those can be lazy-loaded when using Symfony or Pimple very easily with some conventions. See the referenced Symfony PR for the implementation of the Form runtime. |
sstok commentedNov 10, 2015
I like it :) but it is missing some tests. |
stof commentedNov 10, 2015
@fabpot how does it work for the definition of the callable in Twig_SimpleFilter ? Your Symfony PR would not work on Twig 2, where the callable is typehinted, as it is not callable anymore. And you are already loosing the support of named arguments in 1.x as the callable is not callable anymore. Please write tests for this feature in Twig, to see whether it works fine |
stof commentedNov 10, 2015
and shouldn't we have a way for extension to tell the compiler whether they use a runtime or no instead of asking loaders to try to provide one ? This would avoid the lookup in all loaders for each extension access, as most extensions won't use it. This could make things much faster. |
fabpot commentedNov 10, 2015
I know about the callable type hints we have in Twig 2.0, but I'm just going to remove them. |
stof commentedNov 10, 2015
@fabpot this will not solve the fact that we need the callable to access parameters through reflection |
fabpot commentedNov 10, 2015
To speed things up, I'm going to get the runtime only once per template by doing so when initializing the template and then reference a property, that should be enough. |
aa297c1 to037abd2Comparefabpot commentedNov 12, 2015
I've just updated the PR which now is able to deal with named arguments. I still need to add some more tests and perhaps throw an exception when the runtime is different from the extension and the |
51fd01a tof8e251fCompare09b2785 to600e08dCompare| $closingParenthesis =false; | ||
| if ($this->hasAttribute('callable') &&$callable =$this->getAttribute('callable')) { | ||
| if (is_string($callable)) { | ||
| if (is_string($callable) &&false ===strpos($callable,'::')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I added that as some Twig tests define Twig elements as functions that do not exist. Not sure we want to support that, but that's why I've added this here and the code to correctly dump static methods below.
600e08d to05fae21Comparehason commentedSep 28, 2016
I prepared PRsymfony/symfony#18268 for Symfony and created thehttps://github.com/symfonette/class-named-services library. |
mnapoli commentedSep 29, 2016
Is there anything preventing to use service names (instead of class names)? All that would be very useful in many frameworks (working just like the way we can register controllers using service names). |
mnapoli commentedSep 29, 2016
Also would it make sense to use container-interop's |
derrabus commentedSep 29, 2016
If I understood correctly, you're using the FQCN for lookups against this runtime loader. From the point of view of a Symfony developer, it would feel more natural and convenient if I could use service names instead of FQCN, for several reasons:
From Twig's POV, it should not really matter if the string that is used to look up a certain service is a FQCN or an arbitrary service ID or am I missing something? |
doc/advanced.rst Outdated
| any valid PHP callable: | ||
| * **functions/closures/static methods**: Simple to implement and fast (used by | ||
| all Twig core extensions); but it is hard for the runtime to depend on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
closures should be separated from other when you say it isfast. Closures don't get compiled in the same way than functions or static methods. They are compiled in a way requiring to initialize extensions to access them (which adds more overhead than using a method of an extension)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
right
| */ | ||
| abstractclass Twig_Node_Expression_Callextends Twig_Node_Expression | ||
| { | ||
| private$reflector; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
do we really need to make it stateful ? Attributes are mutable, but you don't reset this property when mutating the callable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
They are mutable, but if done after the compilation, that won't change anything, and this property is only used when compilation starts. It's stateful as we need it twice. The only edge case would be a node that is re-used after a compilation, changed, and recompiled, not sure it that's a reasonable thing to do anyway.
| if ($r->isStatic()) { | ||
| $compiler->raw(sprintf('%s::%s',$callable[0],$callable[1])); | ||
| }else { | ||
| $compiler->raw(sprintf('$this->env->getRuntime(\'%s\')->%s',$callable[0],$callable[1])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
at this point, do you have a guarantee that$callable[0] does not contain a quote and does not end with a\ ? If no, some escaping is necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Yes, as$callable[0] is a class name at this point, but I will use the proper compiler method to avoid any surprise if we decide to change the class name the to something else.
| $filter = new Twig_SimpleFilter('rot13', 'str_rot13'); | ||
| // or a class static method | ||
| $filter = new Twig_SimpleFilter('rot13', array('SomeClass', 'rot13Filter')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
It looks you only need the static example one below. The above one is already added on line 144. Or did I miss something else ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This is indeed the exact same notation but one would be a static method while the other one is not. I've added some notes to make it (I hope) more clear.
fabpot commentedSep 29, 2016
@derrabus@mnapoli One thing you might have missed is that getting an extension by name has been deprecated very recently (#2148). Extensions are now referenced by their class names only. So, re-adding a name for the runtime looks like going backward at this point. One "simple" way to get names out of class names would be to provide a map between the class name and the service name or just a default convention on the service name (a prefix + the class name in underscore form or something similar). |
5c3bc56 toac67a67Comparestof commentedSep 29, 2016
@fabpot what we could imagine in Symfony is forcing twig runtimes to be tagged with a specific tag, allowing to build a map of class names to service ids for runtimes. |
fabpot commentedSep 29, 2016
@stof Exactly, that's what I proposed when I wrote "provide a map between the class name and the service name", convention can be for Silex for instance. |
889637d tod328169Comparefabpot commentedSep 29, 2016
I've started to implement the Symfony counterpart of this PR, see the linked PR, but mostlysymfony/symfony#20092 |
…ss than the extension they belong to
d328169 to9cb6860CompareThis PR was merged into the 1.x branch.Discussion----------added runtime extensionsCommits-------9cb6860 allowed filters/functions/tests implementation to use a different class than the extension they belong to
This PR was merged into the 3.2-dev branch.Discussion----------added a Twig runtime loader| Q | A| ------------- | ---| Branch? | master| Bug fix? | no| New feature? | yes| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets | seetwigphp/Twig#1913| License | MIT| Doc PR | not yetThis is the Symfony part oftwigphp/Twig#1913. It introduces a Twig runtime loader.Commits-------7fc174b [TwigBundle] added a Twig runtime loader
mnapoli commentedSep 29, 2016
Right but if I come back on what you said:
So there's a difference between referencing an extension (which is now done by class name), and referencing the callable for an element (functions/filters/tests). For example a problem we are experiencing in my team is that we have a Twig extension for the whole app that provides everything and anything (lots of filters, functions, etc.). We started with dependency injection in the With your change we could have a single So lazy-loading the Twig extension is one thing, but lazy-loading the implementation of the elements (function/filter/…) is another problem and is very interesting. And indeed there's no need for extension names (so#2148 is not conflicting), but there's a need for being able to use services instead of class names inside the callables ( I hope that makes sense. |
fabpot commentedSep 29, 2016
@mnapoli I think we agree on (almost) everything. The goal of this PR is indeed to lazy-load the runtimes, not the extensions which are now only about how to expand Twig (without the implementation). Using the class name is the best way to not consider how the runtimes are going to be loaded. Using a service name is exactly the same as giving a name to the extension. They already have a unique identifier, the class name. Anyway, have a look at my PRs on Symfony, everything works quite well as is. |
…m implementations (fabpot)This PR was merged into the 3.2-dev branch.Discussion----------Twig extensions refatoring to decouple definitions from implementations| Q | A| ------------- | ---| Branch? | master| Bug fix? | no| New feature? | yes| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets | seetwigphp/Twig#1913| License | MIT| Doc PR | not yetThis PR tries to use the new Twig runtime loader to the Twig bridge extensions.Commits-------b515702 fixed circular reference in Twig Form integration4b5e412 removed on indirectionc07fc58 [TwigBridge] decoupled Form extension definitions from its runtime
…m implementations (fabpot)This PR was merged into the 3.2-dev branch.Discussion----------Twig extensions refatoring to decouple definitions from implementations| Q | A| ------------- | ---| Branch? | master| Bug fix? | no| New feature? | yes| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets | seetwigphp/Twig#1913| License | MIT| Doc PR | not yetThis PR tries to use the new Twig runtime loader to the Twig bridge extensions.Commits-------b515702 fixed circular reference in Twig Form integration4b5e412 removed on indirectionc07fc58 [TwigBridge] decoupled Form extension definitions from its runtime
No description provided.