DEPRECATION WARNING

This documentation is not using the current rendering mechanism and will be deleted by December 31st, 2020. The extension maintainer should switch to the new system. Details on how to use the rendering mechanism can be found here.

EXT: Tutorial for Inline Relational Record Editing (IRRE)

Author:Kasper Skårhøj
Created:2002-11-01T00:32:00
Changed by:Oliver Hader
Changed:2007-03-07T08:38:12
Author:Oliver Hader
Email:oh@inpublica.de
Info 3:
Info 4:

EXT: Tutorial for Inline Relational Record Editing (IRRE)

Extension Key: irre_tutorial

Copyright 2006-2007, Oliver Hader, <oh@inpublica.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

EXT: Tutorial for Inline Relational Record Editing (IRRE) 1

Introduction 1

What does it do? 1

Screenshots 1

Tutorial 2

Reusing “select” type for 1:n relations 2

Normalized data structure for 1:n relations 3

Intermediate tables for m:n relations 5

Appearance settings for TCEforms 11

Use Page Tsconfig to override TCA setting 14

Known problems 15

To-Do list 15

Changelog 15

Introduction

What does it do?

Inline Relational Record Editing (IRRE) is a new practice in editing more complex data structures with repetive subsections in just one backend view. New records are created using AJAX technology. Persistant data storage is preferably done by a normalized data model.

IRRE is part of the TYPO3 Core since version 4.1. The allowed TCA configuration reference can be found in the TYPO3 Core Doc API at http://typo3.org/documentation/document-library/core- documentation/doc_core_api/current/view/

The section “Tutorial” is part of the diploma thesis submitted by Oliver Hader in February 2007. You can get the complete diploma thesis at the following URL as PDF: http://typo3.org/development/projects/irre/

Screenshots

Inline Relational Record Editing offers a form-in-a-form solution to handle multidimensional data structures. The following extract of a screenshot is just an introduction. Images concerning each single configuration issue are located at the following “Tutorial” section.

img-1

Tutorial

The following case-study is used in this tutorial to explain the configurable behavior of Inline Relational Record Editing:

The website of a travel business inherits contents of almost 300 different hotels. It has to be possible to create and manage this data using the TYPO3 back-end. Furthermore a hotel consists of different offers, such as a “wellness special” or “relax weekend”. Additionally every single one of these offers can vary in price depending on the season customers chooses to book. Finally this results in a structure spanning three levels, beginning with one hotel as parent, many offers as first generation and also many prices as second generation. Each generation mentioned depends on the previous generation. This scenario is known as a composition of the cardinality 1:n.

img-2 Figure 1: Composition of involved entities

Reusing “select” type for 1:n relations

Simple 1:n relations, between one parent and many other children have formerly being realised using the TCA type “select”. The UIDs were stored in a comma separated list in one field on the parent table. The sequence of numbers in this list was finally the sorting order of all affected child records as well.

 1: $TCA["tx_irretutorial_1ncsv_hotel"] = Array (
 2:     ...
 3:     "columns" => Array (
 4:         "title" => Array (
 5:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_hotel.title",
 6:             "config" => Array (
 7:                 "type" => "input",
 8:                 "size" => "30",
 9:             )
10:         ),
11:         "offers" => Array (
12:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_hotel.offers",
13:             "config" => Array (
14:                 "type" => "select",
15:                 "foreign_table" => "tx_irretutorial_1ncsv_offer",
16:                 “foreign_table_where” =>
17:                     “AND tx_irretutorial_1ncsv_offer.pid=###CURRENT_PID###
18:                     ORDER BY tx_irretutorial_1ncsv_offer.title”,
19:                 "maxitems" => 10,
20:             )
21:         ),
22:     ),
23:     ...
24: );

The TCA type “select” defines the table of children by using the property “foreign_table”. The disadvantage is that child records had to exist before they could used to build a relationship to a parent record.

The new TCA type “inline” inherits the functionalities of Inline Relational Record Editing. It now allows to create new child records even if the parent record is a new one and was not saved before.

 1: $TCA["tx_irretutorial_1ncsv_hotel"] = Array (
 2:     ...
 3:     "columns" => Array (
 4:         "title" => Array (
 5:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_hotel.title",
 6:             "config" => Array (
 7:                 "type" => "input",
 8:                 "size" => "30",
 9:             )
10:         ),
11:         "offers" => Array (
12:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_hotel.offers",
13:             "config" => Array (
14:                 "type" => "inline",
15:                 "foreign_table" => "tx_irretutorial_1ncsv_offer",
16:                 "maxitems" => 10,
17:             )
18:         ),
19:     ),
20:     ...
21: );

Only the type definition changed from “select” to “inline”. The disposal of the property “foreign_table” equals TCA type “select”. This is the simplest way to migrate to Inline Relational Record Editing without losing old relations.

Normalized data structure for 1:n relations

Relations in a list of UIDs cannot be selected directly by a query on a database. Thus it is even better to use a normalized way of storing the relational information. In the sequential approach of the previous section the child records do not even know the UID of their parent. To get a subset of children, first the parent has to be loaded and processed. After that step all related child records have to be fetched and finally these results could be narrowed to get the designated subset.

In a normalized 1:n context, the UID of the parent record is stored in a separate field on every child record. This allows to directly acquire a subset of children related to an ancestor. Before Inline Relational Record Editing was available this could possibly be done by using an individual wizard. The wizard opened a pop-up window and offered the possibility to create a new child record. The UID of the parent was written to a defined field on the database table by clicking the save-button.

This solution comes close to Inline Relational Record Editing, but unnecessarily opens new windows. Imagine a structure of four different levels. To initially create top down the required entities there would be one main back-end view and additionally three pop-up windows.

 1: $TCA["tx_irretutorial_1nff_hotel"] = Array (
 2:     ...
 3:     "columns" => Array (
 4:         "title" => Array (
 5:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_hotel.title",
 6:             "config" => Array (
 7:                 "type" => "input",
 8:                 "size" => "30",
 9:             )
10:         ),
11:         "offers" => Array (
12:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_hotel.offers",
13:             "config" => Array (
14:                 "type" => "inline",
15:                 "foreign_table" => "tx_irretutorial_1nff_offer",
16:                 "foreign_field" => "parentid",
17:                 "foreign_table_field" => "parenttable",
18:                 "maxitems" => 10,
19:             )
20:         ),
21:     ),
22: );
23: $TCA["tx_irretutorial_1nff_offer"] = Array (
24:     "columns" => Array (
25:         "parentid" => Array (
26:             "config" => Array (
27:                 "type" => "passthrough",
28:             )
29:         ),
30:         "parenttable" => Array (
31:             "config" => Array (
32:                 "type" => "passthrough",
33:             )
34:         ),
35:         "title" => Array (
36:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_offer.title",
37:             "config" => Array (
38:                 "type" => "input",
39:                 "size" => "30",
40:             )
41:         ),
42:     ),
43: );

The field “offers” defines that of the accordant “foreign_table”. The property “foreign_field” tells the system to store the UID of the parent record in the defined field on the child record. The key “foreign_table_field” defines the field on the child side that stores the table name of the parent record. In this case it would be “tx_irretutorial_1nff_hotel”.

When the parent record is completely identified by its UID and table name on the child side this is also called a “weak entity”. Thus the accordant child record knows its parent.

img-1 Figure 2: Example view of 1:n relations

Intermediate tables for m:n relations

It could be required to have the possibility that child records can be associated to different parent records and vice versa. In this case the disposal of an intermediate table is necessary. It contains only the information concerning the relation itself.

Before IRRE was integrated TYPO3 supported the so-called MM-Relations (many-to-many) to handle this. MM relations have a very limited structure. It is not possible to edit a record of a MM table directly. Furthermore no history/undo functionality is available for MM relations.

IRRE offers a new way to get a more flexible approach. Intermediate tables are now used to have a regular TCA definition. This includes the existence of UID, PID, timestamp and some other default fields. Thus modifications on a relationship can be reverted to a former state.

To apply this functionality an additional table is required – the intermediate table. Auxiliary the involved entities have to refer to that foreign table and must define in which field their UID information shall be lodged.

The standard deployment on intermediate tables are bidirectional relations. “Bidirectional” describes the way a relationship between two objects can be visualized. In this case a parent record can see its children and vice versa a child knows about its parents.

