[TYPO3-core] RFC: Bidirectioanl MM relations
Kasper Skårhøj
kasper2006 at typo3.com
Thu Sep 7 12:23:33 CEST 2006
Thanks Ingmar and Sebastian,
I feel comfortable that you have done good work.
A vision (not for this patch) is that one day the MM-tables can
contain additional fields with information that says something about
the relation. However, that requires quite some changes, among others
that MM-table relations are not "deleted/created again" as they are
now in TCEmain. Further, it would need a change so relations
communicated to/from TCEmain and TCEforms is more than just a
table_uid string. Hmm... And finally, such as the T3D format must
support it also.
Anyway, there is one concern: what about the sys_refindex?
With what you have done I kind of assume that sys_refindex actually
stores a relation "twice" now. Example:
pages:1 => MM => pages:2,pages:3
So, you edit pages:1. The sys_refindex gets updated; the relation to
pages:2 and pages:3 is registered.
So, you choose to edit pages:2 now. The relation from pages:1 to
pages:2 is shown, you choose to say add or delete something. During
the saving in TCemain, the sys_refindex is updated for "pages:2".
Will it add the reference to pages:1 now?
If the reference is added, it will be redundant in a sense. We must
consider it: Should the sys_refindex NOT register the reference when
it is in fact coming from another record? Or should we let
sys_refindex understand it as "equal" and register it for both pages:
1 and pages:2? What feels right to you?
Anyway, the more SERIOUS problem with sys_refindex is this: Say you
edit pages:2 and remove the reference to pages:1. Now pages:1 only
points to "pages:3". However, in sys_refindex there will still be a
reference recorded to both pages:2 and pages:3 because when saving
pages:2 the API call is only made for pages:2 - but it should also be
made for any added or removed reference!
I didn't look at the code, but either this should be done in TCEmain
- or maybe in sys_refindex. Because when you call sys_refindex to
update itself it will look for what references was added and which
was removed and for each we could call itself redundantly of course
to update those. That would in fact have the most general character.
I'm willing to implement this for you guys when I get a chance to
test your work. Currently, I'm on an island for myself since my Mac
completely refuses any SVN connections with any client application
and I don't know what to do...
- kasper
On Sep 6, 2006, at 11:02 , Ingmar Schlecht wrote:
> This is a SVN patch request.
>
> Problem:
> Currently you can edit mm-relations in the Backend from one side of
> the
> relation only.
>
> Example:
> Say you have two tables, "persons" and "companies".
> Now, if you'd want to express the employment relation between
> those, you
> would either create a field called "employers" in the persons table or
> you would create an "employees" field in the companies table.
> Until now you couldn't make that relation editable from both sides,
> even
> though it would technically be possible if an mm-table is used.
>
> Solution:
> We (Sebastian and me) made it possible to configure the same relation
> from both sides exactly the same way. There is only one difference
> between the configuration on the "foreign" side of the relation
> compared
> to the configuration on the "local" side (You still need to decide
> which
> side you want to call "local", even though there is no longer a real
> difference between the "local" and "foreign" side): The foreign-side
> needs to have the following defined in TCA:
> "MM_opposite_field" => 'employees',
>
> Here's an example configuration:
>
> $TCA["companies"] = Array (
> [...]
> "columns" => Array (
> [...]
> "employees" => Array (
> "exclude" => 1,
> "label" => "Employees",
> "config" => Array (
> "type" => "select",
> "foreign_table" => "persons",
> "size" => 5,
> "MM" => "companies_employees_mm",
> )
> )
> )
> );
>
> $TCA["persons"] = Array (
> [...]
> "columns" => Array (
> [...]
> "employers" => Array (
> "exclude" => 1,
> "label" => "Employers",
> "config" => Array (
> "type" => "select",
> "foreign_table" => "companies",
> "size" => 5,
> "MM" => "companies_employees_mm",
>
> // New:
> "MM_opposite_field" => 'employees',
> )
> )
> )
> );
>
> And the tables.sql file:
> #
> # Table structure for table 'tx_mmftest_company_employees_mm'
> #
> #
> CREATE TABLE companies_employees_mm (
> uid_local int(11) DEFAULT '0' NOT NULL,
> uid_foreign int(11) DEFAULT '0' NOT NULL,
> tablenames varchar(30) DEFAULT '' NOT NULL,
> sorting int(11) DEFAULT '0' NOT NULL,
>
> # New:
> sorting_foreign int(11) DEFAULT '0' NOT NULL,
>
> KEY uid_local (uid_local),
> KEY uid_foreign (uid_foreign)
> );
>
> Difference between René's patch from 19.01.2006 and this one:
> René's patch didn't only make it possible to edit mm relations from
> both
> sides of the relation, but also added the possibility to store
> *multiple
> different* relation-types between the same set of tables into *one*
> mm-table. For example with René's Patch it was possible to store the
> employment relation as well as the customership relation (both are
> companies<=>persons relations) into the same mm-table by what he
> called
> "ident strings".
> However, we considered this feature to be not so important because you
> could just as well create a different mm-table for each relation-
> type. A
> positive side-effect of dropping that feature was that our patch only
> touches the "foreign" side and doesn't change any behavior on the
> "normal" side of the relation, so existing normal mm-fields are not
> changed in any way, which hopefully reduces the amount of bugs...
>
> Now, for those who want to review the patch:
> What we mainly needed to do was modifying t3lib_loaddbgroup to use the
> uid_local field to store the foreign uid and the uid_foreign field to
> store the local uid in case we are lookign at a relation from the
> "foreign side". Unfortunately t3lib_loaddbgroup didn't know the TCA
> configuration of the field it was working on until now, but we needed
> it. Therefore we introduced a new parameter $conf to the start()
> function of t3lib_loaddbgroup containing the TCA field configuration.
> Then we needed to modify all places where t3lib_loaddbgroup::start
> () was
> called, to make sure the $conf parameter was passed.
>
> Another problem we faced was sorting: The sorting on the one side
> of the
> relation (employees of companies) doesn't have anything to do with the
> sorting on the other side of the relation (employers of persons).
> Therefore we introduced another field sorting_foreign to handle
> sorting
> on the foreign side. If a new relation is added on the one side (the
> person selects a new employer), that new entity (the person) is listed
> on top on the other side (the company side). Whether new items
> added on
> the other side are listed on top or at the end of the list can be
> ajusted with the MySQL default value of the sorting columns.
>
> I would like the patch to enter trunk rather sooner then later to
> have a
> long testing period until 4.1 is released. You can test the new
> feature
> with the attached test extension.
>
> cheers
> Ingmar
> Index: C:/apache/typo3/typo3_src-trunk/t3lib/class.t3lib_admin.php
> ===================================================================
> --- C:/apache/typo3/typo3_src-trunk/t3lib/class.t3lib_admin.php
> (revision 1718)
> +++ C:/apache/typo3/typo3_src-trunk/t3lib/class.t3lib_admin.php
> (working copy)
> @@ -535,7 +535,7 @@
> if ($fieldConf['internal_type']=='db') {
> // dbs - group
> $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
> - $dbAnalysis->start($row[$field],$fieldConf['allowed'],
> $fieldConf['MM'],$row['uid']);
> + $dbAnalysis->start($row[$field],$fieldConf['allowed'],
> $fieldConf['MM'],$row['uid'], $table, $fieldConf);
> reset($dbAnalysis->itemArray);
> while (list(,$tempArr)=each($dbAnalysis->itemArray)) {
> $this->checkGroupDBRefs[$tempArr['table']][$tempArr
> ['id']]+=1;
> @@ -545,7 +545,7 @@
> if ($fieldConf['type']=='select' && $fieldConf
> ['foreign_table']) {
> // dbs - select
> $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
> - $dbAnalysis->start($row[$field],$fieldConf
> ['foreign_table'],$fieldConf['MM'],$row['uid']);
> + $dbAnalysis->start($row[$field],$fieldConf
> ['foreign_table'],$fieldConf['MM'],$row['uid'], $table, $fieldConf);
> reset($dbAnalysis->itemArray);
> while (list(,$tempArr)=each($dbAnalysis->itemArray)) {
> if ($tempArr['id']>0) {
> @@ -673,7 +673,7 @@
> $allowedTables = ($fieldConf['type']=='group') ? $fieldConf
> ['allowed'] : $fieldConf['foreign_table'];
>
> $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
> - $dbAnalysis->start($row[$field],$allowedTables,$fieldConf
> ['MM'],$row['uid']);
> + $dbAnalysis->start($row[$field],$allowedTables,$fieldConf
> ['MM'],$row['uid'], $table, $fieldConf);
> reset($dbAnalysis->itemArray);
> while (list(,$tempArr)=each($dbAnalysis->itemArray)) {
> if ($tempArr['table']==$searchTable && $tempArr['id']==$id) {
> Index: C:/apache/typo3/typo3_src-trunk/t3lib/class.t3lib_befunc.php
> ===================================================================
> --- C:/apache/typo3/typo3_src-trunk/t3lib/class.t3lib_befunc.php
> (revision 1719)
> +++ C:/apache/typo3/typo3_src-trunk/t3lib/class.t3lib_befunc.php
> (working copy)
> @@ -171,7 +171,9 @@
> *
> */
>
> +require_once (PATH_t3lib.'class.t3lib_loaddbgroup.php');
>
> +
> /**
> * Standard functions available for the TYPO3 backend.
> * Don't instantiate - call functions with "t3lib_BEfunc::"
> prefixed the function name.
> @@ -1872,14 +1874,17 @@
> }
> $MMfield = join(',',$MMfields);
> }
> - $MMres = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query(
> - $MMfield,
> - ($table!=$theColConf['foreign_table']?$table:''),
> - $theColConf['MM'],
> - $theColConf['foreign_table'],
> - 'AND '.$theColConf['MM'].'.uid_local ='.intval
> ($uid).t3lib_BEfunc::deleteClause($theColConf['foreign_table'])
> - );
> - if ($MMres) {
> +
> + $dbGroup = t3lib_div::makeInstance('t3lib_loadDBGroup');
> + $dbGroup->start($value, $theColConf['foreign_table'],
> $theColConf['MM'], $uid, $table, $theColConf);
> + $selectUids = $dbGroup->tableArray[$theColConf
> ['foreign_table']];
> +
> + if (is_array($selectUids) && count($selectUids)>0) {
> + $MMres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
> + 'uid, '.$MMfield,
> + $theColConf['foreign_table'],
> + 'uid IN ('.implode(',', $selectUids).')'
> + );
> while($MMrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc
> ($MMres)) {
> $mmlA[] = ($noRecordLookup?$MMrow
> ['uid']:t3lib_BEfunc::getRecordTitle($theColConf['foreign_table'],
> $MMrow));
> }
> Index: C:/apache/typo3/typo3_src-trunk/t3lib/
> class.t3lib_loaddbgroup.php
> ===================================================================
> --- C:/apache/typo3/typo3_src-trunk/t3lib/
> class.t3lib_loaddbgroup.php (revision 1718)
> +++ C:/apache/typo3/typo3_src-trunk/t3lib/
> class.t3lib_loaddbgroup.php (working copy)
> @@ -83,10 +83,15 @@
> var $dbPaths=Array();
> var $firstTable = ''; // Will contain the first table name in
> the $tablelist (for positive ids)
> var $secondTable = ''; // Will contain the second table name
> in the $tablelist (for negative ids)
> + // private
> + var $MM_is_foreign = 0; // boolean - if 1, uid_local and
> uid_foreign are switched, and the current table is inserted as
> tablename - this means you display a foreign relation "from the
> opposite side"
> + var $MM_oppositeField = ''; // field name at the "local" side of
> the MM relation
> + var $MM_oppositeTable = ''; // only set if MM_is_foreign is set
> + var $MM_oppositeFieldConf = ''; // only set if MM_is_foreign is set
> + var $MM_isMultiTableRelationship = 0; // is empty by default; if
> MM_is_foreign is set and there is more than one table allowed (on
> the "local" side), then it contains the first table (as a fallback)
> + var $currentTable; // current table => Only needed for reverse
> relations
>
>
> -
> -
> /**
> * Initialization of the class.
> *
> @@ -94,9 +99,35 @@
> * @param string Comma list of tables, first table takes
> priority if no table is set for an entry in the list.
> * @param string Name of a MM table.
> * @param integer Local UID for MM lookup
> + * @param string current table name
> + * @param integer TCA configuration for current field
> * @return void
> */
> - function start($itemlist,$tablelist, $MMtable='',$MMuid=0) {
> + function start($itemlist, $tablelist, $MMtable='', $MMuid=0,
> $currentTable='', $conf=array()) {
> + // SECTION: MM reverse relations
> + $this->MM_is_foreign = ($conf['MM_opposite_field']?1:0);
> + $this->MM_oppositeField = $conf['MM_opposite_field'];
> + $this->currentTable = $currentTable;
> + if ($this->MM_is_foreign) {
> + $tmp = ($conf['type']==='group'?$conf['allowed']:$conf
> ['foreign_table']);
> + // normally, $conf['allowed'] can contain a list of tables,
> but as we are looking at a MM relation from the foreign side, it
> only makes sense to allow one one table in $conf['allowed']
> + $tmp = t3lib_div::trimExplode(',', $tmp);
> + $this->MM_oppositeTable = $tmp[0];
> + unset($tmp);
> +
> + // only add the current table name if there is more than one
> allowed field
> + $this->MM_oppositeFieldConf = $GLOBALS['TCA'][$this-
> >MM_oppositeTable]['columns'][$this->MM_oppositeField]['config'];
> +
> + if ($this->MM_oppositeFieldConf['allowed']) {
> + $oppositeFieldConf_allowed = explode(',', $this-
> >MM_oppositeFieldConf['allowed']);
> + if (count($oppositeFieldConf_allowed) > 1) {
> + $this->MM_isMultiTableRelationship =
> $oppositeFieldConf_allowed[0];
> + }
> + }
> + }
> +
> + // SECTION: normal MM relations
> +
> // If the table list is "*" then all tables are used in the list:
> if (!strcmp(trim($tablelist),'*')) {
> $tablelist = implode(',',array_keys($GLOBALS['TCA']));
> @@ -185,19 +216,41 @@
> */
> function readMM($tableName,$uid) {
> $key=0;
> + if ($this->MM_is_foreign) { // in case of a reverse relation
> + $uidLocal_field = 'uid_foreign';
> + $uidForeign_field = 'uid_local';
> + $sorting_field = 'sorting_foreign';
>
> + if ($this->MM_isMultiTableRelationship) {
> + $additionalWhere = ' AND ( tablenames="'.$this->currentTable.'"';
> + if ($this->currentTable == $this->MM_isMultiTableRelationship)
> { // be backwards compatible! When allowing more than one table
> after having previously allowed only one table, this case applies.
> + $additionalWhere .= ' OR tablenames=""';
> + }
> + $additionalWhere .= ' ) ';
> + }
> + $theTable = $this->MM_oppositeTable;
> + } else { // default
> + $uidLocal_field = 'uid_local';
> + $uidForeign_field = 'uid_foreign';
> + $additionalWhere = '';
> + $sorting_field = 'sorting';
> + }
> +
> // Select all MM relations:
> - $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $tableName,
> 'uid_local='.intval($uid), '', 'sorting');
> + $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $tableName,
> $uidLocal_field.'='.intval($uid).$additionalWhere, '',
> $sorting_field);
> while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
> - $theTable = $row['tablenames'] ? $row['tablenames'] : $this-
> >firstTable; // If tablesnames columns exists and contain a name,
> then this value is the table, else it's the firstTable...
> - if (($row['uid_foreign'] || $theTable=='pages') && $theTable &&
> isset($this->tableArray[$theTable])) {
> - $this->itemArray[$key]['id'] = $row['uid_foreign'];
> + if (!$this->MM_is_foreign) { // default
> + $theTable = $row['tablenames'] ? $row['tablenames'] : $this-
> >firstTable; // If tablesnames columns exists and contain a name,
> then this value is the table, else it's the firstTable...
> + }
> + if (($row[$uidForeign_field] || $theTable=='pages') &&
> $theTable && isset($this->tableArray[$theTable])) {
> +
> + $this->itemArray[$key]['id'] = $row[$uidForeign_field];
> $this->itemArray[$key]['table'] = $theTable;
> - $this->tableArray[$theTable][]= $row['uid_foreign'];
> + $this->tableArray[$theTable][]= $row[$uidForeign_field];
> } elseif ($this->registerNonTableValues) {
> - $this->itemArray[$key]['id'] = $row['uid_foreign'];
> + $this->itemArray[$key]['id'] = $row[$uidForeign_field];
> $this->itemArray[$key]['table'] = '_NO_TABLE';
> - $this->nonTableArray[] = $row['uid_foreign'];
> + $this->nonTableArray[] = $row[$uidForeign_field];
> }
> $key++;
> }
> @@ -214,31 +267,69 @@
> */
> function writeMM($tableName,$uid,$prependTableName=0) {
>
> - // Delete all relations:
> - $GLOBALS['TYPO3_DB']->exec_DELETEquery($tableName,
> 'uid_local='.intval($uid));
> + if ($this->MM_is_foreign) { // in case of a reverse relation
> + $uidLocal_field = 'uid_foreign';
> + $uidForeign_field = 'uid_local';
> + $sorting_field = 'sorting_foreign';
> + } else { // default
> + $uidLocal_field = 'uid_local';
> + $uidForeign_field = 'uid_foreign';
> + $sorting_field = 'sorting';
> + } // TODO: SORTING!
>
> // If there are tables...
> $tableC = count($this->tableArray);
> if ($tableC) {
> - $prep = ($tableC>1||$prependTableName) ? 1 : 0;
> + $prep = ($tableC>1||$prependTableName||$this-
> >MM_isMultiTableRelationship) ? 1 : 0; // boolean: does the field
> "tablename" need to be filled?
> $c=0;
> - $tName=array();
>
> + $additionalWhere_tablenames = '';
> + if ($this->MM_is_foreign && $prep) {
> + $additionalWhere_tablenames = ' AND tablenames="'.$this-
> >currentTable.'"';
> + }
> + $existingMMs = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows
> ($uidForeign_field, $tableName, $uidLocal_field.'='.$uid.
> $additionalWhere_tablenames, '', '', '', $uidForeign_field);
> +
> +
> // For each item, insert it:
> + $uidList = array();
> foreach($this->itemArray as $val) {
> $c++;
>
> - $insertFields = array(
> - 'uid_local' => $uid,
> - 'uid_foreign' => $val['id'],
> - 'sorting' => $c
> - );
> + $uidList[] = $val['id'];
> +
> if ($prep || $val['table']=='_NO_TABLE') {
> - $insertFields['tablenames'] = $val['table'];
> + if ($this->MM_is_foreign) { // insert current table if needed
> + $tablename = $this->currentTable;
> + } else {
> + $tablename = $val['table'];
> + }
> + } else {
> + $tablename = '';
> }
>
> - $GLOBALS['TYPO3_DB']->exec_INSERTquery($tableName,
> $insertFields);
> + if (isset($existingMMs[$val['id']])) {
> + $whereClause = $uidLocal_field.'='.$uid.' AND '.
> $uidForeign_field.'='.$val['id'];
> + if ($tablename)
> + $whereClause .= ' AND tablenames="'.$tablename.'"';
> + $GLOBALS['TYPO3_DB']->exec_UPDATEquery($tableName,
> $whereClause, array($sorting_field => $c));
> + } else {
> + $GLOBALS['TYPO3_DB']->exec_INSERTquery($tableName, array(
> + $uidLocal_field => $uid,
> + $uidForeign_field => $val['id'],
> + $sorting_field => $c,
> + 'tablenames' => $tablename
> + ));
> + }
> }
> +
> + // Delete all not-used relations:
> + $additionalWhere = '';
> + if (count($uidList)) {
> + $additionalWhere = ' AND '.$uidForeign_field.' NOT IN
> ( '.implode(',', $uidList).' ) ';
> + }
> +
> + $GLOBALS['TYPO3_DB']->exec_DELETEquery($tableName,
> $uidLocal_field.'='.intval($uid).$additionalWhere.
> $additionalWhere_tablenames);
> +
> }
> }
>
> Index: C:/apache/typo3/typo3_src-trunk/t3lib/class.t3lib_refindex.php
> ===================================================================
> --- C:/apache/typo3/typo3_src-trunk/t3lib/class.t3lib_refindex.php
> (revision 1718)
> +++ C:/apache/typo3/typo3_src-trunk/t3lib/class.t3lib_refindex.php
> (working copy)
> @@ -570,6 +570,10 @@
> $allowedTables = $conf['type']=='group' ? $conf['allowed'] :
> $conf['foreign_table'].','.$conf['neg_foreign_table'];
> $prependName = $conf['type']=='group' ? $conf
> ['prepend_tname'] : $conf['neg_foreign_table'];
>
> + if($conf['MM_opposite_field']) {
> + return array();
> + }
> +
> $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
> $dbAnalysis->start($value,$allowedTables,$conf['MM'],$uid);
>
> Index: C:/apache/typo3/typo3_src-trunk/t3lib/class.t3lib_tcemain.php
> ===================================================================
> --- C:/apache/typo3/typo3_src-trunk/t3lib/class.t3lib_tcemain.php
> (revision 1718)
> +++ C:/apache/typo3/typo3_src-trunk/t3lib/class.t3lib_tcemain.php
> (working copy)
> @@ -579,7 +579,7 @@
> $fieldArray = $this->newFieldArray($table); // Get a
> fieldArray with default values
> if (isset($incomingFieldArray['pid'])) { // A pid must be
> set for new records.
> // $value = the pid
> - $pid_value = $incomingFieldArray['pid'];
> + $pid_value = $incomingFieldArray['pid'];
>
> // Checking and finding numerical pid, it may be a string-
> reference to another value
> $OK = 1;
> @@ -1328,13 +1328,13 @@
> );
> break;
> case 'db':
> - $valueArray = $this->checkValue_group_select_processDBdata
> ($valueArray,$tcaFieldConf,$id,$status,'group');
> + $valueArray = $this->checkValue_group_select_processDBdata
> ($valueArray,$tcaFieldConf,$id,$status,'group', $table);
> break;
> }
> }
> // For select types which has a foreign table attached:
> if ($tcaFieldConf['type']=='select' && $tcaFieldConf
> ['foreign_table']) {
> - $valueArray = $this->checkValue_group_select_processDBdata
> ($valueArray,$tcaFieldConf,$id,$status,'select');
> + $valueArray = $this->checkValue_group_select_processDBdata
> ($valueArray,$tcaFieldConf,$id,$status,'select', $table);
> }
>
> // BTW, checking for min and max items here does NOT make any
> sense when MM is used because the above function calls will just
> return an array with a single item (the count) if MM is used... Why
> didn't I perform the check before? Probably because we could not
> evaluate the validity of record uids etc... Hmm...
> @@ -1845,15 +1845,16 @@
> * @param integer Record id, used for look-up of MM relations
> (local_uid)
> * @param string Status string ('update' or 'new')
> * @param string The type, either 'select' or 'group'
> + * @param string Table name, needs to be passed to
> t3lib_loadDBGroup
> * @return array Modified value array
> */
> - function checkValue_group_select_processDBdata($valueArray,
> $tcaFieldConf,$id,$status,$type) {
> + function checkValue_group_select_processDBdata($valueArray,
> $tcaFieldConf,$id,$status,$type,$currentTable) {
> $tables = $type=='group'?$tcaFieldConf['allowed']:$tcaFieldConf
> ['foreign_table'].','.$tcaFieldConf['neg_foreign_table'];
> $prep = $type=='group'?$tcaFieldConf['prepend_tname']:
> $tcaFieldConf['neg_foreign_table'];
>
> $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
> $dbAnalysis->registerNonTableValues=$tcaFieldConf
> ['allowNonIdValues'] ? 1 : 0;
> - $dbAnalysis->start(implode(',',$valueArray),$tables);
> + $dbAnalysis->start(implode(',',$valueArray),$tables, '', 0,
> $currentTable, $tcaFieldConf);
>
> if ($tcaFieldConf['MM']) {
> if ($status=='update') {
> @@ -2591,7 +2592,7 @@
> $prependName = $conf['type']=='group' ? $conf
> ['prepend_tname'] : $conf['neg_foreign_table'];
> if ($conf['MM']) {
> $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
> - $dbAnalysis->start('',$allowedTables,$conf['MM'],$uid);
> + $dbAnalysis->start('', $allowedTables, $conf['MM'], $uid,
> $table, $conf);
> $value = implode(',',$dbAnalysis->getValueArray($prependName));
> }
> if ($value) { // Setting the value in this array will notify
> the remapListedDBRecords() function that this field MAY need
> references to be corrected
> @@ -3427,7 +3428,7 @@
>
> /*
> Version ID swapping principles:
> - - Version from archive (future/past, called "swap version")
> will get the uid of the "t3ver_oid", the official element with uid
> = "t3ver_oid" will get the new versions old uid. PIDs are swapped also
> + - Version from archive (future/past, called "swap version")
> will get the uid of the "t3ver_oid", the official element with uid
> = "t3ver_oid" will get the new versions old uid. PIDs are swapped also
>
> uid pid uid t3ver_oid pid
> 1: 13 123 --> -13 247 123 (Original has negated UID, and
> sets t3ver_oid to the final UID (which is nice to know for
> recovery). PID is unchanged at this point)
> @@ -3691,7 +3692,7 @@
> switch($conf['type']) {
> case 'group':
> case 'select':
> - $vArray = $this->remapListedDBRecords_procDBRefs($conf,
> $value, $theUidToUpdate);
> + $vArray = $this->remapListedDBRecords_procDBRefs($conf,
> $value, $theUidToUpdate, $table);
> if (is_array($vArray)) {
> $newData[$fieldName] = implode(',',$vArray);
> }
> @@ -3757,7 +3758,7 @@
>
> // If references are set for this field, set flag so they can
> be corrected later:
> if ($this->isReferenceField($dsConf) && strlen($dataValue)) {
> - $vArray = $this->remapListedDBRecords_procDBRefs($dsConf,
> $dataValue, $uid);
> + $vArray = $this->remapListedDBRecords_procDBRefs($dsConf,
> $dataValue, $uid, $table);
> if (is_array($vArray)) {
> $dataValue = implode(',',$vArray);
> }
> @@ -3773,10 +3774,11 @@
> * @param array TCA field config
> * @param string Field value
> * @param integer UID of local record (for MM relations - might
> need to change if support for FlexForms should be done!)
> + * @param string Table name
> * @return array Returns array of items ready to implode for
> field content.
> * @see remapListedDBRecords()
> */
> - function remapListedDBRecords_procDBRefs($conf, $value,
> $MM_localUid) {
> + function remapListedDBRecords_procDBRefs($conf, $value,
> $MM_localUid, $table) {
>
> // Initialize variables
> $set = FALSE; // Will be set true if an upgrade should be done...
> @@ -3787,7 +3789,7 @@
> // Convert value to list of references:
> $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
> $dbAnalysis->registerNonTableValues = ($conf['type']=='select'
> && $conf['allowNonIdValues']) ? 1 : 0;
> - $dbAnalysis->start($value, $allowedTables, $conf['MM'],
> $MM_localUid);
> + $dbAnalysis->start($value, $allowedTables, $conf['MM'],
> $MM_localUid, $table, $conf);
>
> // Traverse those references and map IDs:
> foreach($dbAnalysis->itemArray as $k => $v) {
> @@ -4964,17 +4966,17 @@
> function int_pageTreeInfo($CPtable,$pid,$counter, $rootID) {
> if ($counter) {
> $addW = !$this->admin ? ' AND '.$this->BE_USER-
> >getPagePermsClause($this->pMap['show']) : '';
> - $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages',
> 'pid='.intval($pid).$this->deleteClause('pages').$addW, '',
> 'sorting DESC');
> - while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
> + $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages',
> 'pid='.intval($pid).$this->deleteClause('pages').$addW, '',
> 'sorting DESC');
> + while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
> if ($row['uid']!=$rootID) {
> - $CPtable[$row['uid']] = $pid;
> - if ($counter-1) { // If the uid is NOT the rootID of the
> copyaction and if we are supposed to walk further down
> - $CPtable = $this->int_pageTreeInfo($CPtable,$row['uid'],
> $counter-1, $rootID);
> - }
> + $CPtable[$row['uid']] = $pid;
> + if ($counter-1) { // If the uid is NOT the rootID of the
> copyaction and if we are supposed to walk further down
> + $CPtable = $this->int_pageTreeInfo($CPtable,$row['uid'],
> $counter-1, $rootID);
> + }
> }
> - }
> + }
> }
> - return $CPtable;
> + return $CPtable;
> }
>
> /**
> @@ -5310,7 +5312,7 @@
> case 0:
> $emails = $this->notifyStageChange_getEmails($workspaceRec
> ['members']);
> break;
> - default:
> + default:
> $emails = $this->notifyStageChange_getEmails($workspaceRec
> ['adminusers'], TRUE);
> break;
> }
> Index: C:/apache/typo3/typo3_src-trunk/t3lib/
> class.t3lib_transferdata.php
> ===================================================================
> --- C:/apache/typo3/typo3_src-trunk/t3lib/
> class.t3lib_transferdata.php (revision 1718)
> +++ C:/apache/typo3/typo3_src-trunk/t3lib/
> class.t3lib_transferdata.php (working copy)
> @@ -382,7 +382,7 @@
> break;
> case 'db':
> $loadDB = t3lib_div::makeInstance('t3lib_loadDBGroup');
> - $loadDB->start($data, $fieldConfig['config']['allowed'],
> $fieldConfig['config']['MM'], $row['uid']);
> + $loadDB->start($data, $fieldConfig['config']['allowed'],
> $fieldConfig['config']['MM'], $row['uid'], $table, $fieldConfig
> ['config']);
> $loadDB->getFromDB();
> $data = $loadDB->readyForInterface();
> break;
> @@ -433,7 +433,7 @@
>
> // Add "foreign table" stuff:
> if ($TCA[$fieldConfig['config']['foreign_table']]) {
> - $dataAcc = $this->selectAddForeign($dataAcc, $elements,
> $fieldConfig, $field, $TSconfig, $row);
> + $dataAcc = $this->selectAddForeign($dataAcc, $elements,
> $fieldConfig, $field, $TSconfig, $row, $table);
> }
>
> // Always keep the native order for display in interface:
> @@ -441,7 +441,7 @@
> } else { // Normal, <= 1 -> value without title on it
> if ($TCA[$fieldConfig['config']['foreign_table']]) {
> // Getting the data
> - $dataIds = $this->getDataIdList($elements, $fieldConfig, $row);
> + $dataIds = $this->getDataIdList($elements, $fieldConfig, $row,
> $table);
>
> if (!count($dataIds)) $dataIds = array(0);
> $dataAcc[]=$dataIds[0];
> @@ -780,11 +780,12 @@
> * @param string The field name
> * @param array TSconfig for the record
> * @param array The record
> + * @param array The current table
> * @return array Modified $dataAcc array
> * @access private
> * @see renderRecord_selectProc()
> */
> - function selectAddForeign($dataAcc, $elements, $fieldConfig,
> $field, $TSconfig, $row) {
> + function selectAddForeign($dataAcc, $elements, $fieldConfig,
> $field, $TSconfig, $row, $table) {
> global $TCA;
>
> // Init:
> @@ -806,7 +807,7 @@
>
> // At this point all records that CAN be selected is found in
> $recordList
> // Now, get the data from loadDBgroup based on the input list
> of values.
> - $dataIds = $this->getDataIdList($elements, $fieldConfig, $row);
> + $dataIds = $this->getDataIdList($elements, $fieldConfig, $row,
> $table);
> if ($fieldConfig['config']['MM']) $dataAcc=array(); // Reset, if
> MM (which cannot bear anything but real relations!)
>
> // After this we can traverse the loadDBgroup values and match
> values with the list of possible values in $recordList:
> @@ -834,13 +835,20 @@
> * @param array The array of original elements - basically the
> field value exploded by ","
> * @param array Field configuration from TCA
> * @param array The data array, currently. Used to set the
> "local_uid" for selecting MM relation records.
> + * @param string Current table name. passed on to t3lib_loadDBGroup
> * @return array An array with ids of the records from the input
> elements array.
> * @access private
> */
> - function getDataIdList($elements, $fieldConfig, $row) {
> + function getDataIdList($elements, $fieldConfig, $row, $table) {
> $loadDB = t3lib_div::makeInstance('t3lib_loadDBGroup');
> $loadDB->registerNonTableValues=$fieldConfig['config']
> ['allowNonIdValues'] ? 1 : 0;
> - $loadDB->start(implode(',',$elements), $fieldConfig['config']
> ['foreign_table'].','.$fieldConfig['config']['neg_foreign_table'],
> $fieldConfig['config']['MM'], $row['uid']);
> + $loadDB->start(implode(',',$elements),
> + $fieldConfig['config']['foreign_table'].','.$fieldConfig
> ['config']['neg_foreign_table'],
> + $fieldConfig['config']['MM'],
> + $row['uid'],
> + $table,
> + $fieldConfig['config']
> + );
>
> $idList = $loadDB->convertPosNeg($loadDB->getValueArray(),
> $fieldConfig['config']['foreign_table'],$fieldConfig['config']
> ['neg_foreign_table']);
>
> Index: C:/apache/typo3/typo3_src-trunk/typo3/mod/user/ws/
> workspaceforms.php
> ===================================================================
> --- C:/apache/typo3/typo3_src-trunk/typo3/mod/user/ws/
> workspaceforms.php (revision 1718)
> +++ C:/apache/typo3/typo3_src-trunk/typo3/mod/user/ws/
> workspaceforms.php (working copy)
> @@ -484,7 +484,7 @@
> $config = &$GLOBALS['TCA']['sys_workspace']['columns']
> ['adminusers']['config'];
> // Notice: $config['MM'] is not set in the current version of
> $TCA but
> // we still pass it to ensure compatibility with feature versions!
> - $loadDB->start($GLOBALS['BE_USER']->user['uid'], $config
> ['allowed'], $config['MM'], $uid);
> + $loadDB->start($GLOBALS['BE_USER']->user['uid'], $config
> ['allowed'], $config['MM'], $uid, 'sys_workspace', $config);
> $loadDB->getFromDB();
> return $loadDB->readyForInterface();
> }
> <T3X_mmftest-0_0_0-z-200609061100.t3x>
> _______________________________________________
> TYPO3-team-core mailing list
> TYPO3-team-core at lists.netfielders.de
> http://lists.netfielders.de/cgi-bin/mailman/listinfo/typo3-team-core
- kasper
"Gimme Five!"
-------------------------------
kasper2006 at typo3.com | +45 20 999 115 | skype: kasperskaarhoej |
gizmo: kasper_typo3
More information about the TYPO3-team-core
mailing list