Template directives fire too early for dynamic content

78 views
Skip to first unread message

Benque Verkoop op Rekening

unread,
Jun 9, 2022, 6:33:13 AM6/9/22
to Fat-Free Framework
Hi Guys,

i have taken the image template directive from https://fatfreeframework.com/3.8/template to start building our own version on this basis. When integrating in our app i found src attribs which are injected in my template are not processed before the directives fire.

So for example: <img src="{{ @UI }}/images/website/{{ @article->hero }}"/> will result in broken HTML code. Both dynamic filled parts of the src are not processed when the directive is fired and tries to work this <img>. I have some work-arounds for some of the occurences however given example cannot be solved and should be left alone by the directive. However, when i do some checks in the directive to decide if i want to process i can only rebuild the existing structure as it was. But when i return the $args it does not work and when i return the <img> tag still including the src="{{ UI }}/images/website/{{ @article->hero }}" the dynamic parts are not processed and put through to the HTML view as is.

So two questions remain:

1) can de directives be fired after ALL template processing is done on filling the @ vars?
2) if not, how can i skip certain <img> tags whilst processing others

Regards

v.

unread,
Jun 10, 2022, 3:05:43 AM6/10/22
to Fat-Free Framework
I'm sorry, but I have a hard time understanding your question.
What exactly do you mean by "image directive" and "firing" them?
What do you mean by $args and @vars?
A few remarks:
- if the html code is broken, as you say, then the problem probably is in the html file, not in f3 or php
- You will probably not want to put your image folder in your UI folder which contains the html files
- using the mvc model your controller will fill all the variables, then you rdirect them to the html view which may use these variables.

ikkez

unread,
Jun 10, 2022, 4:16:25 AM6/10/22
to Fat-Free Framework
See this guide for a more advanced documentation about how to extend the template engine https://fatfreeframework.com/3.8/extended-templating

Here is a ready to use fully fleshed out image thumbnail directive if you want to have a look https://github.com/ikkez/f3-template-directives/blob/master/src/template/tags/image.php

Benque Verkoop op Rekening

unread,
Jun 16, 2022, 3:18:54 AM6/16/22
to Fat-Free Framework
Hi V.
i ment:
1) 'image directive' => a template directive which processes all <img> tags
2) firing => at a certain point f3 will process all directives, but this happens apparently BEFORE the @ vars are processed
3) @ vars => all variables uses with @ syntax, as per my example @article->hero
4) $args => in this case the arguments filled when the directive is executed, this to see what <img> tag it actually finds. And my proof that the src attrib at that point still holds @article->hero instead of the value that variable shall hold

I hope it is more clear now.

Op vrijdag 10 juni 2022 om 09:05:43 UTC+2 schreef v.:

Benque Verkoop op Rekening

unread,
Jun 16, 2022, 3:22:33 AM6/16/22
to Fat-Free Framework
Hi Ikkez,

although different in goal, this is what i have now. Problem lies somewhere else. In my response to V (see above) i try to explain that the directive itself is not the problem. The problem is when an <img> tag contains a @var as a src attrib value which shall be filled by, for example, /my/image.png the directive processes the <img> BEFORE the @var is actually filled with the path. Thus the directive cannot work because the path is still @var and the directive cannot load the image.

I hope i made it clearer now :-)

Op vrijdag 10 juni 2022 om 10:16:25 UTC+2 schreef ikkez:

Benque Verkoop op Rekening

unread,
Jun 16, 2022, 3:27:33 AM6/16/22
to Fat-Free Framework
To both,

thanks for your replies, my f3 project is getting more mature every day!

The goal here is i ideally would like the app to get all template (theme) images belonging to the theme (not content) such as logo/icons and copy & optimize them to a folder within the webroot. The themes are not within the webroot and i do not like the divide theme stuff to two places.

I hope this explains why i need <img> processing. And before you ask :-), yes @article->hero may suggest it is indeed content but it's part of the theme. The theme offers 5 hero's to choose from, which are tailordesigned for the theme and in my eyes should go IN the theme folder structure. And thus outside the webroot, and thus unreachable.

Op donderdag 16 juni 2022 om 09:22:33 UTC+2 schreef Benque Verkoop op Rekening:

v.

unread,
Jun 16, 2022, 10:03:14 AM6/16/22
to Fat-Free Framework
Sorry, still not grasping what you want to achieve and what your problem is. You use terminology that is unknown to me.