Bidirectional asymmetric m:n relations

Asymmetric behaviour of relations is the most common rule. The condition for a relation to be asymmetric is that two different tables are affected. The opposite is a symmetric relation which is described in the following section. To get a step-by-step introduction we just relate hotels to offers and care about prices later on.

img-3 Figure 3: UML scheme of simple bidirectional asymmetric relations

The prefix “tx_irretutorial_...” of each table is missing in the UML scheme to get a better overview. “hotel_offer_rel” is the intermediate table with the information which hotel is related to which offer and vice versa.

 1: $TCA["tx_irretutorial_mnasym_hotel"] = Array (
 2:     ...
 3:     "columns" => Array (
 4:         "title" => Array (
 5:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_hotel.title",
 6:             "config" => Array (
 7:                 "type" => "input",
 8:                 "size" => "30",
 9:             )
10:         ),
11:         "offers" => Array (
12:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_hotel.offers",
13:             "config" => Array (
14:                 "type" => "inline",
15:                 "foreign_table" => "tx_irretutorial_mnasym_hotel_offer_rel",
16:                 "foreign_field" => "hotelid",
17:                 "foreign_sortby" => "hotelsort",
18:                 "foreign_label" => "offerid",
19:                 "maxitems" => 10,
20:             )
21:         ),
22:     ),
23: );
24: $TCA["tx_irretutorial_mnasym_hotel_offer_rel"] = Array (
25:     "columns" => Array (
26:         "hotelid" => Array (
27:             "label" => "LLL:EXT:[locallang-path]:tx_irretutorial_hotel_offer_rel.hotelid",
28:             "config" => Array (
29:                 "type" => "select",
30:                 "foreign_table" => "tx_irretutorial_mnasym_hotel",
31:                 "maxitems" => 1,
32:             )
33:         ),
34:         "offerid" => Array (
35:             "label" => "LLL:EXT:[locallang-path]:tx_irretutorial_hotel_offer_rel.offerid",
36:             "config" => Array (
37:                 "type" => "select",
38:                 "foreign_table" => "tx_irretutorial_mnasym_offer",
39:                 "maxitems" => 1,
40:             )
41:         ),
42:         "hotelsort" => Array (
43:             "config" => Array (
44:                 "type" => "passthrough",
45:             )
46:         ),
47:         "offersort" => Array (
48:             "config" => Array (
49:                 "type" => "passthrough",
50:             )
51:         ),
52:     ),
53: );
54: $TCA["tx_irretutorial_mnasym_offer"] = Array (
55:     ...
56:     "columns" => Array (
57:         "title" => Array (
58:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_offer.title",
59:             "config" => Array (
60:                 "type" => "input",
61:                 "size" => "30",
62:             )
63:         ),
64:         "hotels" => Array (
65:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_offer.hotels",
66:             "config" => Array (
67:                 "type" => "inline",
68:                 "foreign_table" => "tx_irretutorial_mnasym_hotel_offer_rel",
69:                 "foreign_field" => "offerid",
70:                 "foreign_sortby" => "offersort",
71:                 "foreign_label" => "hotelid",
72:                 "maxitems" => 10,
73:             )
74:         ),
75:     ),
76: );

The TCA source code example from above implements the structure shown in Figure 3. The field to inherit the functionality of Inline Relational Record Editing is set to manage children of the intermediate table by “foreign_table” instead of the offer table directly. The UID of the parent record will be written to the “foreign_field” on the intermediate table. Furthermore manual sorting and the field to hold this information is defined.

“foreing_label” tells TCEforms from which field the specific record title should be generated. In this case the field “offerid” of the intermediate table is used which holds records of the entity “offer”. Thus the title of the related offer record will be shown inside the hotel record. If the optional setting “foreign_label” is missing, TCEforms shows the default label defined in $TCA[<table>]['ctrl']['label'].

The field “hotelid” on the intermediate table stores the UID of the parent hotel. It is set to be of TCA type “select” and is pointing back to its own table. The field “offerid” works similar. But it is very important that these two fields only allow a maximum of one item to be selected (“maxitems” must be set to one). Thus it would also be possible to edit the record of the intermediate table directly.

img-4 Figure 4: Editing relation on intermediate table directly

