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

"extends"'s inheritance chain of templates with the same name #67

Closed
chilek opened this issue Jul 3, 2015 · 24 comments
Closed

"extends"'s inheritance chain of templates with the same name #67

chilek opened this issue Jul 3, 2015 · 24 comments

Comments

@chilek
Copy link

chilek commented Jul 3, 2015

Hello,

I assume the following scenario:
I have many template directories, when each contains template.html file. Let's assume these directories have names: directory1, directory2, directory3.
Then we add all these directories using Smarty::addTemplateDir() method in exact above order to template directories list.
I'd like to be able to create templates as below:

  1. template.html from directory3:
    {block name="contents"}This is {/block}
  2. template.html from directory2:
    {extends file="template.html"}
    {block name="contents"}{$smarty.block.parent}the {/block}
  3. template.html from directory1:
    {extends file="template.html"}
    {block name="contents"}{$smarty.block.parent}test.{/block}

I'd like to get as the result the following text:
This is the test.

Now Smarty triggers error in such scenario, because of recursive template loading.
It could detect that a given directory has been used as template directory for template.html file already and continue searching for template.html file from next template directory in directory chain. It would allow to create dynamically modified templates with simple usage from php code:
$smarty->display('template.html');
This code could be used by something like application plugins.

Maybe you have another solution for described scenario?

Bests, Tomasz

@chilek chilek changed the title extends inheritance chain of templates with the same name "extends"'s inheritance chain of templates with the same name Jul 3, 2015
@uwetews
Copy link
Contributor

uwetews commented Jul 3, 2015

It can be done already.
You can address the template folders by its index.

  1. template.html from directory3:
    {block name="contents"}This is {/block}
  2. template.html from directory2:
    {extends file="[2]template.html"}
    {block name="contents"}{$smarty.block.parent}the {/block}
  3. template.html from directory1:
    {extends file="[1]template.html"}
    {block name="contents"}{$smarty.block.parent}test.{/block}

Note that above example is dependent from the order of the template_dir's.

You may set/add template_dir's also with a named index. Which may add more options.

@uwetews uwetews closed this as completed Jul 3, 2015
@chilek
Copy link
Author

chilek commented Jul 3, 2015

Uwe, thanks for the sugestion, but in your example you have to know registration order of potential application plugins. These application plugins add their individual template directories by Smarty::addTemplateDir(). Plugin creator doesn't know what other application plugins will be installed by user, so he (plugin creator) can't count on template indexes :(

In meantime I've found interesting example:
https://github.com/smarty-php/smarty/blob/master/demo/plugins/resource.extendsall.php
Doesn't it apply to my scenario in any way?

@chilek
Copy link
Author

chilek commented Jul 3, 2015

Something interesting from forum which seems to be what I exactly need:
http://www.smarty.net/forums/viewtopic.php?t=25419

@uwetews
Copy link
Contributor

uwetews commented Jul 4, 2015

Yes, the 'extendsall' could work for you.
Note same as the 'extends' resource all {extends} tags inside the templates will be ignored.

You set/add template_dir's also with a named index.
$smarty->setTemplateDir(array('d1' => 'directory1', 'd2' => 'directory2', 'd3' => 'directory3'));

  1. template.html from directory3:
    {block name="contents"}This is {/block}
  2. template.html from directory2:
    {extends file="['d3']template.html"}
    {block name="contents"}{$smarty.block.parent}the {/block}
  3. template.html from directory1:
    {extends file="['d2']template.html"}
    {block name="contents"}{$smarty.block.parent}test.{/block}

Now you can change with {extends} template name and folder.
That was something I mentioned also here http://www.smarty.net/forums/viewtopic.php?t=25419

@chilek
Copy link
Author

chilek commented Jul 4, 2015

Maybe I wasn't precise so far, so I try to give more detailed example:

  1. In code of application core we have:
    a) template directory named core with template file named template.html
    b) $smarty->addTemplateDir(array('core' => '........./core'));
  2. In code of foo plugin we have:
    a) template directory named foo with template file named template.html
    b) $smarty->addTemplateDir(array('foo' => '........./foo'));
  3. In code of bar plugin we have:
    a) template directory named bar with template file named template.html
    b) $smarty->addTemplateDir(array('bar' => '........./bar'));
  4. foo plugin's author does't know anything about other plugins, so he can't use any directory indexes at all (beside of core of course).
    a) so he could use:
    {extends file="[core]template.html"}
    b) but he couldn't:
    {extends file="[bar]template.html"}
    because he doesn't know anything about this plugin code and bar plugin can be even not installed at all.

@uwetews
Copy link
Contributor

uwetews commented Jul 4, 2015

I was just guessing. So each plugin has it's file template.html and I guess each plugin defines {block} tags with a unique name for that plugin ?

How to access the plugins from user template of random name?
Here my thoughts:
$smarty->display('extends:user.html|extendsall:template.html');
or some new method like
$smarty->loadTemplatePlugins('template.html');
will load all 'template.html' files as parent blocks
$smarty->display('user.html');

Would this be a smarty idea?

@chilek
Copy link
Author

chilek commented Jul 4, 2015

I was just guessing. So each plugin has it's file template.html and I guess each plugin defines {block} > tags with a unique name for that plugin ?

Yes each plugin has its template.html file which extends template.html.
Each template in core has their own unique block names.

$smarty->display('extends:user.html|extendsall:template.html');

user.html in core and template.html for loading from plugins, yeah?

@chilek
Copy link
Author

chilek commented Jul 4, 2015

Uwe,

I have command below in core application module:

$smarty->display('extendsall:customer/customerinfo.html');

This template in core application defines some block as:

{block name="customervoipaccountsbox"}
    {include file="customer/customervoipaccountsbox.html"}
{/block}

In plugin template directory I've prepared template customer/customerinfo.html file as below:

{extends file="customer/customerinfo.html"}
{block name="customervoipaccountsbox"}
    {include file="hv_accountinfobox2.html"}
{/block}

