[TYPO3-ect] TODO
Elmar Hinz
elmar.DOT.hinz at team.MINUS.red.DOT.net
Fri Apr 20 03:55:05 CEST 2007
>
> Now i want to publish your article. Now you have written a few after the
> pi_base prper caching article.
> Which one do you prefer, is the most important to publish it on
> typo3.org ?
>
> vg Steffen
Hi Steffen,
here comes the first article,
it's formatted in markdown, so you can quickly convert: markdow > HTML > OO
Transformer: http://daringfireball.net/projects/markdown/dingus
Regards
Elmar
# Towards a new world of well integrated extensions
## Passage 1: Successful caching with tslib\_pibase
By Elmar Hinz <elmar.hinz at team-red.net>
### Welcome aboard
So you want to code a TYPO3 frontend extension? Great. Do you whish, that the output can be queried by indexed search? Do you want that your extension is really fast? Then you already find yourself amidst a great clifffhanger.
You may say "Why certainly, I have prepared my plugin with the famous TYPO3 kickstarter. So what?". To quickly take all your illusions away: Simply trusting the kickstarter generated code is not enough to get a fast and clean caching extension. There are some tender points. The kickstarter and the plugin base class tslib\_pibase are both very old pieces of code. Due to backward compatibility issues with the existing extensions the core team is cautios with improvements. Until the community has elaborated a new plugin base, it's up to you, to carefully navigate your ship through the cliffs.
Weigh the anchor! We are already on our journey towards the new world of well integrated extensions. During this first passage you will discover how to avoid the most dangerous no\_cache parameter.
### Your first adventure
Your first task is a typical application for a plugin, to build a search form with a result list below linking to the detail views on a separate page. You want to cache and index each detail view, but you need a dynamic search form and result list. How do you achive this?
The current version of the kickstarter has in fact some functionality to build a plugin with a search form, with a result list and links to single view. Looks perfect. While you create the plugin at a certain point the kickstarter asks you to decide between a USER and a USER\_INT object. You are informed, that the USER object will cache the output while the USER\_INT doesn’t. Even for this simple example you feel that you would need both types. A difficult decision.
Maybe you decide for a USER\_INT, because the form is dynamic. Not bad. But the kickstarter generated code will not cache the single views. Bad for performance. Additionally the single views will not be fetched for indexed search. That is annoying.
Should you better decide for a USER object? Then the single views are cached. Fine. But halt. The search would also be cached. It wouldn't work dynamically. What does the kickstarter? It generates a "no\_cache=1" parameter into the form as a hidden field. That is even worse. Now the whole page will be completely re-rendered for every request of the search form. It becomes a performance killer for the site if people often use the search form.
### Excurs: Essentials about caching
#### no\_cache=1
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 as many resources as possible and so it is very bad for performance. Don't even ask if you could find the page by indexed search.
On a live server NEVER EVER
* append "no\_cache=1" to a URL
* use the function $GLOBALS["TSFE"]->set_no\_cache()
* set the no cache checkbox in the TYPO3 backend form
#### 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. You can't find the output by indexed search.
#### USER
This objects output is cached with the whole page if everything is well configured. There will be different variants of each page. The different variants are kept apart by the different URL parameter values, that also controll the generated output.
The variable $pi_checkCHash should always be set within USER object to enable caching.
var $pi\_checkCHash = TRUE;
### Your second advanture
Surprising lesson of your first advanture: You shouldn't use the kickstarter generated code for this simple task. The kickstarter can be a dangerous master for you. Make yourself the master and learn to use the kickster as a usefull but boneheaded tool.
But the riddles solution now is logically. Isn't it? You need to combine more than one plugin. At least a USER and a USER\_INT. There are several different solutions to do this. For the beginner I suggest that you generate as many plugins as you need with the kickstarter, for example three, form, result list and single view. They can all stay within the same extension.
Having made this decision you hear the boy calling from the crow's nest again. The next ciff is straight ahead. You now discover, that tslib\_pibase wasn't originally designed to link from one plugin to another, like from a result list USER\_INT to a single view USER and back again. The original design results in strange configuration settings and irritating namings of them. Learn to steer the ship carefully through this cliffs.
### Mastering links between USER and USER_INT objects
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
// -----------------------------------------------------------------------------------
...
}
}
You have just learned about the importance of the link parameters to keep the different versions of a page with a USER object apart. But what are the variables, that control the generation of this link parameters within tslib\_pibase link functions? This are exctly two:
1. the function parameter $cache
2. 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 USER and a USER\_INT objects.
When we link from the search for to the single view I speak in this context of a "source plugin" of the link and a "target plugin" of the link. Depending on the target object you need to create different types of links. I repeat: It depends on the target object, not on the source object. There are also links that point back to the object itself, i.e. the links of the pager below a search result list. In this case source and target object are identical.
#### Links to USER objects have a cHash
Links to USER objects necessarily need a cHash. The cHash is a certification, that the call is a call with legal variables and that the resulting page is allowed and requested to be cached. To reach this you set:
* $cache =1
* $this->pi\_USER\_INT\_obj = 0
#### Links to USER\_INT objects have no cHash
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
### Conclusions
1. You have discoverd that it is usually not enough to work with one plugin, if you need the combination of cached and uncached
pages within one application. You need at least 2 plugins. That also means, that the admin user of our application has to drop in
two plugins and to configure them.
2. You have learned that the kind of the link you 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.
### Closing scene
You say, "All this is nice, but I still don't know how to include my class as USER or a USER\_INT". Well, as usual. One solution is the function t3lib_extMgm::addPItoST43(…) within the file ext\_localconf.php. If it is a USER the last parameter has to be 1 for a USER\_INT it has to be 0.
In the given task you would need two or three plugins instead of one. This way the plugin selection dropdown quickly fills up with plugins. Not that pretty. There is a more ambitious way to se it up, by putting several USER and USER\_INT into one USER plugin. The selection can be moved the configuration flexform and the dropdowns get more organized again. How to do this will probably be the topic of "Passage 2" of "Towards a new world of well integrated extensions". In the meantime you will find more articles concerning caching within my private blog: http://t3flyers.wordpress.com.
### Credits
* Team Red: http://team-red.net
* Sunbeam Berlin: http://sunbeam-berlin.de
* Steffen Kamper: http://www.sk-typo3.de
* Daniel Brüßler: http://www.patchworking.de
* Galileo Verlag: http://www.galileocomputing.de/katalog/buecher/titel/gp/titelID-1230
* Das Extension Coordination Team: http://wiki.typo3.org/index.php/Extension\_coordination\_team
More information about the TYPO3-team-extension-coordination
mailing list