Figure 4 shows the possibility of directly selecting one hotel and one offer that should be related to each other. Of course it doesn't make any sense to edit the intermediate table directly. This is just to transfer the idea and behaviour behind Inline Relational Record Editing. Since the price depends on on the offer of a hotel it concerns only the relationship. The solution to integrate prices in this scheme is to define them as an attribute on the intermediate table used for hotels and offers.

img-5 Figure 5: UML scheme of extended bidirectional asymmetric relations

 1: $TCA["tx_irretutorial_mnasym_hotel_offer_rel"] = Array (
 2:     ...
 3:     "columns" => Array (
 4:         ...
 5:         "prices" => Array (
 6:             "label" => "LLL:EXT:[locallang-path]:tx_irretutorial_hotel_offer_rel.prices",
 7:             "config" => Array (
 8:                 "type" => "inline",
 9:                 "foreign_table" => "tx_irretutorial_mnasym_price",
10:                 "foreign_field" => "parentid",
11:                 "maxitems" => 10,
12:             )
13:         ),
14:         ...
15:     ),
16:     ...
17: );
18: $TCA["tx_irretutorial_mnasym_price"] = Array (
19:     ...
20:     "columns" => Array (
21:         "parentid" => Array (
22:             "config" => Array (
23:                 "type" => "passthrough",
24:             )
25:         ),
26:         "title" => Array (
27:             "exclude" => 1,
28:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_price.title",
29:             "config" => Array (
30:                 "type" => "input",
31:                 "size" => "30",
32:                 "eval" => "required",
33:             )
34:         ),
35:         "price" => Array (
36:             "exclude" => 1,
37:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_price.price",
38:             "config" => Array (
39:                 "type" => "input",
40:                 "size" => "30",
41:                 "eval" => "double2",
42:             )
43:         ),
44:     ),
45: );

The field “price” is used as new attribute on the intermediate table used for hotels and offers. The utilization of attributes in general is explained in the following section “Attributes for each m:n relation”.

The field “price” is of the TCA type “inline” again to allow the integration of several child records. It is used to be a normalized 1:n relation like described in “Normalized data structure for 1:n relations” in a previous section.

Bidirectional symmetric m:n relations

A special case of bidirectional asymmetric relations are symmetric relations. The adjective symmetric describes the self referencing property to the same table. It could be demanded, that entities of the same type have a relationship. Symmetric m:n relations handle this situation.

The travel business case-study will not be left for an example: A relationship between one or more hotels to each other as branch offices shall be achieved. Indeed a better matching task would be the representation of a family. The husband is married to its spouse and both have two children. All involved objects are of the same type – they are humans or persons. Every relation is bidirectional symmetric.

 1: $TCA["tx_irretutorial_mnsym_hotel"] = Array (
 2:     ...
 3:     "columns" => Array (
 4:         "title" => Array (
 5:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_hotel.title",
 6:             "config" => Array (
 7:                 "type" => "input",
 8:                 "size" => "30",
 9:             )
10:         ),
11:         "branches" => Array (
12:             "label" => "LLL:EXT:[locallang-path]:tx_irretutorial_hotel.branches",
13:             "config" => Array (
14:                 "type" => "inline",
15:                 "foreign_table" => "tx_irretutorial_mnsym_hotel_rel",
16:                 "foreign_field" => "hotelid",
17:                 "foreign_sortby" => "hotelsort",
18:                 "foreign_label" => "branchid",
19:                 "symmetric_field" => "branchid",
20:                 "symmetric_sortby" => "branchsort",
21:                 "symmetric_label" => "hotelid",
22:                 "maxitems" => 10,
23:             )
24:         ),
25:     ),
26: );
27: $TCA["tx_irretutorial_mnsym_hotel_rel"] = Array (
28:     ...
29:     "columns" => Array (
30:         "hotelid" => Array (
31:             "label" => "LLL:EXT:[locallang-path]:tx_irretutorial_hotel_rel.hotelid",
32:             "config" => Array (
33:                 "type" => "select",
34:                 "foreign_table" => "tx_irretutorial_mnsym_hotel",
35:                 "maxitems" => 1,
36:             )
37:         ),
38:         "branchid" => Array (
39:             "label" => "LLL:EXT:[locallang-path]:tx_irretutorial_hotel_rel.branchid",
40:             "config" => Array (
41:                 "type" => "select",
42:                 "foreign_table" => "tx_irretutorial_mnsym_hotel",
43:                 "maxitems" => 1,
44:             )
45:         ),
46:         "hotelsort" => Array (
47:             "config" => Array (
48:                 "type" => "passthrough",
49:             )
50:         ),
51:         "branchsort" => Array (
52:             "config" => Array (
53:                 "type" => "passthrough",
54:             )
55:         ),
56:     ),
57: );

The field “branches” links to the intermediate table but defines two pointer fields “foreign_field” and “symmetric_field”. The UID of the current main record will be set to one of these fields according to which record initially created the record in the intermediate table. The we edit the creator the “foreign_field” is used. If we edit the related record the “symmetric_field” is used.

The disposal of “foreign_sortby” and “symmetric_sortby” equals the previously mentioned behaviour.

The pointer fields “hotelid” and “branchid” resemble the bidirectional asymmetric approach. Both fields are pointing back to the same table of the entity “hotel” in this case however.

img-6 Figure 6: Bidirectional symmetric m:n relations of hotels

Attributes for each m:n relation

The utilization of standard TCA instead of the standard MM style to implement intermediate tables offers the possibility to use custom attributes for each relation. A new attribute simply has to be added in the TCA of the intermediate table and the SQL table definition. Rendering and data handling is done by the TYPO3 Core Engine further.

In the following example the relation between hotels and offers are attributed by a select field to define quality and a check box to denote an all-inclusive offer.

img-7 Figure 7: Edit attributes for each relation

 1: $TCA["tx_irretutorial_mnattr_hotel_offer_rel"] = Array (
 2:     ...
 3:     "columns" => Array (
 4:         "hotelid" => Array (...),
 5:         "offerid" => Array (...),
 6:         "hotelsort" => Array (...),
 7:         "offersort" => Array (...),
 8:         "quality" => Array (
 9:             "label" => "LLL:EXT:[locallang-path]:tx_irretutorial_hotel_offer_rel.quality",
10:             "config" => Array (
11:                 "type" => "select",
12:                 "items" => Array (
13:                     Array("(1 star) *", "1"),
14:                     Array("(2 stars) **", "2"),
15:                     Array("(3 stars) ***", "3"),
16:                     Array("(4 stars) ****", "4"),
17:                     Array("(5 stars) *****", "5"),
18:                 ),
19:             )
20:         ),
21:         "allincl" => Array (
22:             "label" => "LLL:EXT:[locallang-path]:tx_irretutorial_hotel_offer_rel.allincl",
23:             "config" => Array (
24:                 "type" => "check",
25:             )
26:         ),
27:     ),
28: );

The fields “quality” and “allincl” define regular TCA types to be used as attributes on each relationship between hotels and offers. The new TCA type “inline” could also be used in this case (see the example to integrate prices in the previous section “Bidirectional symmetric m:n relations”).

Using a record selector

Record selectors support the editor to create relations to a given set of elements. A selector could be a simple selector-box or an element browser. The selector-box implements the TCA type “select” and shows records which are globally available. The element browser uses the TCA type “group” with the subtype “db”. It opens a new pop-up window which shows the page structure and enables to select records from the accordant page.

 1: $TCA["tx_irretutorial_mnasym_hotel"] = Array (
 2:     ...
 3:     "columns" => Array (
 4:         ...
 5:         "offers" => Array (
 6:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_hotel.offers",
 7:             "config" => Array (
 8:                 "type" => "inline",
 9:                 "foreign_table" => "tx_irretutorial_mnasym_hotel_offer_rel",
10:                 "foreign_field" => "hotelid",
11:                 “foreign_selector” => “offerid”,
12:                 "foreign_sortby" => "hotelsort",
13:                 "foreign_label" => "offerid",
14:                 "maxitems" => 10,
15:             )
16:         ),
17:     ),
18: );
19: $TCA["tx_irretutorial_mnasym_hotel_offer_rel"] = Array (
20:     "columns" => Array (
21:         "hotelid" => Array (
22:             "label" => "LLL:EXT:[locallang-path]:tx_irretutorial_hotel_offer_rel.hotelid",
23:             "config" => Array (
24:                 "type" => "select",
25:                 "foreign_table" => "tx_irretutorial_mnasym_hotel",
26:                 "maxitems" => 1,
27:             )
28:         ),
29:         "offerid" => Array (
30:             "label" => "LLL:EXT:[locallang-path]:tx_irretutorial_hotel_offer_rel.offerid",
31:             "config" => Array (
32:                 "type" => "select",
33:                 "foreign_table" => "tx_irretutorial_mnasym_offer",
34:                 "maxitems" => 1,
35:             )
36:         ),
37:     ),
38: );