You say " <img src="{{ @UI }}/images/website/{{ @article->hero }}"/> will result in broken HTML code"
So what is the resulting "broken HTML code"  then?
@UI isn't or shouldn't be reachable from the outside, so any images there are by definition not accisible to the user's browser. This has nothing to do with f3, but with your web server.
@UI is for f3 stuff and shouldn't be available to users. You images SHOULD be available to users and hence do not belong in @UI.
What is wrong with putting them in an image or assets directory?

Later in your original post you say " Both dynamic filled parts of the src are not processed when the directive is fired ", what is the output?

If you are working in an MVC model is I presume you are, you should fill the variables in your controller and send them to the output.
Typically there is no more processing and variable setting after the view is shown.

Benque Verkoop op Rekening

unread,
Jun 17, 2022, 3:52:16 AM6/17/22
to Fat-Free Framework
Hi V,

thanx for holding on :-)

Your first comment: You say " <img src="{{ @UI }}/images/website/{{ @article->hero }}"/> will result in broken HTML code"
I don't think i stated this. Above line is in my template and works like it should. @UI holds the path and @article->hero holds the actual basename of the image. The templating resolves into a resolving img path. So far so good.
The problem arises when i use a template directive. With 'Firing' in this context' i mean the actual moment in runtime of the whole app this directive is processed. I do not know any better terms than these. What happens is the directive is processed when the path is not yet processed by the template. In the directive the image should be loaded, optimized and saved to an webroot accessible folder location. But the direct gets {{ @UI }}/images/website/{{ @article->hero }} to process instead of /myuilocation/images/website/hero-1.png. And thus the directive can not process the image, and even more disturbing when the directive returns the basic structure it got from the template structure both @ vars are not processed at all and actually end up in my HTML. And thus the HTML is broken.

So your tip about when filling what is irrelevant since i am dependant on which order of tasks the templating engine uses. Apparently directives first and filling vars later...

@UI is for f3 stuff: yes i totally agree, that is actually the whole point of this exercise :-), to expose elements from UI when i want it after the app has processed/optimised them and placed them in an accessible folder location. Not within UI ofcourse.

Hope this helps. But i get the feeling this cannot be solved without change processing order of the tasks in the templating engine.

Op donderdag 16 juni 2022 om 16:03:14 UTC+2 schreef v.:

v.

unread,
Jun 17, 2022, 4:08:20 AM6/17/22
to Fat-Free Framework
I am not going to argue over this, but you literally stated that.... I copy pasted from your original message... which is still available on this very page...
Maybe you can post your actual code, since I still don't understand what you are trying to do.
I don't understand your use of the term "directive" in this context, but I am thinking that you probably need to do more in the controller, before actually "firing" the template engine.

I actually created a base64 encoded string to show an image outside the public folder in one of my apps. Depending on what it is you want to achieve, this may be a possible solution.
Copying it to a publicly accessible folder can also be perfectly done in the controller function before showing the actual html template

Benque Verkoop op Rekening

unread,
Jun 17, 2022, 5:00:15 AM6/17/22
to Fat-Free Framework
Hi V,

thanx for your reply, the term directive comes from F3 itself and is documented: https://fatfreeframework.com/3.8/quick-reference#include.

I assumed this was known, my apologies for this.

So I created a directive similar to the code Ikkez posted in this topic.

Just to be safe but definitely not condescendant; directives are used to postprocess your templates. One solution i implemented for example is when a form is posted to a different route than the form itself and an error occurs the user rerouted back to the form which is shown with all filled values still in there. You can do this in a controller or even in the template itself by adding a small check per form element but a directive gives the advantage it becomes default behaviour and keeps your controllers small and your templates clean.
Same for my solution; i thought it to be practical that for every UI image i use in my templates they will automatically be copied and optimized from the unaccessible UI location to and accessible webroot location. Directives seem to be ideal since it prevents extra controller logic and whenever i get a request through a new controller this procedure is ready to go and do not have to think about it. And added bonus; my templates remain intiutive since i can just link the image the way it should. The app will take care of it the way it wants and my template designers need not bother about special paths or other special code.

How did you go about your b64 solution? Something you want to share?



Op vrijdag 17 juni 2022 om 10:08:20 UTC+2 schreef v.:

v.

unread,
Jun 17, 2022, 5:30:19 AM6/17/22
to Fat-Free Framework
Basically just

>   $imgData = base64_encode(file_get_contents($img_file));
>   $src = 'data: '.mime_content_type($img_file).';base64,'.$imgData;

