Part of meta-issue #1788918: [GTD] [META] Prepare for Twig main engine core inclusion until December 1
We will need to extend the twig function findTemplate to check Drupal's theme registry for the location of the current template if we want to be able to include one template from within another, example: image_formatter.twig
This is how we will be calling theme_image_style or theme_image based on weather there is a style or not...
<figure class="{{ item.attributes.class }}" {{ item.attributes }}>
{% if style %}
{% include 'image_style.twig' with {image: item.image } %}
{% else %}
{% include 'image.twig' %}
{% endif %}
{% if item.caption %}
<figcaption>
{{ item.caption }}
</figcaption>
{% endif %}
</figure>
It currently throws an error saying that image.twig can not be found. But if you give it the full path to the image, like so:
<figure class="{{ item.attributes.class }}" {{ item.attributes }}>
{% if style %}
{% include 'core/themes/stark/templates/image/image_style.twig' with {image: item.image } %}
{% else %}
{% include 'core/themes/stark/templates/theme.inc/image.twig' %}
{% endif %}
{% if item.caption %}
<figcaption>
{{ item.caption }}
</figcaption>
{% endif %}
</figure>
It works just fine.
DX todo
- find all template paths for current theme
- find all template paths for parent themes(if any)
- find all core template files for core stark theme
- cache it or store into config() or EntityConfig
- addPath() with computed paths
Background Information
#1777532-4: Extend Twig_Loader_Filesystem instance to get .twig templates paths with hierarchy for theme dependencies
Comments
Comment #1
jenlamptonmoving to the active sandbox.
Comment #2
jenlamptonupdating component
Comment #3
andypostAny reason to have current
theme_registryor is there some battleplan to fix it with new EntityConfig?Comment #4
podarokWe do not actually need extend findTemplate()
Looks like we just have to rewrite twig() function from twig.engine
with
$loader->addPath($path)
after creating $loader instanceComment #5
podarokbetter title and
My proposal for todo
Comment #6
podaroktypo and status
Comment #7
soulston CreditAttribution: soulston commentedtitle typo
Comment #7.0
podarokUpdated issue summary.
Comment #7.1
podarokUpdated issue summary.
Comment #7.2
podarokUpdated issue summary.
Comment #8
vlad.dancer+1 for #5
Comment #8.0
vlad.dancerUpdated issue summary.
Comment #9
Rene BakxIntroducing a new static instance or singleton doesn't sound like a very smart plan when drupal is making the transition into a DIC system.
For Symfony2 the including of templates from bundle1 in bundle2 is solved by extending the include tab with a given structure.
something like this :
incude "@bundle::Folder:folder:template.twig
I guess a system like this could work in drupal too, just need to substitute bundle for theme.
In the override of the include, we just need to check if the to be included file excist and include it. Perhaps the theme registry (if it survives into d8) could be injected into the twig environment, so it becomes easier to see if the requested incude file actually is part of a twig theme instead of traversing all themes and such.
Comment #10
vlad.dancerAs I understand bundle in Symfony it is like module in Drupal? So, U mean to search templates in modules?
Comment #11
podarokSuch syntax looks like not good due to theme dependency system
If one theme is child for another(parent) handling with ...folder:folder... is weird
I vote for #5 cause
children
and
parent(inactive, overridden) theme
is more simpler and better to undestand for front-end designers
Comment #12
podarokYes, I agree with that
But as I know DIC is not ready yet
#1706064: Compile the Injection Container to disk
#1759152: Add a database service to the DIC
And If You can be more specific and provide for us a few examples how we can use DIC workaround - I`ll be happy with that
For now - singleton workaround works well and can be extended for multiple instances possibility between feature freeze and code freeze stages and do not looks like blocking issue for us till feature freeze
Comment #13
Rene Bakx@vlad, Bundles are indeed the symfony equivalent of modules, but my comment was more from a syntax point of view.
@podarok,
Say you have a theme called 'bartik', and your own theme called 'thingee' which is a subtheme of bartik. With the naming structure suggested you could simply do something like.
{% extends '@bartik:node.twig' %} or {% include '@bartik:blocks:block_contact.twig' %}
Where I admit, it is more work to type in a template, but in a blink of an eye it is perfectly clear where the template is extended from, rather then make a magical system where you traverse themes underwater to see if it is a subtheme, and if the parent actually has the template you want to extend or include. Without our thrusty old theme registry it would mean that every time a change is made, the file system must do the traversing again and again. Performance wise, I rather would type a little bit more and spend my time educating new themers instead of telling them stories about magic includes.
As for an example on the DIC, must see if I can digg up some time next week, so I can see what the status is, cause I tought it was already functional, yet very slow cause it is not materialized to disk in a cache (like symfony2 does when you turn your application into production mode) Personally I would rather work on a long term solution, instead of focusing on a short term thing. But i can imagine the presure that is upon us as community, December is coming along awefully fast, and if we don't make it before then this whole twig in core is a no-go I presume?
Comment #14
podarokNot with twig and its template compillation cache
Comment #15
Rene Bakxonly if you are in production mode, in development mode a template is always considered fresh and therefor recompiled on every hit. A minor issue perhaps, but from a developers point of view quite irritating and possible slow. Compare it to the now common practice of clearing the theme registry on every request.
But besides that, my point for extending the loader system with the @themename notation is more about the readablity of template code then performance. I believe drupal could use a little less magic and more clearabillty on where what comes from :)
Comment #16
Fabianx CreditAttribution: Fabianx commentedStarting work on this
Comment #17
Fabianx CreditAttribution: Fabianx commentedSeems we need something like:
and maybe run the preprocess function - if needed with the default being that preprocess is called, but for item-lists or table cells the output can be pre-formatted.
But maybe this is making it more complex and we should just ensure to always call the respective preprocess function. Maybe even re-add theme("item_list", { x:y }).
Comment #18
podarok#17 make template designers crazy
can we make it more simple?
Comment #19
Fabianx CreditAttribution: Fabianx commentedThats the official way:
http://twig.sensiolabs.org/doc/tags/include.html
I don't think we should divert from it.
We just need to make sure that the preprocess functions are called properly.
Comment #20
podarok#19 I got it
Comment #21
steveoliver CreditAttribution: steveoliver commentedre:
Can we discuss this point, and how to know what is "proper", like when does an
{% include %}
'ed twig file need or not need preprocessing?Comment #22
steveoliver CreditAttribution: steveoliver commentedAm I right to think that currently when we include a twig template we are *not* running preprocess on that, as we are circumventing theme() at that, template, level?
Comment #23
Fabianx CreditAttribution: Fabianx commented@22: That is correct.
Comment #24
marfillaster CreditAttribution: marfillaster commentedIn Symfony2 if preprocessing is needed on an include tag, render is used instead which creates a sub request.
Comment #25
Fabianx CreditAttribution: Fabianx commented#24: Interesting ...
Comment #26
marfillaster CreditAttribution: marfillaster commentedThis is the actual code that gets executed via twig render function. This in turn calls Symfony2 Actions templating helper.
https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/Framew...
Comment #27
jenlamptonWill #1777532: Extend Twig_Loader_Filesystem instance to get .twig templates paths with hierarchy for theme dependencies resolve the preprocessing issue?
What I've been doing in current templates is calling the preprocessor for the included template in the preprocessor for the parent template, like so:
we could just continue to do this for every template that includes another, if we had to.
Comment #28
Fabianx CreditAttribution: Fabianx commentedUpdate from Hangout today:
* include will never call preprocess, but will be changed so namespaced templates can be loaded from the theme_registry.
* We will provide theme() for calling the full stack().
=> If you use "theme" you are in Drupal land
=> If you use "use", "extends", "include", "import", "embed" you are in twig land, but templates will be loaded via our special file loader.
---> Nice separation of concerns.
Comment #29
jenlamptonI created #1842160: Consider appropriate usage of theme() from within Twig templates but I think that might just be a dupe of this one. Updating title.
Comment #30
Fabianx CreditAttribution: Fabianx commentedWe still need to change the loader, so changing title back and re-opening and following the other one.
Comment #31
Rene BakxI guess the way templates are discovered changed inbetween D7 and D8? If not, I rewrote the D7 twig template discovery system yesterday to mimic a part of the way Symfony2 is handling includes.
Basically it comes down to a structure like this :
or without the path
or if you are in the same theme
I addapted the Twig_Loader to use this system, with a fallback to the normal inclusion system. And the changes to the engine + loader will be commited into my D7-twig sandbox somewhere this evening (CET+1)
Comment #32
Fabianx CreditAttribution: Fabianx commented#31: Thanks a lot, I will pull the changes in :-).
That was exactly my plan as well, but doesn't Symfony use @namespace: instead of namespace::?
Just wondering ...
Edit: I am not yet seeing the changes. Have you pushed, yet?
Comment #33
Rene BakxNope.. did not make it.. deadlines and work. And yes symfony uses the @ namespace to determine the difference, but i removed the @ because the theming structure in D7 is a lot less structured over various bundles.
I changed the system only to use the current theme and if available the base theme as possible source.
Planning to do the commit today, i actually blocked some time this afternoon to do this :)
Just to be sure, my implementation is for D7, and not a backport of the D8 system. I looked at that once, but it was a lot of work with in my humble opinion less to be gained for D7.
Comment #34
Fabianx CreditAttribution: Fabianx commentedI have taken a look at your sandbox and am thinking of what I'll port to D8, so that is totally fine as I am aware of the differences.
Comment #34.0
Fabianx CreditAttribution: Fabianx commentedUpdated issue summary.
Comment #35
sunUnless I'm terribly mistaken, this has been fixed in Drupal core very recently. We now support to load templates from a given provider namespace, denoted by
@provider/desired-template
.Unfortunately I'm not able to find the core issue right now, but nevertheless, closing as duplicate.