Smarty Forum Index Smarty
The discussions here are for Smarty, a template engine for the PHP programming language.

Smarty 3.1 and some caching issues

 
Post new topic   Reply to topic    Smarty Forum Index -> Smarty 3
View previous topic :: View next topic  
Author Message
SlowFox
Smarty Regular


Joined: 02 Oct 2006
Posts: 44

PostPosted: Wed Oct 12, 2011 3:21 pm    Post subject: Smarty 3.1 and some caching issues Reply with quote

I am in some trouble after moving to Smarty3.1.3. One of my bigger projects uses Smarty for 7 years now and has about 750 individual templates. Due to Smarty2 restrictions and the number of templates, I created my own file structure according to the project needs and wrote a wrapper class based on the Smarty class. This works as follows: templates are divided into "categories" and (if there are still too many in a single category) into a directory tree below them. The place where the template can be found is well defined and the template name does NOT need to be unique throughout the system.

So I have something like (just a small example to illustrate the point):

category "format_xml": order.tpl, receipt.tpl, invoice.tpl
category "format_csv": order.tpl, receipt.tpl, invoice.tpl
category "format_html": order.tpl, receipt.tpl, invoice.tpl

category "page":
directory user: show.tpl, edit.tpl, delete.tpl
directory product: show.tpl, edit.tpl, delete.tpl
directory product/part: show.tpl, edit.tpl, delete.tpl

When switching to 3.1.3 I replacedd my old wrapper by a custom resource handler class which is given category and directory in its constructor and which looks for and returns the appropriate files. Works fine at a basic level. However there appear two different problems:

A) Smarty_Resource::source() and Smarty_Template_Source::getCompiled() both use static caches. They inhibit renderinging of two different templates with the same name. The cache key consists of joined_template_dir (which is constant throughout my usage of Smarty) and $template_resource, which is the (in my case: identical) filename. Bad luck... even trying to use different Smarty objects and/or different resource handlers had no effect, as the caches are static. After commenting out the caching, this issue is solved but I don't really like patching 3rd party software. An idea would be to let the resource handler optionally create a unique identifier for each template which could be used for all the caching issues.

B) templates with the same name are still a problem, as they are not distinguished in the compile-cache directory. I can work around the problem partially by generating different resource types for each category (though this is kind of abusing this feature), but as soon as there are identical files within a single category, this fails miserably. As for now I disabled the compile-cache completely which makes my project work again; however, the performance hit is quite strong. I think this could be solved by the same measure: a template id supported by the custom resource handler to distinguish templates instead of using their mere file name.
Back to top
View user's profile Send private message
rodneyrehm
Administrator


Joined: 30 Mar 2007
Posts: 674
Location: Germany, border to Switzerland

PostPosted: Wed Oct 12, 2011 4:20 pm    Post subject: Reply with quote

so what you need (to solve both problems) is a way for your custom resource handler to modify the template's name. I'll look into it (tomorrow…)
_________________
Twitter
Back to top
View user's profile Send private message Visit poster's website
SlowFox
Smarty Regular


Joined: 02 Oct 2006
Posts: 44

PostPosted: Wed Oct 12, 2011 10:44 pm    Post subject: Reply with quote

globe wrote:
so what you need (to solve both problems) is a way for your custom resource handler to modify the template's name

Yes, that would be perfectly fine.
Back to top
View user's profile Send private message
rodneyrehm
Administrator


Joined: 30 Mar 2007
Posts: 674
Location: Germany, border to Switzerland

PostPosted: Thu Oct 13, 2011 1:27 pm    Post subject: Reply with quote

So I worked up a solution to the problem: SVN trunk revision 4379.

resource.ambiguous.php is of special interest to you. use buildUniqueResourceName() make your ambiguous templates unique (inject your category, directory, …). Also make sure the $source->filepath and $source->uid are unique accross the board.

Whatever buildUniqueResourceName() returns is used for runtime caching mechanisms. whatever ->filepath and ->uid contain, are used for persistent caching (compiled templates, output cache). (not that you really needed to know this…)
_________________
Twitter
Back to top
View user's profile Send private message Visit poster's website
SlowFox
Smarty Regular


Joined: 02 Oct 2006
Posts: 44

PostPosted: Fri Oct 14, 2011 6:37 am    Post subject: Reply with quote

globe wrote:
So I worked up a solution to the problem: SVN trunk revision 4379

Wow, cool. Thanks!

Two questions:

1) most likely I just did something wrong, but why is it
Code:
Smarty_Template_Source::getCompiled() {
[...]
$_cache_key = $_template->template_resource . '#' . $_template->compile_id;

Shouldn't there be a reference to $this->uid? When I change this to
Code:
$_cache_key = $_template->template_resource . '#' . $this->uid . '#' . $_template->compile_id;

things work as I thought they should do. But perhaps I did miss something?

2) why the double caching in Smarty_Resource::load()?
Code:
// try the instance cache
if (isset(self::$resources[$resource_type])) {
    return self::$resources[$resource_type];
}

// try registered resource
if (isset($smarty->registered_resources[$resource_type])) {
    if ($smarty->registered_resources[$resource_type] instanceof Smarty_Resource) {
        return self::$resources[$resource_type] = $smarty->registered_resources[$resource_type];
    }
    if (!isset(self::$resources['registered'])) {
        self::$resources['registered'] = new Smarty_Internal_Resource_Registered();
    }
    return self::$resources['registered'];
}

I can see only two possibilities:

a) one uses only a single Smarty object (as 99% of the people do), then it does not make any difference in performance whether only $smarty->registered_resources[$resource_type] is used, or self::$resources[$resource_type] is set as well.

