TYPO3 13.4.4 and 12.4.26 maintenance releases published
The versions 13.4.4 and 12.4.26 of the TYPO3 Enterprise Content Management System have just been released.
reset($hookObjectsArr);
while (list(,$hookObj) = each($hookObjectsArr)) {
if (method_exists ($hookObj, 'processDatamap_postProcessFieldArray')) {
$hookObj->processDatamap_postProcessFieldArray ($status, $table, $id, $fieldArray, $this);
}
}
This was great luck of course, because usually you don't find a pre-made hook which perfectly suits your needs. But if there is a need for a new entry point and that hook makes sense to implement, just contact the author of that paticular part of code and he'll gladly provide you with a hook.As you already know, hooks come in two flavours: callUserFunction and the getUserObj. Most of the core developers prefer the tasty getUserObj way - and not only because it has some fancy design pattern behind it (to be honest, it's not that fancy at all, but at least it has something to do with objects).
Anyways, before you can register your method at some hook, you'll have to find out what kind of species you deal with. In our little example, we came across some getUserObj style.
Going the getUserObj way
Instead of explaining the different implementations, I'll just go ahead with describing how we implement our userfunction the getUserObj way. Later on I will show the same implementation using the callUserFunction method, so you'll easily see the differences.
Create and include your own class
The first thing we need, is a new class which contains our user function. This is one important fact about getUserObj driven hooks: You create a class (usually one for each function you want to override in the original source) which contains as many methods as hooks you want to implement.
In our example we want to use one hook in the function process_datamap in the class tce_main. That's why I create a new file, calledclass.tx_myextension_tcemainprocdm.php containing a class named tx_myextension_tcemainprocdm.
Of course it would have been nicer to use the whole function name (..._tcemain_processdatamap) as a filename, but according to the <link http: typo3.org documentation document-library>coding guidelines we are only allowed to use 31 characters for our filename.
Finally we create an empty function in our new classed, with exactly the same name mentioned in the hook. Our class should now look like this:
class tx_myextension_tcemainprocdm {
function processDatamap_postProcessFieldArray ($status, $table, $id, &$fieldArray, &$this) {
// here comes the code
}
}
Register the method
We have seen in the code snippet from TCEmain, that an array called $hookObjectsArr is being traversed and a method processDatamap_postProcessFieldArray is being called if it exists. Aparrently we have to make sure that our new class is also available as an instantiated object in just that array $hookObjectsArr.
The solution lies at the very beginning of the process_datamap function:
// First prepare user defined objects (if any) for hooks which extend this function:
$hookObjectsArr = array();
if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'])) {
foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'] as $classRef) {
$hookObjectsArr[] = &t3lib_div::getUserObj ($classRef);
}
}
As you can see, we just have to put our class name into the global variable called $TYPO3_CONF_VARS (this is also the recommended place for managing hooks in general). We will do that by adding one line to the ext_localconf.php of our extension:
$GLOBALS ['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = 'tx_myextension_tcemainprocdm';
Note that the ...php']['processDatamapClass'] variable is an array and we just add another value (our class name).
There is another thing we have to take care of: Make sure that the file containing our new class is loaded when it's going to be used in the hook. You could either add a require_once statement into the ext_tables.php of your extension - or, which is the reccomended way, use the following hint:
Hint: Include and register your class simultaneously
There is a nice feature in the getUserObj method which allows us to combine the two steps loading the file and registering the class: Instead of putting require_once into ext_tables.php and registering your class in ext_localconf.php, you may register your new class with a line like this (in ext_localconf.php):
$GLOBALS ['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = 'EXT:myextension/class.myextension_tcemainprocdm.php:tx_myextension_tcemainprocdm';
Another great advantage of this method is that your file will only be included if it's really used!
Hide page - Part I
Now we finally may create the actual implementation providing the new functionality. Let's have a look at our new function again:
function processDatamap_postProcessFieldArray ($status, $table, $id, &$fieldArray, &$reference) {
As you can see, the variable &$fieldArray was passed by reference, which means that we can modify it if we want! And we do want to change it: If there is a backend user logged in, not being member of a certain backend usergroup (namely the chief editor's group), we want to set the hidden field to 1.
if (!t3lib_div::inList ($reference->BE_USER->user['usergroup'], $chiefEditorsUsergroup)) {
if ($status == 'update' && $table == 'pages') {
$fieldArray['hidden'] = 1;
}
}
Through the $reference parameter, we have complete access to the parent object providing the hook. In our case we use TCEmain's variable BE_USER which contains an instance of the current backend user object.
Of course you will have to set $chiefEditorsUsergroup to some meaningful value ...
Hide page - Part II
That works just fine, however it doesn't really make sense yet. The page will only be hidden if someone not being the chief editor edits the page, that is: some record in the table pages. But what if someone modifies a content element being part of that page, how can we intercept that? Just like that:
class.tx_myextension_tcemain.php:
1:function processDatamap_postProcessFieldArray ($status,$table,$id,&$fieldArray,&$reference) {
2: if (!t3lib_div::inList ($reference->BE_USER->user['usergroup'], $chiefEditorsUsergroup)) {
3: if ($status == 'update' && $table == 'pages') {
4: $fieldArray['hidden'] = 1;
}
7: if ($status == 'update' && $table == 'tt_content') {
8: $row = t3lib_BEfunc::getRecord ($table, $id);
10: if (is_array ($row)) {
11: $dataArr = array ();
12: $dataArr['pages'][$row['pid']]['hidden'] = 1;
14: $tce = t3lib_div::makeInstance('t3lib_TCEmain');
15: $tce->start($dataArr, array());
16: $tce->process_datamap();
}
}
}
}
Noticed that we call process_datamap from the userfunction itsel?. We have to create a new instance of TCEmain (line 14) to achieve that.
Now, what if this hook was provided using t3lib_div::callUserFunc? The code in TCEmain would look similar to this:
if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapPostProcFieldArray'])) {
$_params = array (
'status' => $status,
'table' => $table,
'id' => $id,
'fieldArray' => &$fieldArray,
);
foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapPostProcFieldArray'] as $funcRef) {
$content .= t3lib_div::callUserFunction($funcRef, $params, $this);
}
}
Instead of passing the variables direktly to a method with a pre-defined name, they are stuffed into an array ($params) and passed to the user function through t3lib_div::callUserfunction. This doesn't look as nice as the other approach, see that?
To make things a bit shorter, I just summarize the changes to the different files below, I guess you get the point:
ext_localconf.php:
$GLOBALS ['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapPostProcFieldArray'][] = 'tx_myextension_tcemainprocdm->processDatamap_postProcFieldArray';
ext_tables.php:
require_once(t3lib_extMgm::extPath('myextension').'class.tx_myextension_tcemainprocdm.php');
class.tx_myextension_tcemainprocdm.php:
function processDatamap_postProcFieldArray (&$params, &$reference) {
if (!t3lib_div::inList ($reference->BE_USER->user['usergroup'], $requiredUsergroup)) {
if ($params['status'] == 'update' && $params['table'] == 'pages') {
$params['fieldArray']['hidden'] = 1;
}
if ($params['status'] == 'update' && $params['table'] == 'tt_content') {
$row = t3lib_BEfunc::getRecord ($params['table'], $params['id']);
if (is_array ($row)) {
$dataArr = array ();
$dataArr['pages'][$row['pid']]['hidden'] = 1;
$tce = t3lib_div::makeInstance('t3lib_TCEmain');
$tce->start($dataArr, array());
$tce->process_datamap();
}
}
}
}
Locate a possible hook in the script you want to extend. If there is none, suggest a new hook to the source's author
Create a new class for each function you want to extend
Create a method for each hook you want to use. It is named after the method called in the hook itself. Use the same interface for your function which is defined in the hook.
Register your class by adding your extension name, filename and classname to the appropriate place in the global $TYPO3_CONF_VARS
Study the source you want to extend and know what you are about to do!
make sure that your class containing the user function gets included (by require_once)
all parameters are passed in a single array, the second parameter contains a reference to the parent class.
You may collect all userfunctions in one big class, it's up to you.
The versions 13.4.4 and 12.4.26 of the TYPO3 Enterprise Content Management System have just been released.
In 2025, the Best Practices Team will have one remote day per month. We'll meet on TYPO3 Slack for a day of general housework and working through our…
When the much-improved functionality at docs.typo3.org was implemented, it still missed a nice-looking frontend. That work was completed by two French…
In this special episode of Inside TYPO3, we sit down with Marc Thiele, the founder and organizer of Beyond Tellerrand, to talk about the power of…
Still sticking to an older version of TYPO3? Today, 9.5.49, 10.4.48 and 11.5.42 have been released. Staying on top of maintenance updates should be a…
The versions 13.4.3 and 12.4.25 of the TYPO3 Enterprise Content Management System have just been released.