DEPRECATION WARNING

This documentation is not using the current rendering mechanism and is probably outdated. The extension maintainer should switch to the new system. Details on how to use the rendering mechanism can be found here.

User TCA types and bidirectional MM tables

Author:Kasper Skårhøj
Created:2002-11-01T00:32:00
Changed:2007-03-07T16:25:08
Author:René Fritz
Email:r.fritz@colorcube.de
Info 3:
Info 4:

User TCA types and bidirectional MM tables

Extension Key: mmforeign

Copyright 2006-2007, René Fritz, <r.fritz@colorcube.de>

This document is published under the Open Content License

available from http://www.opencontent.org/opl.shtml

The content of this document is related to TYPO3

- a GNU/GPL CMS/Framework available from www.typo3.com

Table of Contents

User TCA types and bidirectional MM tables 1

Introduction 1

Installation 2

Developers section 2

Configuration (bidirectional) 3

Tutorial 3

Known problems 5

To-Do list 5

Changelog 5

Introduction

What does it do?

With TYPO3 V4.1 this extension is not needed anymore to extended MM table handling for the standard field types like 'group' and 'select', used by DAM for example.

This extension change parts of the TYPO3 core (TCE) to allow the implementation of other field types than the default like input, select and group. While rendering of fields is already possible with a user function it is not the case for the database handling itself. TCE offers a standard set of fields types and that's it. Now you can implement your own field types, means the database handling of it.

As example implementation of a field type this extension introduces the concept of bidirectional MM relations to the TYPO3 framework.

NOTE: This extension is only useful for programmers who wish to implement own field types or bidirectional relations in their extension tables. This extension by itself do nothing until another extension use it. You should only go on reading this if you have some experience with extension programming.

Bidirectional MM relations

MM relations are already used in many extensions as a mean of establishing a “link” between two tables. For further reading about this see the TYPO3 Core APIs section 4 about the Table Configuration Array (TCA). Since I assume that you already have some knowledge about programming extensions for the TYPO3 framework I will not go into detail on how this works.

The problem at hand

MM-relations in TYPO3s backend were only singledirectional. To explain what this means, take this example:

You have two tables, tx_myext_table1 and tx_myext_table2 . In tx_myext_table1 you have configured a field of type “select”. The item array of this select field is filled with records from t x_myext_table2 by using an MM relation. For this purpose a third “join”-table tx_myext_table1_table2_mm is used.

In order to find any relations TYPO3 expects the tx_myext_table1_table2_mm to contain the following fields:

uid_local - this points to the uid of the local table (tx_myext_table1). uid_foreign – this points to the uid of the foreign table (tx_myext_table2).

So far everything is good. You can view, edit and delete relations between the two tables - but only from the local table´s point of view . Now, what if you wanted to create a “select” field in the tx_myext_table2 which was populated with records from the tx_myext_table1 using the same “join” table ( tx_myext_table1_table2_mm) ? The short answer to that question is: You can't.

To give you a real world example, take a look at the tt_news extension. You can open a single tt_news record and assign it to one or more categories. But you can't open a category and select which tt_news records should be assigned to it.

This is were this extension comes in. It allows you to create “select” and “group” fields that uses the uid_local field in the “join” table to lookup records in the foreign table.

History

The code of this extension has some history. It was part of the DAM extension, needed to provide mm relations of DAM records to other tables like content elements. The code didn't made it into the 4.0 Version of TYPO3 mainly because nobody was able to review it. That's why it is put into it's own extension, which has some disadvantages (see section Installation).

Mads Brunn published the extension “bidirectional” which basically provide the same functionality. That's why I borrowed his extension manual content and modified it to fit for this extension.

The solution provided by this extension is a bit more flexible than “bidirectional” and has different configuration values, but it is also more complex.

After all the code was transformed to a more flexible solution. Now there's an interface in TCE to implement own field types and the bidirectional solution is just an implementation of a new field type.

Installation

There's nothing special to mention for installation, but the extension installs three XCLASSes the administrator should know about:

  • t3lib/class.t3lib_transferdata.php
  • t3lib/class.t3lib_tcemain.php

Using XCLASS is a way of changing core functions with an extension. This can work without problems but shouldn't be used generally and is more like a workaround.

When another extension installs an XCLASS for one of the mentioned files the whole functionality will break and database relations might be lost.

In a previous version of this extension the bidirectional functionality was patched (XCLASS) directly into the TYPO3 core. Now the changes made by the XCLASSes are very small in comparison. That means the default behavior of TCE shouldn't be affected in any way.

During installation one can choose to use the old XCLASSes which is deprecated!

Developers section

As said the extension provide an interface to allow the implementation of new TCE field types. An example implementation is included. A full documentation of the functionality can't be provided as it just too much to cover all topics. So this just an introduction.

Implementing a field type for TCE means to provide functions for converting data from the database for usage in backend forms (TCEforms) and converting the submitted form data for database storage or even write the data to the database.

In principle that can be done with a 'user' type in TCA and a user function for form rendering. But this will not work when database relations needs to be handled because the form data will be written to db as it is by TCE. That's where we need own functions when the default TCE fields don't provide the needed functionality.

To activate a so called userProcessClass for a field you have to add an entry in TCA like following:

'config' => array (
     'userProcessClass' => 'EXT:mmforeign/class.tx_mmforeign_tce.php:tx_mmforeign_tce',

A userProcessClass can (but don't must) provide following methods:

renderRecord_procField()
checkValue()
copyRecord_procField()
remapListedDBRecords_procField()

For details have a look into the example implementation. The methods have similar names like the methods in TCEmain so it is possible to have a look into the core how field handling work there.

Implementing all methods might not be needed, it depends on the data format (releations) and what's needed. For example renderRecord_procField() could be excluded when the data format coming from the database is already in expected format or a needed transformation will be done in a TCEforms user function.

When a method is not implemented the data will be passed through, which means it will not be touched by another TCE function.

Another example could be that only form data processing is wanted. Then checkValue() have to be implemented.

Configuration (bidirectional)

To enable the bidirectional MM handling for a field add in the TCA config section of the field:

"userProcessClass" => "EXT:mmforeign/class.tx_mmforeign_tce.php:tx_mmforeign_tce",

The extension works by extending the way you configure MM relations in the TCA for fields of type “select” and “group”.

((generated))

Addition to Core API'ssection 4.2.9 ['columns'][fieldname]['config'] / TYPE: "select"section 4.2.10 ['columns'][fieldname]['config'] / TYPE: "group")
MM_foreign_select

Key

MM_foreign_select

Datatype

boolean

Description

If set the uid_local field will be used to lookup foreign records instead of uid_foreign.

Scope

Proc.

MM_match_fields

Key

MM_match_fields

Datatype

array

Description

Defines field/value pairs that will be used for read and update queries of the MM table.

'MM_match_fields' => array('ident' => 'category'),

Scope

Proc.

MM_insert_fields

Key

MM_insert_fields

Datatype

array

Description

Defines field/value pairs that will be written to the MM table when a relation is written.

'MM_insert_fields' => array('a_field' => 'a value'),

Scope

Proc.

MM_table_where

Key

MM_table_where

Datatype

string

Description

This is a where clause which is included in MM table queries.

Scope

Proc.

prepend_tname

Key

prepend_tname

Datatype

boolean

Description

If set the table name of the relation is stored in the MM tables field “tablenames”.

Scope

Proc.

Tutorial

Example 1: Adding a bidirectional field in tt_news

In this section I will go through an example of how to use bidirectional MM relations. This example extends the tt_news extension by adding a bidirectional field to the tt_news_cat table.

Creating the field in the database

We start by creating the field in the database:

#
# Table structure for table 'tt_news_cat'
#
CREATE TABLE tt_news_cat (
        tx_mmforeignexample_tt_news int(11) DEFAULT '0' NOT NULL
);
Configuring the field

Next, we configure the field and adds it to the $TCA:

 0: <?php
 1: if (!defined ('TYPO3_MODE'))     die ('Access denied.');
 2: $tempColumns = Array (
 3:     "tx_bidirectionalexample_tt_news" => Array (
 4:         "exclude" => 1,
 5:         "label" => "News in this category",
 6:         "config" => Array (
 7:             "type" => "select",
 8:             "userProcessClass" => "EXT:mmforeign/class.tx_mmforeign_tce.php:tx_mmforeign_tce",
 9:             "foreign_table" => "tt_news",
10:             "foreign_table_where" => "ORDER BY tt_news.crdate",
11:             "size" => 10,
12:             "minitems" => 0,
13:             "maxitems" => 100,
14:             "MM" => "tt_news_cat_mm",
15:             "MM_foreign_select" => 1,
16:         )
17:     ),
18: );
19: t3lib_div::loadTCA("tt_news_cat");
20: t3lib_extMgm::addTCAcolumns("tt_news_cat",$tempColumns,1);
21: t3lib_extMgm::addToAllTCAtypes("tt_news_cat","tx_mmforeignexample_tt_news;;;;1-1-1");
22: ?>

Notice the syntax of line 8 and 15.

Example 2: Using additional fields in MM table

Uncommented example that might not make real sense. Just to show how to use an additional field in MM tables.

#
# Table structure for table 'tx_example_item_mm'
#
CREATE TABLE tx_example_item_mm (
  uid_local int(11) DEFAULT '0' NOT NULL,
  uid_foreign int(11) DEFAULT '0' NOT NULL,
  tablenames varchar(30) DEFAULT '' NOT NULL,
  ident varchar(30) DEFAULT '' NOT NULL,
  sorting int(11) unsigned DEFAULT '0' NOT NULL,
  KEY uid_local (uid_local),
  KEY uid_foreign (uid_foreign)
);
$TCA['tx_example_item'] = array(
...
        'columns' => array(
                'category' => array(
                        'label' => 'Category:',
                        'config' => array (
                                'type' => 'group',
                             'userProcessClass' => 'EXT:mmforeign/class.tx_mmforeign_tce.php:tx_mmforeign_tce',
                                'internal_type' => 'db',
                             'allowed' => 'tx_example_category',
                             'prepend_tname' => 1,
                             'MM' => 'tx_example_item_mm',
                             'MM_match_fields' => array('ident' => 'category'),
                                'size' => 3,
                                'maxitems' => 200,
                                'minitems' => 0,
                        )
                ),

$TCA['tx_example_category'] = array(
...
        'columns' => array(
                'related' => array(
                        'label' => 'Category:',
                        'config' => array (
                                'type' => 'group',
                             'userProcessClass' => 'EXT:mmforeign/class.tx_mmforeign_tce.php:tx_mmforeign_tce',
                                'internal_type' => 'db',
                             'allowed' => 'tx_example_item',
                             'prepend_tname' => 1,
                             'MM' => 'tx_example_item_mm',
                             'MM_foreign_select' => 1,
                             'MM_match_fields' => array('ident' => 'category'),
                                'size' => 3,
                                'maxitems' => 200,
                                'minitems' => 0,
                        )
                ),

Known problems

((generated))

t3lib_refindex

The class of TYPO3 V4 don't work correctly with foreign MM relations (when core is patched). Means the relation is stored twice. This is because of a hash calculation including the sorting which makes no sense to me.

Anyway t3lib_refindex is unsupported and might produce unexpected results for userProcessClass fields.

To-Do list

- Find somebody who will make this part of the core.

Changelog

- Implemented an interface in TCEmain and make 'bidirectional' use of it. Much cleaner.

img-1 User TCA types and bidirectional MM tables - 5