By Sebastiaan de Jonge, published on Friday, February 5, 2010 at 19:13

In my daily line of work I develop TYPO3 websites. Creating a website usually involves grabbing something from the TER, now because some customers have very... let's say 'exclusive' wishes 😉 what we find is not always what we really need. Most of the times we have some overkill features, or worse.. missing features.

Missing features

Once we need something that isn't there, it could qualify as a missing feature. Now there is three things you can do in this case.

  • Contact the extension developer(s) either through e-mail, forge or whatever you deem necessary. Ask them to think about implementing your feature. If this is something very specific of which only few or maybe even no other users may benefit, the answer to this will most likely be NO.
  • Another option would be to dig into the extension, start modifying things. Add you missing feature.. and your done! Downside of this that if there will ever be updates available for this extension, there's no way you are going to be able to update it. This can be a very dangerous trick when security issues arise, making your website vulnerable to attacks.
  • Now the best option would be (of course if they are available) to use so-called "Hooks".

What are hooks?

Hooks are small points inside a script or extension that allow you to execute your own code, usually with some parameters of the given code passed through the hook methods. They are usually located at strategical points, so they provide a lot of flexibility.

A real life example

On a website we are making use of the extension sr_feuser_register for front-end user registration. Now our customer wants to validate the address that is entered in this form. And he wants this to be done with some webservice over SOAP. So for some how we need to implement this feature inside sr_feuser_register because this is not something standard.

So to see if this is possible, we need to figure out how to insert this into the flow of the extension. The preferred option would be to do this with a hook. Usually available hooks can be found in the extension manual. This is also the case for this extension.

http://typo3.org/documentation/document-library/extension-manuals/sr_feuser_register/2.5.24/view/1/5/#id2495610

Finding your hook inside the code

However, the hook I will use in my example is not in the manual (or at least not at this section). Another good place to look would be inside the code! Searching for $hookObj, 'hook', $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'] or $TYPO3_CONF_VARS['EXTCONF'] will get you pretty close to finding them.

Basically, most hooks will look somewhat like this:

if (is_array($hookClassArray)) {
    foreach($hookClassArray as $classRef) {
        $hookObj= &t3lib_div::getUserObj($classRef);
        if (method_exists($hookObj, 'evalValues')) {
            $errorField = $hookObj->hookFunctionName($someVar, $anotherVar, $this);
            if ($errorField!='')    {
                $failureArray[] = $errorField;
            }
        }
    }
}

And what it does is actually not so complicated. The global on line 1 is simply a global array, that is looped through here. The array contains class references, which are called one by one as the array is looped through. Each class reference should have  the function 'hookFunctionName' in this case, which will be called by this process.

Class references

A class reference is, well a reference to a class (who would have guessed). Usually they are called in the same way, but I remember 1 example where this was different. Anyway, a class reference would look something like this:

$classRef = 'EXT:my_extension/pi1/class.tx_myextension_pi1.php:&tx_myextension_pi1';

If we dismember this string we will find the following:

  • EXT: - The path to our extension, for example typo3conf/ext/, this is automatically generated!
  • my_extension/pi1/ - The path to our code file, extension key followed by possible subfolders.
  • class.tx_myextension_pi1.php - The code file, this will contain the class and the hook function.
  • :&tx_myextension_pi1 - This is the reference (&) to our class. In this class the hook function should be!

Using a hook

So let's say we found are hook, and we want to start using it. There are things we will need to do. First of all we will need to create 'an extension'. The easiest way to do this is through the 'kickstarter'. Assuming that you know how to do this already, I will continue 😉

Just create a small extension, add a front-end plugin and insert it as 'Just include library'. This will make sure you extension is always included, and thereby accessible. When finished configuring your extension, write the result and install it.

 

Our next step will be to add the hook function to the class, together with the right parameters! If you are not sure about these parameters, or they are not documented, you can select the call from the original code. This way you are sure you will include all parameters. Just make sure that, if present, you change $this into something else.

public function evalValues(
    $theTable,
    $dataArray,
    $origArray,
    $markContentArray,
    $cmdKey,
    $requiredArray,
    $theField,
    $cmdParts,
    $caller
) {

Now that we have added our function, we need to make sure it's called when needed. To do this we have to add our class reference to the array. We do this by setting it in our extensions ext_localconf.php. It should look somewhat like this:

$TYPO3_CONF_VARS['EXTCONF']['tx_theextensionwewillhook_pi1']['postPreSomething'][] = 'EXT:tx_myextension/pi1/class.tx_myextension_pi1.php:&tx_myextension_pi1';

Since ext_tables.php and ext_localconf.php are both cached we will need to clear our configuration cache before this code is actually loaded. After this, we are ready to go.

Changing data with your hooks

In most occaisions, hooks allow you to change multiple sets of data. These are usually all passed as parameters to your function. Since a function can only return 1 value, most of the times hooks don't return anything. We can still change these variable by create references to them in our function.

Our original function will look like this:

public function addGlobalMarkers($markers, $parentObject)

If we would want to alter the items of $markers we should create a reference of it, instead of passing the entire array.

public function addGlobalMarks(&$markers, &$parentObject)

Now any changes made in $a_markers will also be passed on to the original.

No hook, or not the hook you need?

If you can't find the hook you need, sometimes you can use a combination of 2 or more hooks to still achieve the same result. Additionally you could send a request to the extension developer or on TYPO3 Forge for the placement of a hook on a certain position.

A real working example

At the bottom of this article you can download a small sample I have made just for this article. It's a small extension that applies 2 hooks. This time not in any extensions, but in the TYPO3 core. It will output 2 comments at the end of each page. One before content caching, and one after. This should get you kickstarted if you want to puzzle around a little with hooks.

Adding hooks to your own extension

Hooks are essential inflexibility, it allows others to extend to their needs. If you want to add hooks to your own extensions, make sure you put them in strategical locations. Before and after processes, on spots where global actions can be performed. 

Documenting the hooks and some examples of what can be done with them isn't a bad idea either. This will allow developers to find what they are looking for a lot quicker. Making them more likely to use your extension.

Comments

Alexandre
Alexandre - Thursday, April 1, 2010 at 10:05

Nice wrap-up !
Another solution, when there is no hook available, is to use XCLASSes.
It is less viable but anyway better than modifying directly the extension.

Rey
Rey - Thursday, October 28, 2010 at 05:05

HiThis post is great but since i'm newbie to typo3 can u plz post with little etail steps with an example

Thanks

Rey