b) one uses several smarty instances, then it is counterintuitive to say
Code:

$smarty_1 = new Smarty();
$smarty_1->registerResource(new Smarty_Resource_Something('res_1');

$smarty_2 = new Smarty();
$smarty_2->registerResource(new Smarty_Resource_Something('res_2');

and to have both resources available in both smarty objects afterwards (but this is only a question of not understanding your intentions, not actually any problem for me).
Back to top
View user's profile Send private message
rodneyrehm
Administrator


Joined: 30 Mar 2007
Posts: 674
Location: Germany, border to Switzerland

PostPosted: Fri Oct 14, 2011 9:46 am    Post subject: Reply with quote

1) you're right, I totally forgot about Smarty_Template_Compiled.
2) Well, the caching was intended to speed up the resource handler identification. But you're right, it is possible that handlers allowed in SmartInstance1 could not be in SmartyInstance2 but would still bleed through. I'll investigate this.
_________________
Twitter
Back to top
View user's profile Send private message Visit poster's website
rodneyrehm
Administrator


Joined: 30 Mar 2007
Posts: 674
Location: Germany, border to Switzerland

PostPosted: Fri Oct 14, 2011 9:56 am    Post subject: Reply with quote

So I've proven the "resource handler bleeding through" thing. Caching the handlers should ensure that auto-loaded handlers (say resource.mysql.php) are initialized only once (otherwise you might establish multiple connections to a database or some such). So what we've got to add is a way to identify if the cached resource may be used with the given smarty instance. thanks for finding that!
_________________
Twitter
Back to top
View user's profile Send private message Visit poster's website
SlowFox
Smarty Regular


Joined: 02 Oct 2006
Posts: 44

PostPosted: Fri Oct 14, 2011 10:49 am    Post subject: Reply with quote

globe wrote:
Caching the handlers should ensure that auto-loaded handlers (say resource.mysql.php) are initialized only once (otherwise you might establish multiple connections to a database or some such). So what we've got to add is a way to identify if the cached resource may be used with the given smarty instance

From a users point of view I'd expect something like the following:

A given Template:
Code:
<p>some stuff with: {include file='mysql:subtemplate.tpl'}</p>


A given Resource:
Code:
class Smarty_Resource_Mysql extends Smarty_Resource_Custom {
    public function __construct($dbname);
    public function buildUniqueResourceName(...);
    public function populate(...);

    [...]
}


Case A: two objects sharing a database connection:
Code:
$resource_mysql = new Smarty_Resource_Mysql('db_1');

$smarty_a = new Smarty();
$smarty_a->registerResource('mysql', $resource_mysql);

$smarty_b = new Smarty();
$smarty_b->registerResource('mysql', $resource_mysql);


Case B - two objects with different database connections:
Code:
$resource_a = new Smarty_Resource_Mysql('db_1');
$smarty_a = new Smarty();
$smarty_a->registerResource('mysql', $resource_a);

$resource_b = new Smarty_Resource_Mysql('db_2');
$smarty_b = new Smarty();
$smarty_b->registerResource('mysql', $resource_b);


Actually, the second example is not completely esoteric: think of an application with several clients, each with his own corporate layout. You could paint different clients' advertisments on a single page: one frame-template, one handler, but a variety of individual templates behind that, each stored in the respective clients database.

(And regardless of applicability this kind of usage just feels natural for me)
Back to top
View user's profile Send private message
rodneyrehm
Administrator


Joined: 30 Mar 2007
Posts: 674
Location: Germany, border to Switzerland

PostPosted: Sat Oct 15, 2011 10:51 am    Post subject: Reply with quote

I just landed a patch for this.

Resource and CacheResource handling is now (properly) functioning as (initially intended and) follows:

1. check if the handler is already in smarty-instance-specific cache, if so: done
2. check if the handler was registered to smarty-instance, if so: done
3. check everything else, if a handler meets all criteria, check if an instance of the handler already exists, otherwise create a new instance.

Code:
// plugins/resource.foo.php exists
$smarty1 = new Smarty();
$smarty2 = new Smarty();
$smarty1->fetch('foo:bar.tpl');
$smarty2->fetch('foo:blurp.tpl');
// resource handler of smarty 1 === smarty 2

$smarty1 = new Smarty();
$smarty2 = new Smarty();
$smarty2->registerResource('foo', Smarty_Resource_Foo());
$smarty1->fetch('foo:bar.tpl');
$smarty2->fetch('foo:blurp.tpl');
// resource handler of smarty 1 !== smarty 2

_________________
Twitter
Back to top
View user's profile Send private message Visit poster's website
SlowFox
Smarty Regular


Joined: 02 Oct 2006
Posts: 44

PostPosted: Sun Oct 16, 2011 1:58 pm    Post subject: Reply with quote

rodneyrehm wrote:
I just landed a patch for this

Thank you so much, this is exactly what I was longing for.

(Using the trunk I've got a problem with the compile time check now, but this is most likely better off in a new thread)
Back to top
View user's profile Send private message
rodneyrehm
Administrator


Joined: 30 Mar 2007
Posts: 674
Location: Germany, border to Switzerland

PostPosted: Fri Oct 21, 2011 6:41 pm    Post subject: Reply with quote

I just added an option to enable this ambiguity handling. http://code.google.com/p/smarty-php/source/detail?r=4445

Add
Code:
$smarty->allow_ambiguous_resources = true;
to your setup. We disabled this by default, since 99% of implementations won't need this (and should not suffer the performance overhead it imposes…)
_________________
Twitter
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Smarty Forum Index -> Smarty 3 All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group
Protected by Anti-Spam ACP