I thought that it would load parent template with extending it by child template, but it was not the clue :( Am i missing anything?
I put https://github.com/smarty-php/smarty/blob/master/demo/plugins/resource.extendsall.php named resource.extendsall.php file in application core SmartyPlugins directory.

@chilek
Copy link
Author

chilek commented Jul 4, 2015

Ok that's apparently the bug in 3.1.27:
https://github.com/smarty-php/smarty/blob/v3.1.27/libs/sysplugins/smarty_internal_resource_file.php#L56
but should be:

if (isset($fileMatch['index'])) {

You've already fixed in HEAD. When will u release 3.1.28?
Thanks a lot for help!

@uwetews
Copy link
Contributor

uwetews commented Jul 5, 2015

if (!empty($fileMatch['index'])) {

is correct. There are conditions where $fileMatch['index'] contains an empty string.
empty() returns also true when $fileMatch['index'] undefined.

@chilek
Copy link
Author

chilek commented Jul 5, 2015

No Uwe, it's not correct. When $fileMatch['index'] contains '0' string (it's default unnamed index for first directory in template directory list) empty() returns true, and this causes the problem which I had before proposed change.

@chilek
Copy link
Author

chilek commented Jul 5, 2015

From php.net documentation:

  1. bool isset ( mixed $var [, mixed $... ] )
Determine if a variable is set and is not NULL.
  1. bool empty ( mixed $var )
"" (an empty string)
0 (0 as an integer)
0.0 (0 as a float)
"0" (0 as a string)
NULL
FALSE
array() (an empty array)
$var; (a variable declared, but without a value)

@uwetews
Copy link
Contributor

uwetews commented Jul 5, 2015

Yes, you are right!!!!
With your change to isset() it will still detect the condition of an empty string in $fileMatch['index'] some instructions later.

Anyway 3.1.28 does solve the problem.
I'm currently still working on some 3.1.28 code. I expect a release within the next 2 weeks.

@chilek
Copy link
Author

chilek commented Jul 5, 2015

Anyway 3.1.28 does solve the problem.
I'm currently still working on some 3.1.28 code. I expect a release within the next 2 weeks.

Exactly!

@chilek
Copy link
Author

chilek commented Jul 9, 2015

Is there any way to automatically prepend all included files in template with 'extendsall:'?
Doing it for Smarty::display() and Smarty::fetch() is as easy as own fetch() implementation in child class of Smarty, but what about:

 {include file="template.html"}

in parent template? Now I have to put 'extendsall:' before template file name to avoid recursive template loading and it's not convenient :(

@uwetews
Copy link
Contributor

uwetews commented Jul 9, 2015

$smarty->default_resource_type = 'extendsall';

Will replace the Smarty default resource type 'file' with 'extendsall'.
This would affect also Smarty::display() and Smarty::fetch().

@chilek
Copy link
Author

chilek commented Jul 9, 2015

I tried it before I had made changes described above, but that had finished with message:

Fatal error: Call to a member function getTemplateDir() on a non-object in ....../lib/SmartyPlugins/resource.extendsall.php on line 28

I've noticed you had changed
https://github.com/smarty-php/smarty/blob/master/demo/plugins/resource.extendsall.php
but this only changes php error message to:

Fatal error: Maximum function nesting level of '250' reached, aborting! in /home/users/hiperus/lms/lib/Smarty/sysplugins/smarty_resource.php on line 224

Call Stack:
    0.0022     855928   1. {main}() /home/users/hiperus/lms/index.php:0
    0.4288   12403400   2. include('/home/users/hiperus/lms/modules/customerinfo.php') /home/users/hiperus/lms/index.php:291
    0.4800   14607624   3. Smarty->display() /home/users/hiperus/lms/modules/customerinfo.php:38
    0.4800   14607944   4. LMSSmarty->fetch() /home/users/hiperus/lms/lib/Smarty/Smarty.class.php:834
    0.4800   14608104   5. Smarty->fetch() /home/users/hiperus/lms/lib/LMSSmarty.php:31
    0.4801   14612656   6. Smarty_Internal_Template->render() /home/users/hiperus/lms/lib/Smarty/Smarty.class.php:820
    0.4803   14632920   7. Smarty_Internal_Template->loadSource() /home/users/hiperus/lms/lib/Smarty/sysplugins/smarty_internal_template.php:210
    0.4803   14632920   8. Smarty_Template_Source::load() /home/users/hiperus/lms/lib/Smarty/sysplugins/smarty_internal_template.php:787
    0.4857   14713032   9. Smarty_Resource_Extendsall->populate() /home/users/hiperus/lms/lib/Smarty/sysplugins/smarty_template_source.php:193
    0.4857   14714672  10. Smarty_Template_Source::load() /home/users/hiperus/lms/lib/SmartyPlugins/resource.extendsall.php:28
    0.4857   14717584  11. Smarty_Resource_Extendsall->populate() /home/users/hiperus/lms/lib/Smarty/sysplugins/smarty_template_source.php:193
    0.4857   14719232  12. Smarty_Template_Source::load() /home/users/hiperus/lms/lib/SmartyPlugins/resource.extendsall.php:28
    0.4858   14722144  13. Smarty_Resource_Extendsall->populate() /home/users/hiperus/lms/lib/Smarty/sysplugins/smarty_template_source.php:193
    0.4858   14723792  14. Smarty_Template_Source::load() /home/users/hiperus/lms/lib/SmartyPlugins/resource.extendsall.php:28
    0.4858   14726704  15. Smarty_Resource_Extendsall->populate() /home/users/hiperus/lms/lib/Smarty/sysplugins/smarty_template_source.php:193
    0.4859   14728352  16. Smarty_Template_Source::load() /home/users/hiperus/lms/lib/SmartyPlugins/resource.extendsall.php:28
    0.4859   14731264  17. Smarty_Resource_Extendsall->populate() /home/users/hiperus/lms/lib/Smarty/sysplugins/smarty_template_source.php:193
    0.4859   14732920  18. Smarty_Template_Source::load() /home/users/hiperus/lms/lib/SmartyPlugins/resource.extendsall.php:28
    0.4859   14735832  19. Smarty_Resource_Extendsall->populate() /home/users/hiperus/lms/lib/Smarty/sysplugins/smarty_template_source.php:193
    0.4859   14737488  20. Smarty_Template_Source::load() /home/users/hiperus/lms/lib/SmartyPlugins/resource.extendsall.php:28
    0.4859   14740400  21. Smarty_Resource_Extendsall->populate() /home/users/hiperus/lms/lib/Smarty/sysplugins/smarty_template_source.php:193
    0.4860   14742056  22. Smarty_Template_Source::load() /home/users/hiperus/lms/lib/SmartyPlugins/resource.extendsall.php:28
    0.4860   14744968  23. Smarty_Resource_Extendsall->populate() /home/users/hiperus/lms/lib/Smarty/sysplugins/smarty_template_source.php:193
    0.4860   14746632  24. Smarty_Template_Source::load() /home/users/hiperus/lms/lib/SmartyPlugins/resource.extendsall.php:28
[snip]

@uwetews
Copy link
Contributor

uwetews commented Jul 10, 2015

extendsall did use internally the default resource, assuming it is 'file:'.
It's now changed that it explicitly use 'file:'

@chilek
Copy link
Author

chilek commented Jul 10, 2015

I've bumped smarty to 3.1.28-dev, because last changes in resource.extendsall.php require relative changes in Smarty_Template_Source class (i.e. Smarty_Template_Source::getTimeStamp() method).
Unfortunately problem still persists with message changed a little bit:

Fatal error: Uncaught: Smarty Compiler: Syntax error in template 
"/home/users/hiperus/lms/templates/default/welcome/welcome.html"  on line 0 "" illegal recursive call of "/home/users/hiperus/lms/templates/default/layout.html"
  thrown in /home/users/hiperus/lms/lib/Smarty/sysplugins/smarty_internal_templatecompilerbase.php on line 0

welcome/welcome.html file contains at the begining:

{extends file="layout.html"}

and layout.html doesn't contain {extends} blocks at all.

@uwetews
Copy link
Contributor

uwetews commented Jul 11, 2015

This is caused now because the extendsall default resource is used also on the {extends} tag.

So you have the option to add extendsall: to your {include} tags or
make extendall the default and add file: to your {extends} tags.

@chilek
Copy link
Author

chilek commented Jul 11, 2015

For the time I use own Smarty class inherited from original one with redefined fetch method as below:

class LMSSmarty extends Smarty {
        public function fetch($template = null, $cache_id = null, $compile_id = null, $parent = null, $display = false, $merge_tpl_vars = true, $no_output_filter = false) {
                if (!is_null($template) && is_string($template) && !preg_match('/^(\/|[a-z]{2,}:)/i', $template))
                        $template = 'extendsall:' . $template;
                return parent::fetch($template, $cache_id, $compile_id, $parent, $display, $merge_tpl_vars, $no_output_filter);
        }
}

That resolves default extendsall resource type for all Smarty::display() and Smarty::fetch() calls.

Changing default resource type for all {include} blocks I make using prefilter definied as:

class Smarty_Prefilter_Extendsall_Include {
        public function prefilter_extendsall_include($tpl_source, Smarty_Internal_Template $template) {
                if (is_array($template->smarty->template_dir) === false)
                        return $tpl_source;
                // prepend all files in {include} blocks with resource type 'extendsall:'
                return preg_replace('#(\{include\s*file=[\'"])(?:(?![a-z]+:|/))(.+)([\'"][^}]*\})#i', '$1extendsall:$2$3', $tpl_source);
        }
}

@uwetews
Copy link
Contributor

uwetews commented Jul 11, 2015

Yes, I think your solution should be free of side effects.

@chilek
Copy link
Author

chilek commented Jul 11, 2015

Uwe, thanks a lot for all your help!

@flexjoly
Copy link

Hi,
I need something like this, but a bit different. Last night i posted allready on the smarty-forum: http://www.smarty.net/forums/viewtopic.php?p=91132

Can this extendsall also work for multiple childs who dont know what they extend, but they add content to the defined blocks. AND each childs needs to be parsed locally with their own template and their own variables.
I can load the parent-templates before or after the childs.

Greetz, flexjoly

think-mcunanan pushed a commit to think-mcunanan/smarty that referenced this issue Mar 22, 2023
…count-deletion-text-to-privacy

#5380: 旧WEB予約 プライバシーポリシーに会員情報削除の文言を追記する
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants