HOWTO: A quick guide to proper caching with tslib_pibase – Episode 1

11 09 2006

Copyright (c) 2006 Elmar Hinz, elmar.hinz@team-red.net
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”.

How to do clean caching and linking with tslib_pibase?

Solution first

class tx_myExtension extends tslib_pibase{
  var $prefixId = 'tx_myExtension'; // same as classname
  var  $pi_checkCHash = TRUE;     // if this is a USER plugin
  var  $pi_USER_INT_obj;               // we don't set it here, we set it on demand
  ...
  function someFunction(...){
    ...
    // -----------------------------------------------------------------------------------
    // link to USER
    // -----------------------------------------------------------------------------------
    $cache = 1;
    $this->pi_USER_INT_obj = 0;
    $this->prefixId = 'tx_targetExtension'; // for internal links keep 'tx_myExtension'
    // -----------------------------------------------------------------------------------
    $label = 'Link to USER plugin';  // the link text
    $overrulePIvars = array( ... the parameters we need to send to the target plugin .... );
    $clearAnyway=1;    // the current values of piVars will NOT be preserved
    $altPageId=33;      // ID of the target page, if not on the same page
    $link = $this->pi_linkTP_keepPIvars($label, $overrulePIvars, $cache, $clearAnyway, $altPageId);
    // -----------------------------------------------------------------------------------
    $this->prefixId = 'tx_myExtension'; // set it back
    // -----------------------------------------------------------------------------------
    ...

    // -----------------------------------------------------------------------------------
    // link to USER_INT
    // -----------------------------------------------------------------------------------
    $cache = 0;
    $this->pi_USER_INT_obj = 1;
    $this->prefixId = 'tx_targetExtension'; // for internal links keep 'tx_myExtension'
    // -----------------------------------------------------------------------------------
    $label = 'Link to USER_INT plugin';  // the link text
    $overrulePIvars = array( ... the parameters we need to send to the target plugin .... );
    $clearAnyway=1;    // the current values of piVars will NOT be preserved
    $altPageId=33;      // ID of the target page, if not on the same page
    $link = $this->pi_linkTP_keepPIvars($label, $overrulePIvars, $cache, $clearAnyway, $altPageId);
    // -----------------------------------------------------------------------------------
    $this->prefixId = 'tx_myExtension'; // set it back
    // -----------------------------------------------------------------------------------
    ...
  }
}

Discussion

The configuration of link-functions could have a more simple API. There is especially one point in tslib_pibase — I regard it as a little bug — that I think is the main source of confusion. It isn’t a blocker to use tslib_pibase, but it makes the handling of caching over complicated. This ends up in dozends of suboptimal caching extensions in TER. Let’s learn to deal with this, to have a better TER.

Hint: It isn’t that easy to get this bug fixed, because core developers fear of backward compatibility issues.

Scenario

Let’s take a typical usecase, a search form, a result list and many details views. You certainly want the details views cached and indexed, but you don’t want to cache the search form and the result list. Now how? If you create an extension by the kickstarter, you either can decide for a USER object that caches or a USER_INT that doesn’t cache. Even for our simple example we would already need both types. That is the point.

The beginner will probably decide for a USER_INT in the kickstarter. The details views will not be cached. That is bad for performance. The pages will not be indexed by indexed search. Maye the beginner decides for USER, so that the search doesn’t work until he sets the no_cache parameter in the one or other way. That is worse. Now the whole page will be re-rendered for every request of the search form. Clearly a performance killer.

Take two

I know of two alternative ways, to access this challenge. The easy way is to work with two plugins instead of one, certainly within the same extension. This way is covered by this article.

Advanced programmers may decide for a USER/USER_INT switch within the same plugin. This USER/USER_INT (also possible as COA/COA_INT) switch was first proposed by typoscript guru JoH in the newsgroup of the Extension Coordination Team (ECT). Meanwhile I have successfully proven his idea and I will use it in my future projects. This advanced way will also be the topic of a future article. : See Joh’s original test setup.