The most significant change is the inclusion of the parameter “foreign_selector”. In this case the field “offerid” is part of the intermediate table which was defined to be the “foreign_table”. Thus the record-selector will show available entries of the “offer” table.

img-8 Figure 8: Using a record selector to create relations

Define uniqueness on relations

Relations between entities should possibly be unique. Concerning our case-study it doesn't make any sense to build a relation from a hotel to the same offer more than once. In this case it is demanded to define uniqueness. The value of the field that is used to be unique thus can only appear once as relation. If the editor still tries to create multiple relationships to the same child record he will be notified.

 1: $TCA["tx_irretutorial_mnasym_hotel"] = Array (
 2:     ...
 3:     "columns" => Array (
 4:         ...
 5:         "offers" => Array (
 6:             "label" => "LLL:EXT:irre_tutorial/locallang_db.xml:tx_irretutorial_hotel.offers",
 7:             "config" => Array (
 8:                 "type" => "inline",
 9:                 "foreign_table" => "tx_irretutorial_mnasym_hotel_offer_rel",
10:                 "foreign_field" => "hotelid",
11:                 “foreign_selector” => “offerid”,
12:                 “foreign_unique” => “offerid”,
13:                 "foreign_sortby" => "hotelsort",
14:                 "foreign_label" => "offerid",
15:                 "maxitems" => 10,
16:             )
17:         ),
18:     ),
19: );

The “foreign_unique” property points to the same field on the intermediate table as the “foreign_selector”. But it's also possible to use uniqueness handling without any selector.

Appearance settings for TCEforms

Appearance configuration allows to define how relational sections should be shown and behave in the back-end view.

Define visibility of child forms

The boolean keys “collapseAll” and “expandSingle” allow to define how the input forms of children are displayed to the editor.

If the collapseAll property is enabled, all child records are represented by their header-bar, showing an icon, the title and the control-items. On clicking the icon or title, the accordant element will expand and exhibit its secrets. This is a good way to save space on the screen and offer a quick overview for child records on the next level.

The expandSingle behaviour ties in with the previous, but takes care that only one child record in the same level is expanded. So, if someone edits data in any element, clicking another one of the same type, results in collapsing the current and expanding the next.

 1: $TCA["tx_irretutorial_1nff_hotel"] = Array (
 2:     ...
 3:     "columns" => Array (
 4:         "offers" => Array (
 5:             "config" => Array (
 6:                 "type" => "inline",
 7:                 ...
 8:                 “appearance” => Array (
 9:                     “collapseAll” => 1,
10:                     “expandSingle” => 1,
11:                 ),
12:             )
13:         ),
14:     ),
15: );
Use combined mode for complex relational editing

In situations an intermediate table is used normally it is only possible to select a child record on the parent side what also narrows the editing process to the parent record only.

The combined mode offers a possibility to manipulate both sides of a relationship directly. If a field on the child table is defined by the property “foreign_selector” and the appearance “useCombination” is enabled the whole child record can be rendered and edited in the back- end view.

img-10 Figure 10: Use combined editing mode

Manipulating the displayed child record affects it directly and not just a copy. Thus the block of the child record is shown with a red border.

 1: $TCA["tx_irretutorial_mnasym_hotel"] = Array (
 2:     ...
 3:     "columns" => Array (
 4:         "offers" => Array (
 5:             "config" => Array (
 6:                 "type" => "inline",
 7:                 “foreign_selector” => “offerid”,
 8:                 ...
 9:                 “appearance” => Array (
10:                     “useCombination” => 1,
11:                 ),
12:             )
13:         ),
14:     ),
15: );

