[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