smarty-php / smarty

Smarty is a template engine for PHP, facilitating the separation of presentation (HTML/CSS) from application logic.
Other
2.22k stars 701 forks source link

Request for `prependTemplateDir()` or more options with `addTemplateDir()` - weight, duplicate handling #1022

Closed eileenmcnaughton closed 1 month ago

eileenmcnaughton commented 1 month ago

We have a code base (CiviCRM) that uses Smarty & can be extended by extensions.

Our main code base registers the template directory but the plugins can also register their own. However, in many cases the plugins want their directories to take precedence.

This is a feature request to be able to call addTemplateDir() with a weight or similar or prependTemplateDir().

A secondary request is that this would handle duplicates. We have found that calling getTemplateDirs() is expensive if done between calls to addTemplateDir() and often the extensions are unaware of each other.

wisskid commented 1 month ago

Could you elaborate on that second request? I'm afraid I don't understand what you mean.

wisskid commented 1 month ago

And as for your first request, would you need something like this?

    public function prependTemplateDir($new_template_dir, $is_config = false): void {
        $current_template_dirs = $this->getTemplateDir(null, $is_config);
        array_unshift($current_template_dirs, $new_template_dir);
        $this->setTemplateDir($current_template_dirs, $is_config);
    }
totten commented 1 month ago

@wisskid Yeah, that's the basic idea. Part of the reason for filing this is... that we recently found that's non-performant to repeatedly combine getTemplateDir() and setTemplateDir(). The going theory: each call to getTemplateDir() causes it to re-run normalization over all the paths.

For a small number of paths, that's fine. But it turns out - whenever one extension adds a path, it (re)normalizes n-many paths for all prior extensions. So it's basically O(n^2). Or here's the longer rationalization of that theory:

Screenshot from 2024-05-29 00-45-38

With a handful of extensions, no one notices. But for folks with a large number of extensions, it balloons.

So prependTemplateDirs() would probably want to bypass the (re)normalization that's built into getTemplateDir().

eileenmcnaughton commented 1 month ago

thanks for the quick reply - I was writing a response but seems Tim did first so I'll go with 'what he said' on the second.

On the first, I might be wrong on the second request but it's my understanding that if I have 2 bits of code that don't know about each other & each do

 $smarty->addTemplateDir('\srv\var\template');

Then the template will potentially be added and / or processed through _realPath() twice. I kinda get that it needs to be for symlinks but maybe there is a cheap check that can be done before going through all the expensive stuff

wisskid commented 1 month ago

I see. In that case, we can change it as follows:

    public function prependTemplateDir($new_template_dir, $is_config = false): void {
        $current_template_dirs = $is_config ? $this->config_dir : $this->template_dir;
        array_unshift($current_template_dirs, $new_template_dir);
        $this->setTemplateDir($current_template_dirs, $is_config);
    }

That would postpone the expensive call to _normalizeTemplateConfig up until the first load of a template. Correct?

eileenmcnaughton commented 1 month ago

Yes that seems correct to me

wisskid commented 1 month ago

I'll try to squeeze it in asap

eileenmcnaughton commented 1 month ago

thank you - you have been incredibly responsive!

wisskid commented 1 month ago

@eileenmcnaughton you're welcome!