The required configuration properties to enable the combined mode are the “foreign_selector” and the appearance setting “useCombination”. The child records to be displayed combined to the parent are defined by the field on the intermediate table the “foreign_selector” is set to.

Use drag'n'drop functionality to speed up sorting

Imagine you have a list of many records that shall be sorted manually. It could take some time to put the first item to the end of that list ny clicking the move-down-button for each step.

To speed up this case the script.aculo.us framework is used to offer drag'n'drop sorting. If a record should be moved from the top to the bottom of a list, it just has to be dragged at the beginning and dropped at the end. This feature is enabled by the appearance property “useSortable”. “Sortable” is deduced of the JavaScript object of script.aculo.us with the same name.

Of course it only works if there is at least a sorting column defined in TCA for that table which stores the information. Thus there has to be at least a “sortby” in the ctrl-section, “foreign_sortby” or “symmetric_sortby” in the field configuration.

 1: $TCA["tx_irretutorial_1nff_hotel"] = Array (
 2:     ...
 3:     "columns" => Array (
 4:         "offers" => Array (
 5:             "config" => Array (
 6:                 "type" => "inline",
 7:                 ...
 8:                 “appearance” => Array (
 9:                     “useSortable” => 1,
10:                 ),
11:             )
12:         ),
13:     ),
14: );

Drag'n'drop sorting of child records is enabled by by the appearance property “useSortable”. Thus the script.aculo.us feature “Sortable” will be enabled.

img-11 Figure 11: Using drag'n'drop sorting

The child records can be sorted by clicking the orange “move” icon and dragging the selected block. Use Page Tsconfig to override TCA setting ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Page TSconfig allows to override TCA field configuration since TYPO3 4.1. This offers a flexible opportunity to reuse tables and TCA definitions but adept it to the visual demands. The “Page TSconfig” can be set and modified in the “page properties”.

TCEFORM.<table>.<field>.config {
  <property1> = <key1>
  <property2>.<subProperty> = <key2>
}
$TCA[<table>]['columns'][<field>]['config'][<property1>] = <key1>;
$TCA[<table>]['columns'][<field>]['config'][<property1>][<subProperty>] = <key2>;

By default it is impossible to override all TCA properties. Thus trying to change the type from “inline” to “input” has no effect. For the TCA type “inline” the allowed properties to be overridden are appearance, foreign_label, foreign_selector, foreign_unique, maxitems, minitems, size, autoSizeMax and symmetric_label. The complete whitelist can be found in doc_core_tsconfig, section “Page TSconfig”. The evaluation of allowed properties is done in TCEforms. Thus extension developers with special demands to this issue can influence and extend the whitelist by modifying the array t3lib_TCEforms::$allowOverrideMatrix.

TCEFORM.tx_irretutorial_mnasym_hotel.offers.config {
  foreign_selector = offerid
  size = 5
}
TCEFORM.tx_irretutorial_mnasym_offer.hotels.config {
  foreign_selector = hotelid
  size = 5
}

The example shown above enables the assignment of record selectors for the entities hotel and offer. This method is used in EXT “irre_tutorial” on the pages “m:n asymmetric selector” and “m:n asymmetric combo”.

Known problems

Currenty no known problems. If you encounter any bugs please use the TYPO3 bugtracker at http://bugs.typo3.org/ to publish your bug report. The bugtracker has an own section for “Inline Relational Record Editing”.

Please see the To-Do list which describes some missing features that probably will be integrated in further TYPO3 Core development.

To-Do list

  • Support FlexForms
  • Support Workspaces&Versioning
  • Implement import&export of data structures concerning IRRE (tx_impexp)
  • Support the Party Information Frameworks on implementing IRRE
  • Support the Extension Kickstarter to implement the TCA type “inline”

Changelog

2007-03-07 Oliver Hader < oh@inpublica.de >

Updated code blocks in documentation to be correctly rendered on typo3.org

2007-02-20 Oliver Hader < oh@inpublica.de >

Updated documentation to be correctly rendered on typo3.org

2007-02-19 Oliver Hader < oh@inpublica.de >

Initial work on the documentation for the irre_tutorial extension.

img-12 EXT: Tutorial for Inline Relational Record Editing (IRRE) - 15