Skip to content
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

Macros imported to parent template are not accessible in child templates #1924

Closed
sarcher opened this issue Nov 22, 2015 · 16 comments
Closed
Labels

Comments

@sarcher
Copy link

sarcher commented Nov 22, 2015

Testing a Symfony 3/Twig 2 migration on a very large project and came across this.

Suppose we have in parent.html.twig:

{% import 'example_macros.html.twig' as example_macros %}

And then in another template:

{% extends 'parent.html.twig' %}

{{ example_macros.something() }}

This works in Twig 1.x but does not work in Twig 2 (on master). I can't find a specific reference to removing this in the documentation, and wonder if it is intended, since I can find no workaround other than importing commonly used macros into every template. On a large project this is very cumbersome, so I am hoping this is not intended.

If it is intended, is there a workaround for something like this or similar to this?

@ninsuo
Copy link
Contributor

ninsuo commented Nov 22, 2015

This looks like a bug to me.

In 1.x, macros are compiled with a get prefix (eg: getMacroName($param, ...))
http://twigfiddle.com/nm06hd

In 2.x, macros are now compiled with a macro prefix (eg: macroMacroName($param, ...))
http://twigfiddle.com/nm06hd/2

The macro call in a child template (escaping excluded) is:

 $this->getAttribute((isset($context["macro"]) ? $context["macro"] : null), "hello", array(0 => "Fabien"), "method");

But Twig_Template::getAttribute do not implement this new prefix:
https://github.com/twigphp/Twig/blob/master/lib/Twig/Template.php#L538

        if (isset(self::$cache[$class]['methods'][$lcItem])) {
            $method = (string) $item;
        } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
            $method = 'get'.$item;
        } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
            $method = 'is'.$item;
        } elseif (isset(self::$cache[$class]['methods']['__call'])) {
            $method = (string) $item;
            $call = true;
        }

As calling the macro in the template who imports it is just:

echo $context["macro"]->macro_hello("Fabien");

I wonder if we should update the getAttribute method so it manages macro prefixes, or if we should update the compiler so it doesn't call getAttribute anymore on macro calls.

@fabpot
Copy link
Contributor

fabpot commented Nov 23, 2015

The compiler uses getAttribute() in the second case because the macro is not defined, so it cannot be "fixed". Unfortunately, the use case described in this ticket was not supported in Twig 1.x, it worked "by chance".

@ninsuo
Copy link
Contributor

ninsuo commented Nov 23, 2015

As the context is passed to child templates, the macro is well defined. It is just not callable because getAttribute does not manage the macro prefix.

@sarcher
Copy link
Author

sarcher commented Nov 23, 2015

Is there a philosophical reason to not support this type of inheritance, or is merely a technical one that could be solved with the right PR?

@hason
Copy link
Contributor

hason commented Nov 23, 2015

The discussion is in #1766 and the commit was introduced in #1771.

@ninsuo
Copy link
Contributor

ninsuo commented Nov 23, 2015

Yep, renaming the prefix introduced this issue. What do you think @stof?

@stof
Copy link
Member

stof commented Nov 24, 2015

@ninsuo the fact that macros imported in the parent were available in the child templates is a side effect of the old implementation, and it was never supported officially. Note that we are aware of the fact it does not work anymore. This is why we were not able to change this in 1.x.
Making macros callable through getAttribute caused several issues in the past (and requires some special handling in getAttribute to mark such methods as safe btw)

@ninsuo
Copy link
Contributor

ninsuo commented Nov 24, 2015

Hmm, yeah, I just read the expression parser, you are right. So the old implementation behavior was a cool bug :)

@ninsuo
Copy link
Contributor

ninsuo commented Nov 24, 2015

I think we could "fix" this but this will require deep work. It looks weird to add even more work to the already most perf-killing method (Template::getAttribute), but treating macro calls at parsing/compilation time makes them unavailable to other templates.

Maybe copying the blocks behavior (a MacroReference in the function parser (well at least, a reference somewhere), then inheritance via doDisplay...)?

@hason
Copy link
Contributor

hason commented Nov 24, 2015

@ninsuo Yeah, I prefer blocks as is mentioned in #1302 and prepared in #1433.

@ninsuo
Copy link
Contributor

ninsuo commented Nov 24, 2015

Not sure, I want to keep macros, but allow macros inheritance just like blocks are inherited.
I don't know yet what could be done, but that's a good feature, will try to find something.

@stof
Copy link
Member

stof commented Nov 25, 2015

@ninsuo normal macro calls were already treated at compilation time (they are not compiled through getAttribute, even in 1.x)

@HeahDude
Copy link

HeahDude commented Feb 4, 2016

If anyone is interested, I made a gist for an extension allowing to dynamically autoload macro from any views : see link

@HeahDude
Copy link

HeahDude commented Feb 4, 2016

It also work inside macro and set tags

@HeahDude
Copy link

HeahDude commented Feb 5, 2016

Made some tests with this gist and it works perfectly.

Autoload works from absolutely everywhere without import tag, and bonus, once a template is compiled, it is cached for future requests too !

@fabpot fabpot added the Macros label Nov 13, 2016
@fabpot
Copy link
Contributor

fabpot commented May 17, 2019

I'm going to close this one as the 1.x "feature" was actually a nice side effect (but it also came with even more not so nice side effects). With #3012, we are redefining the macro scope rules.

@fabpot fabpot closed this as completed May 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

6 participants