Essentials about caching

no_cache

There are several ways to set the parameter no_cache=1. However the usage of this parameter is depreciated and you should only use it for development or testing purposes. The effect of this parameter is that the whole page (not only the plugin) is re-rendered upon each call. It is neither fetched from the cache nor is it stored into the cache. That wastes a lot of resources and has a slow performance.

USER_INT

This object is never cached, but the pages where it sits in, are usually cached. Because the USER_INT isn’t cached you don’t need different versions of the page for it.

USER

This objects output is cached with the whole page if everything is well configured. As the output is dynamic there will be different variants of each page. The different variants are kept apart by the different URL parameter values send to the page.

The variable $pi_checkCHash should always be set within USER object to enable caching.

  • var $pi_checkCHash = TRUE;

Links to USER and to USER_INT

Now we come to the apex of this short introduction to proper caching. We already learned about the importance of the link parameters to keep the different versions of a page with a USER object apart. Now what are the variables, that control the generation of this link parameters within pi_base link functions?

  • the function parameter $cache
  • the object variable $this->pi_USER_INT_obj

The reasons why we need to set 2 different variables for this simple task are rather of historical than of reasonable nature. Take it how it is for now and learn how to deal with it. For our application we work with a pair of a USER and a USER_INT objects.

Depending on the target object we need to create special types of links. I repeat: It depends on the target object, not on the source object. There may be links to the same object (result-browser links). Then the target object is the same as the source object.

cHash links to USER objects

Links to USER objects necessarily need a cHash, if you want, that the target view is being cached. The cHash is a certification, that the call is a call with legal variables and that the database is allowed to cache the generated view. To reach this you set:

  • $cache =1
  • $this->pi_USER_INT_obj = 0

Simple links to USER_INT objects

USER_INT objects are never cached. So it simply would have no effect to also call them with a cHash. However this wouldn’t give any sense, so you can strip off the cHash for this case.

  • $cache =0
  • $this->pi_USER_INT_obj = 1

(In fact $cache=1 also works, but it would look rather confusing, if we don’t want a cHash. If you want learn more about this paradoxon, read Episode 2.)

Conclusions

  1. We have seen that it is usually not enough to work with one plugin, if we need the combination of cached and uncached pages within one application. We need at least 2 plugins, which also means that the admin user of our application has to drop in and to configure two plugins.
  2. We have learned that the kind of a link we build doesn’t depend on the origin of this link but on the type of the links target.
  3. The clou of all: The object variable $this->pi_USER_INT_obj isn’t that static as it looks like by it’s name and its type. It has to be set to the appropriate value right before each generation of a link, depending on the type of the target.

I hope this little summary will assist the TYPO3 community to create better caching extensions.

Elmar

P.S.

You can create USER or USER_INT within your TS template.

You also can use the function: t3lib_extMgm::addPItoST43(…)

Depending if the last parameter is 1 or 0 it will include the extension as USER or USER_INT.


Actions

Information

3 responses

6 04 2007
A quick guide to proper caching with tslib_pibase - Episode 2 « TYPO3 FLYERS

[...] Episode 1 of A quick guide to proper caching with tslib_pibase I touched the problematic of the object variable $pi_USER_INT_obj. Obviously the name was designed [...]

30 05 2007
Golden rules for TYPO3 extension programmers « TYPO3 FLYERS

[...] with the no_cache parameter is an ugly extension. It’s a killer for indexing and performance. Use a USER_INT where [...]

9 06 2008
caching - TYPO3forum.net

[...] Also ich habe es jetzt endlich geschafft! Dabei hat mir diese Seite geholfen: HOWTO: A quick guide to proper caching with tslib_pibase – Episode 1 TYPO3 FLYERS Jetzt werden auch alle Detailseiten gecached. Leider hat das auch Nachteile: der erste Aufruf [...]

Leave a comment