config.添加配置:’MM_own_field’ => true,
添加t3lib_loaddbgroup的XCLASS:
* @package TYPO3 * @subpackage t3lib */ class ux_t3lib_loadDBGroup extends t3lib_loadDBGroup{ // External, static: var $fromTC = 1; // Means that only uid and the label-field is returned var $registerNonTableValues=0; // If set, values that are not ids in tables are normally discarded. By this options they will be preserved. // Internal, dynamic: var $tableArray=Array(); // Contains the table names as keys. The values are the id-values for each table. Should ONLY contain proper table names. var $itemArray=Array(); // Contains items in an numeric array (table/id for each). Tablenames here might be "_NO_TABLE" var $nonTableArray=array(); // Array for NON-table elements var $additionalWhere=array(); var $checkIfDeleted = 1; // deleted-column is added to additionalWhere... if this is set... 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 var $undeleteRecord; // if a record should be undeleted (so do not use the $useDeleteClause on t3lib_BEfunc) var $MM_ownField = false; //add by bobo var $MM_match_fields = array(); // array of fields value pairs that should match while SELECT and will be written into MM table if $MM_insert_fields is not set var $MM_insert_fields = array(); // array of fields and value pairs used for insert in MM table var $MM_table_where = ''; // extra MM table where /** * Initialization of the class. * * @param string List of group/select items * @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, $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->MM_table_where = $conf['MM_table_where']; $this->MM_hasUidField = $conf['MM_hasUidField']; $this->MM_match_fields = is_array($conf['MM_match_fields']) ? $conf['MM_match_fields'] : array(); $this->MM_insert_fields = is_array($conf['MM_insert_fields']) ? $conf['MM_insert_fields'] : $this->MM_match_fields; $this->MM_ownField = $conf['MM_own_field']; //add by bobo $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 t3lib_div::loadTCA($this->MM_oppositeTable); // We must be sure this has been done at least once before accessing the "columns" part of TCA for a table. $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'])); } // The tables are traversed and internal arrays are initialized: $tempTableArray = t3lib_div::trimExplode(',',$tablelist,1); foreach($tempTableArray as $key => $val) { $tName = trim($val); $this->tableArray[$tName] = Array(); if ($this->checkIfDeleted && $GLOBALS['TCA'][$tName]['ctrl']['delete']) { $fieldN = $tName.'.'.$GLOBALS['TCA'][$tName]['ctrl']['delete']; $this->additionalWhere[$tName].=' AND '.$fieldN.'=0'; } } if (is_array($this->tableArray)) { reset($this->tableArray); } else {return 'No tables!';} // Set first and second tables: $this->firstTable = key($this->tableArray); // Is the first table next($this->tableArray); $this->secondTable = key($this->tableArray); // If the second table is set and the ID number is less than zero (later) then the record is regarded to come from the second table... // Now, populate the internal itemArray and tableArray arrays: if ($MMtable) { // If MM, then call this function to do that: if ($MMuid) { $this->readMM($MMtable, $MMuid); } else { // Revert to readList() for new records in order to load possible default values from $itemlist $this->readList($itemlist); } } elseif ($MMuid && $conf['foreign_field']) { // If not MM but foreign_field, the read the records by the foreign_field $this->readForeignField($MMuid, $conf); } else { // If not MM, then explode the itemlist by "," and traverse the list: $this->readList($itemlist); // do automatic default_sortby, if any if ($conf['foreign_default_sortby']) { $this->sortList($conf['foreign_default_sortby']); } } } /** * Writes the internal itemArray to MM table: * * @param string MM table name * @param integer Local UID * @param boolean If set, then table names will always be written. * @return void */ function writeMM($MM_tableName,$uid,$prependTableName=0) { 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'; } // If there are tables... $tableC = count($this->tableArray); if ($tableC) { $prep = ($tableC>1||$prependTableName||$this->MM_isMultiTableRelationship) ? 1 : 0; // boolean: does the field "tablename" need to be filled? $c=0; $additionalWhere_tablenames = ''; if ($this->MM_is_foreign && $prep) { $additionalWhere_tablenames = ' AND tablenames="'.$this->currentTable.'"'; } $additionalWhere = ''; // add WHERE clause if configured if ($this->MM_table_where) { $additionalWhere.= "\n".str_replace('###THIS_UID###', intval($uid), $this->MM_table_where); } // Select, update or delete only those relations that match the configured fields foreach ($this->MM_match_fields as $field => $value) { $additionalWhere.= ' AND '.$field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($value, $MM_tableName); } $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( $uidForeign_field.($prep?', tablenames':'').($this->MM_hasUidField?', uid':''), $MM_tableName, $uidLocal_field.'='.$uid.$additionalWhere_tablenames.$additionalWhere, '', $sorting_field ); $oldMMs = array(); $oldMMs_inclUid = array(); // This array is similar to $oldMMs but also holds the uid of the MM-records, if any (configured by MM_hasUidField). If the UID is present it will be used to update sorting and delete MM-records. This is necessary if the "multiple" feature is used for the MM relations. $oldMMs is still needed for the in_array() search used to look if an item from $this->itemArray is in $oldMMs while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { if (!$this->MM_is_foreign && $prep) { $oldMMs[] = array($row['tablenames'], $row[$uidForeign_field]); } else { $oldMMs[] = $row[$uidForeign_field]; } $oldMMs_inclUid[] = array($row['tablenames'], $row[$uidForeign_field], $row['uid']); } // For each item, insert it: foreach($this->itemArray as $val) { $c++; if ($prep || $val['table']=='_NO_TABLE') { if ($this->MM_is_foreign) { // insert current table if needed $tablename = $this->currentTable; } else { $tablename = $val['table']; } } else { $tablename = ''; } if(!$this->MM_is_foreign && $prep) { $item = array($val['table'], $val['id']); } else { $item = $val['id']; } if (in_array($item, $oldMMs)) { $oldMMs_index = array_search($item, $oldMMs); $whereClause = $uidLocal_field.'='.$uid.' AND '.$uidForeign_field.'='.$val['id']. ($this->MM_hasUidField ? ' AND uid='.intval($oldMMs_inclUid[$oldMMs_index][2]) : ''); // In principle, selecting on the UID is all we need to do if a uid field is available since that is unique! But as long as it "doesn't hurt" we just add it to the where clause. It should all match up. if ($tablename) { $whereClause .= ' AND tablenames="'.$tablename.'"'; } $GLOBALS['TYPO3_DB']->exec_UPDATEquery($MM_tableName, $whereClause.$additionalWhere, array($sorting_field => $c)); unset($oldMMs[$oldMMs_index]); // remove the item from the $oldMMs array so after this foreach loop only the ones that need to be deleted are in there. unset($oldMMs_inclUid[$oldMMs_index]); // remove the item from the $oldMMs array so after this foreach loop only the ones that need to be deleted are in there. } else { $insertFields = $this->MM_insert_fields; $insertFields[$uidLocal_field] = $uid; $insertFields[$uidForeign_field] = $val['id']; $insertFields[$sorting_field] = $c; if($tablename) { $insertFields['tablenames'] = $tablename; } $GLOBALS['TYPO3_DB']->exec_INSERTquery($MM_tableName, $insertFields); //add by bobo if ($this->MM_ownField) { $c++; $insertFields[$uidLocal_field] = $val['id']; $insertFields[$uidForeign_field] = $uid; $insertFields[$sorting_field] = $c; $GLOBALS['TYPO3_DB']->exec_INSERTquery($MM_tableName, $insertFields); } if ($this->MM_is_foreign) { $this->updateRefIndex($val['table'], $val['id']); } } } // Delete all not-used relations: if(is_array($oldMMs) && count($oldMMs) > 0) { $removeClauses = array(); $updateRefIndex_records = array(); foreach($oldMMs as $oldMM_key => $mmItem) { if ($this->MM_hasUidField) { // If UID field is present, of course we need only use that for deleting...: $removeClauses[] = 'uid='.intval($oldMMs_inclUid[$oldMM_key][2]); $elDelete = $oldMMs_inclUid[$oldMM_key]; } else { if(is_array($mmItem)) { $removeClauses[] = 'tablenames="'.$mmItem[0].'" AND '.$uidForeign_field.'='.$mmItem[1]; } else { $removeClauses[] = $uidForeign_field.'='.$mmItem; } } if ($this->MM_is_foreign) { if(is_array($mmItem)) { $updateRefIndex_records[] = array($mmItem[0],$mmItem[1]); } else { $updateRefIndex_records[] = array($this->firstTable,$mmItem); } } } $deleteAddWhere = ' AND ('.implode(' OR ', $removeClauses).')'; $GLOBALS['TYPO3_DB']->exec_DELETEquery($MM_tableName, $uidLocal_field.'='.intval($uid).$deleteAddWhere.$additionalWhere_tablenames.$additionalWhere); //add by bobo if ($this->MM_ownField) { $removeClauses = str_replace($uidForeign_field,$uidLocal_field,$removeClauses); $deleteAddWhere = '('.implode(' OR ', $removeClauses).')'; $GLOBALS['TYPO3_DB']->exec_DELETEquery($MM_tableName, $deleteAddWhere.' and '.$uidForeign_field.'='.intval($uid).$additionalWhere_tablenames.$additionalWhere); } // Update ref index: foreach($updateRefIndex_records as $pair) { $this->updateRefIndex($pair[0],$pair[1]); } } // Update ref index; In tcemain it is not certain that this will happen because if only the MM field is changed the record itself is not updated and so the ref-index is not either. This could also have been fixed in updateDB in tcemain, however I decided to do it here ... $this->updateRefIndex($this->currentTable,$uid); } } } ?>