where $img_file is the complete path to the image on the server.
The controller than sets the image variable to $src before it outputs the view. 
But I'm sure you can just copy the file as well

Benque Verkoop op Rekening

unread,
Jun 17, 2022, 6:04:21 AM6/17/22
to Fat-Free Framework
Okay, got it. This should go into all involved endpoint controllers or even the base controller. Which in my humble opinion should not process template logic. I think logic regarding templates, url preparation, asset optimisations should be taken care of by the templating itself. I do appreciate the line data: src solution, something to think about when copying. Not sure yet about the performance though... i have no idea if data: src can be cached...

Op vrijdag 17 juni 2022 om 11:30:19 UTC+2 schreef v.:

ikkez

unread,
Jun 18, 2022, 2:11:54 AM6/18/22
to Fat-Free Framework
Hi again.. guess I'm a bit late to the party again... 

Just to clearify one thing: dynamic property values in directive attributes need to be handled in the directive itself. They are not resolved before, for the reason that the directives are run at compile time and it's output is then rendered into the temporary template file, which then only later is executed for rendering on each request itself. Hence the real resolved values it not yet available at this point.

To handle this properly, there are the methods token, resolve and resolveParams that should be used according to the directives use case. There are examples how to use this in my templates directives addon repo https://github.com/ikkez/f3-template-directives/tree/master/src/template/tags

BUT, for your described use case of just finding and processing all images a theme uses, I can imagine that there are other ways images or other assets are consumed outside of an <img> directive. I.e. as background images for inline css like 

<div class="slider">
  <div class="slide" style="background-image: url(path/to/image.jpg)" />
</div>

In order to fetch these cases as well, it might be worth a minute to think about it and decide if it would be a better idea to use a token filter instead:

<picture>
  <source srcset="{{ @heroImgLarge | image }}" media="(min-width: 600px)"> 
  <img src="{{ @heroImg | image }}"> 
</picture>

You can then register a custom "image" filter with this method https://fatfreeframework.com/3.8/preview#filter and process the image path in there, copy / move the file, optimize it and return a new path. This way you can use the image path in other components as well, like meta og:image tags, as data attribute for javascript things, etc.

hope this helps.

ikkez

unread,
Jun 18, 2022, 2:20:30 AM6/18/22
to Fat-Free Framework
one more thing..

this might break:
<custom-directive src="{{ @UI }}/images/website/{{ @article->hero }}"/>

this is better:
<custom-directive src="{{ @UI.'/images/website/'.@article->hero }}"/>

if the first way works, depends on how the directive implements handling dynamic property values. Hence it's currently more save to just pass a token with a concatenated string as a whole into the attribute instead of mixing it up. 

ALSO note that UI can potentially be an array instead of a plain simple string as well ;)

Benque Verkoop op Rekening

unread,
Jun 20, 2022, 6:26:04 AM6/20/22
to Fat-Free Framework
Hi Ikkez,

thanks, this is one cool feature! I will consider this along with your added answer about processing the tokens within the directive.

Op zaterdag 18 juni 2022 om 08:11:54 UTC+2 schreef ikkez:

Benque Verkoop op Rekening

unread,
Jun 20, 2022, 6:30:29 AM6/20/22
to Fat-Free Framework
This does not work unfortunately. Still trying the token processing in the directive...

Op zaterdag 18 juni 2022 om 08:20:30 UTC+2 schreef ikkez:
Message has been deleted
Message has been deleted

Benque Verkoop op Rekening

unread,
Jun 20, 2022, 7:33:41 AM6/20/22
to Fat-Free Framework
Partially resolved:

$tmpl = \Preview::instance();
$image = $tmpl->resolve($attr['src']);

This works for @UI, but not for @article (coming from my model).

Found that f3->get('articles') is available in directive. So now my problem is narrowed to the fact i have a <repeat> loop in my template on @articles which declare @article locally i presume and this is not available in the directive. Which i kinda understand but would love to solve in some way.

Is see my template ends up in tmp/xxx.php as:

<?php foreach (($articles?:[]) as $article): ?>
<?php echo $this->render('includes/post-snippet.html',NULL,get_defined_vars(),0); ?>
<?php endforeach; ?>

my <img> tag is in post-snippet.html. Is there any way to get a hold of $article in this loop?

Op maandag 20 juni 2022 om 12:30:29 UTC+2 schreef Benque Verkoop op Rekening:
Reply all
Reply to author
Forward
0 new messages