Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

Merged
fabpot merged 1 commit intotwigphp:1.xfromfabpot:extensions-runtime
Sep 29, 2016
Merged

Conversation

@fabpot
Copy link
Contributor

No description provided.

Copy link
Member

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
Copy link
Member

how would this work to lazy-load extensions ?

@fabpotfabpotforce-pushed theextensions-runtime branch 2 times, most recently froma4b51ce to76c1f04CompareNovember 10, 2015 08:39
@fabpotfabpotforce-pushed theextensions-runtime branch 3 times, most recently fromeb3435e toa6324e5CompareNovember 10, 2015 08:46
@fabpot
Copy link
ContributorAuthor

Just done some renames.

@fabpot
Copy link
ContributorAuthor

@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
Copy link

I like it :) but it is missing some tests.

@stof
Copy link
Member

@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
Copy link
Member

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
Copy link
ContributorAuthor

I know about the callable type hints we have in Twig 2.0, but I'm just going to remove them.

@stof
Copy link
Member

@fabpot this will not solve the fact that we need the callable to access parameters through reflection

@fabpot
Copy link
ContributorAuthor

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.

@fabpotfabpotforce-pushed theextensions-runtime branch 5 times, most recently fromaa297c1 to037abd2CompareNovember 12, 2015 07:06
@fabpot
Copy link
ContributorAuthor

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 theruntime_class is not defined.

@fabpotfabpotforce-pushed theextensions-runtime branch 2 times, most recently from51fd01a tof8e251fCompareSeptember 23, 2016 20:02
@fabpotfabpotforce-pushed theextensions-runtime branch 4 times, most recently from09b2785 to600e08dCompareSeptember 27, 2016 18:17
$closingParenthesis =false;
if ($this->hasAttribute('callable') &&$callable =$this->getAttribute('callable')) {
if (is_string($callable)) {
if (is_string($callable) &&false ===strpos($callable,'::')) {
Copy link
ContributorAuthor

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.

@hason
Copy link
Contributor

@fabpot

we don't have a mechanism to retrieve a service by its class name

I prepared PRsymfony/symfony#18268 for Symfony and created thehttps://github.com/symfonette/class-named-services library.

@mnapoli
Copy link

The only "complexity" is how we are going to make it work with Silex and Symfony as we don't have a mechanism to retrieve a service by its class name :)

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).

Koc and moufmouf reacted with thumbs up emoji

@mnapoli
Copy link

Also would it make sense to use container-interop'sContainerInterface? Or if you don't want to use that standard, would PSR-11 be a good candidate for that once/if it passes? I'm trying to see if that could be a good use case for it.

moufmouf reacted with thumbs up emoji

@derrabus
Copy link
Contributor

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:

  • With FQCN, I need a mechanism that resolves the FQCN to a service ID.
  • Using service IDs, I can rename/move a class without having to change the loader.
  • With service IDs, I can have multiple services using the same class with different configurations.
  • Furthermore, service IDs allow me to use aliases to change the implementation depending on configuration/environment.

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?

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
Copy link
Member

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)

Copy link
ContributorAuthor

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;
Copy link
Member

@stofstofSep 29, 2016
edited
Loading

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

Copy link
ContributorAuthor

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]));
Copy link
Member

@stofstofSep 29, 2016
edited
Loading

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.

Copy link
ContributorAuthor

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'));
Copy link

@harikthariktSep 29, 2016
edited
Loading

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 ?

Copy link
ContributorAuthor

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.

harikt reacted with thumbs up emoji
@fabpot
Copy link
ContributorAuthor

@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).

@fabpotfabpotforce-pushed theextensions-runtime branch 2 times, most recently from5c3bc56 toac67a67CompareSeptember 29, 2016 16:35
@stof
Copy link
Member

@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
Copy link
ContributorAuthor

@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.

@fabpot
Copy link
ContributorAuthor

I've started to implement the Symfony counterpart of this PR, see the linked PR, but mostlysymfony/symfony#20092

@fabpotfabpot merged commit9cb6860 intotwigphp:1.xSep 29, 2016
fabpot added a commit that referenced this pull requestSep 29, 2016
This 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
fabpot added a commit to symfony/symfony that referenced this pull requestSep 29, 2016
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
Copy link

@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.

Right but if I come back on what you said:

When defining a Twig element, you can now use a class different from the extension: array('ImplementationClass', 'method') or ImplementationClass::method'. Of course, Twig has no idea on how to create an instance of ImplementationClass, so that's the goal of the runtime loader, which most of the time is going to use a dependency injection container to do its work.

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 theTwigExtension class but ended up with a clogged constructor and lots of services initialized for nothing. We could split the class in multiple extensions but all the services would still always be loaded.

With your change we could have a singleTwigExtension declaring all the elements, yet have the implementations in separate classes (group in topics that make sense). Each of these classes could be a proper service (use dependency injection fully). With the new "loader" those function/filters/… implementations would only be instantiated when the function/filter/… is actually used, which is more efficient.

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 (new \Twig_SimpleFilter('price', ['app.price_formatter', 'formatPrice']),).

I hope that makes sense.

@fabpot
Copy link
ContributorAuthor

@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.

fabpot added a commit to symfony/symfony that referenced this pull requestOct 1, 2016
…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
symfony-splitter pushed a commit to symfony/twig-bundle that referenced this pull requestOct 1, 2016
…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
@fabpotfabpot deleted the extensions-runtime branchOctober 9, 2016 18:54
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

2 more reviewers

@harikthariktharikt left review comments

@stofstofstof left review comments

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

7 participants

@fabpot@stof@sstok@hason@mnapoli@derrabus@harikt

[8]ページ先頭

©2009-2025 Movatter.jp