TYPO3 Romania, Magento, eCommerce, webdesign, content management systems

partial code snapshot

Writing TYPO3 backend hooks into your own extensions

Let's assume you have created a simple frontend plugin. Let's also assume this extension has 1 table. Let's call this table "paintings". Let's say that you also have a table called "history", and for the sake of a working sample, let's say that the client adds table records in a sysfolder in the backend, using the "List" tool in the "Web" module.

Now, what the client might want in this case is to write in the history log anytime you do a particular change to a painting. So, if an editor changes the status of a painting, say, set it from stock to sold, your client wants to add the change in the log, so he can look at the painting history anytime he wants, and this way he can see all the changes to the painting that interest him. And the examples for such a scenario could go on

The main thing though is that you need a way to hook onto the "Save", "Save and close" or "Save and add new record" buttons for every record. Or maybe to some other functionality, it's your choice in the end. So when your editor hits "Save", you need to be able to add your own functionality that stores data in the history table too. In TYPO3, hooking such functions is done using, well, hooks.

For general requirements, some hooks are already built in, so all you have to do is extend them, and this is what we will do in this case, extend an existing hook.

If you want to search for available hooks in the core files or extension files, you can use the extension dmc_hooklist (from TER), or you can take a look at the currently extended hooks by looking at Admin Tools > Configuration > $TYPO3_CONF_VARS in the backend.

In our case, we need to extend the $TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php'] array. Why do we use the TCEMAIN class? Because, according to the docs:

The TYPO3 Core Engine is the class that handles all data writing to database tables configured in $TCA. In addition the class handles commands such as copy, move, delete. It will handle undo/history and versioning of records as well and everything will be logged to the sys_log. And it will make sure that write permissions are evaluated correctly for the user trying to write to the database. Generally, any processing specific option in the $TCA array is handled by TCE.

Since we are writing the history each time a record is saved (writing to the database), we're extending a TCEMAIN hook. And the hook used to save data is called "processDatamapClass".

We are going to write our hook using the "getUserObj" way, and here are the required steps to do it.

In your extension directory:

1. create a file called class.tx_EXTENSIONNAME_tcemainprocdm.php. Here you will be placing the hook code.

2. in the extension's ext_localconf.php file, place this line at the end...

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = 'EXT:rm_stock/class.tx_EXTENSIONNAME_tcemainprocdm.php:tx_EXTENSIONNAME_tcemainprocdm';

So basically in ext_localconf.php is the link between the hook name and the hook code. This is how TYPO3 knows what code to call when it processes the existing "processDatamapClass" hooks.

As for the code, let's just enter some simple processing code in our newly created PHP file (class.tx_EXTENSIONNAME_tcemainprocdm.php)

<?php

class tx_EXTENSIONNAME_tcemainprocdm {
    function processDatamap_postProcessFieldArray ($status, $table, $id, &$fieldArray, &$reference) {
    // $table is the current table being processed
    // $id is the record's id (uid field)
    // $fieldArray has all the fields that have BEEN CHANGED, so not all the fields, just those that have been updated
    // $reference is a reference to the currently calling object, the object that calls this hook
   // In our case, let's write a simple example that checks for our table, and outputs the changed data to the screen, what you do from here on, it depends on the desired functionality...

    if ($table == 'paintings')
    {
       echo "This is the fieldArray data";
       print_r($fieldArray);
       echo "Do something with painting with uid $uid";
    }

    }
  }

?>

Important! Please note that the hook above is executed BEFORE data is being saved in the database (the painting data). $fieldArray is sent as a reference, so it CAN be changed, and this way you can save different data in the database.

For example, let's say your painting stores the status, and the owner. But if your editor sets the painting status to 0 (zero), which means "In Stock", then you want the current owner to be set to 0 (zero) too, without the editor having to do that himself. So, in your hook, you can write something like this...

if ($fieldArray['status'] == 0)
  $fieldArray['owner'] = 0;

and this way, your owner would be removed whenever the painting status is set to be in stock.

I hope you get the picture. If not, have a look at the documentation below.

Further reading: