Project

General

Profile

Bug #16166 » MMetusalem.diff

Administrator Admin, 2008-02-01 00:00

View differences:

/Users/kasper/Sites/typo3/TYPO3core/t3lib/class.t3lib_loaddbgroup.php (working copy)
require_once (PATH_t3lib.'class.t3lib_refindex.php');
......
$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;
......
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']) {
......
* @param boolean If set, then table names will always be written.
* @return void
*/
function writeMM($tableName,$uid,$prependTableName=0) {
function writeMM($MM_tableName,$uid,$prependTableName=0) {
if ($this->MM_is_foreign) { // in case of a reverse relation
$uidLocal_field = 'uid_foreign';
......
}
// 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, $tableName);
$additionalWhere.= ' AND '.$field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($value, $MM_tableName);
}
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($uidForeign_field.($prep?', tablenames':''), $tableName, $uidLocal_field.'='.$uid.$additionalWhere_tablenames.$additionalWhere);
$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:
......
}
if (in_array($item, $oldMMs)) {
unset($oldMMs[array_search($item, $oldMMs)]); // remove the item from the $oldMMs array so after this foreach loop only the ones that need to be deleted are in there.
$whereClause = $uidLocal_field.'='.$uid.' AND '.$uidForeign_field.'='.$val['id'];
$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($tableName, $whereClause.$additionalWhere, array($sorting_field => $c));
$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['tablenames'] = $tablename;
}
$GLOBALS['TYPO3_DB']->exec_INSERTquery($tableName, $insertFields);
$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();
foreach($oldMMs as $mmItem) {
if(is_array($mmItem)) {
$removeClauses[] = 'tablenames="'.$mmItem[0].'" AND '.$uidForeign_field.'='.$mmItem[1];
$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 {
$removeClauses[] = $uidForeign_field.'='.$mmItem;
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($tableName, $uidLocal_field.'='.intval($uid).$deleteAddWhere.$additionalWhere_tablenames.$additionalWhere);
$GLOBALS['TYPO3_DB']->exec_DELETEquery($MM_tableName, $uidLocal_field.'='.intval($uid).$deleteAddWhere.$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);
}
}
/**
* Remaps MM table elements from one local uid to another
* Does NOT update the reference index for you, must be called subsequently to do that!
*
* @param string MM table name
* @param integer Local, current UID
* @param integer Local, new UID
* @param boolean If set, then table names will always be written.
* @return void
*/
function remapMM($MM_tableName,$uid,$newUid,$prependTableName=0) {
if ($this->MM_is_foreign) { // in case of a reverse relation
$uidLocal_field = 'uid_foreign';
} else { // default
$uidLocal_field = 'uid_local';
}
// 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);
}
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($MM_tableName, $uidLocal_field.'='.intval($uid).$additionalWhere_tablenames.$additionalWhere, array($uidLocal_field => $newUid));
}
}
/Users/kasper/Sites/typo3/TYPO3core/t3lib/class.t3lib_tcemain.php (working copy)
if ($status=='update') {
$dbAnalysis->writeMM($tcaFieldConf['MM'],$id,$prep);
} else {
$this->dbAnalysisStore[] = array($dbAnalysis,$tcaFieldConf['MM'],$id,$prep); // This will be traversed later to execute the actions
$this->dbAnalysisStore[] = array($dbAnalysis,$tcaFieldConf['MM'],$id,$prep,$currentTable); // This will be traversed later to execute the actions
}
$valueArray = $dbAnalysis->countItems();
} elseif ($type == 'inline') {
......
$dsConf['TCEforms']['config'],
$dataValues[$key][$vKey],
$dataValues_current[$key][$vKey],
$uploadedFiles[$key][$vKey]
$uploadedFiles[$key][$vKey],
$structurePath.$key.'/'.$vKey.'/'
);
}
} else { // Default
......
$curVersion['t3ver_swapmode'] = $swapVersion['t3ver_swapmode'];
}
// Registering and swapping MM relations in current and swap records:
$this->version_remapMMForVersionSwap($table,$id,$swapWith);
// Execute swapping:
$sqlErrors = array();
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid='.intval($id),$swapVersion);
......
$swapVersion[$field] = $tempValue;
}
}
/**
* Swaps MM-relations for current/swap record, see version_swap()
*
* @param string Table for the two input records
* @param integer Current record (about to go offline)
* @param integer Swap record (about to go online)
* @return void
* @see version_swap()
*/
function version_remapMMForVersionSwap($table,$id,$swapWith) {
global $TCA;
// Actually, selecting the records fully is only need if flexforms are found inside... This could be optimized ...
$currentRec = t3lib_BEfunc::getRecord($table,$id);
$swapRec = t3lib_BEfunc::getRecord($table,$swapWith);
$this->version_remapMMForVersionSwap_reg = array();
foreach($TCA[$table]['columns'] as $field => $fConf) {
$conf = $fConf['config'];
if ($this->isReferenceField($conf)) {
$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']) {
$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
/* @var $dbAnalysis t3lib_loadDBGroup */
$dbAnalysis->start('', $allowedTables, $conf['MM'], $id, $table, $conf);
if (count($dbAnalysis->getValueArray($prependName))) {
$this->version_remapMMForVersionSwap_reg[$id][$field] = array($dbAnalysis, $conf['MM'], $prependName);
}
$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
/* @var $dbAnalysis t3lib_loadDBGroup */
$dbAnalysis->start('', $allowedTables, $conf['MM'], $swapWith, $table, $conf);
if (count($dbAnalysis->getValueArray($prependName))) {
$this->version_remapMMForVersionSwap_reg[$swapWith][$field] = array($dbAnalysis, $conf['MM'], $prependName);
}
}
} elseif($conf['type']=='flex') {
// Current record
$dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $currentRec, $table);
$currentValueArray = t3lib_div::xml2array($currentRec[$field]);
if (is_array($currentValueArray)) {
$this->checkValue_flex_procInData(
$currentValueArray['data'],
array(), // Not used.
array(), // Not used.
$dataStructArray,
array($table,$id,$field), // Parameters.
'version_remapMMForVersionSwap_flexFormCallBack'
);
}
// Swap record
$dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $swapRec, $table);
$currentValueArray = t3lib_div::xml2array($swapRec[$field]);
if (is_array($currentValueArray)) {
$this->checkValue_flex_procInData(
$currentValueArray['data'],
array(), // Not used.
array(), // Not used.
$dataStructArray,
array($table,$swapWith,$field), // Parameters.
'version_remapMMForVersionSwap_flexFormCallBack'
);
}
}
}
// Execute:
$this->version_remapMMForVersionSwap_execSwap($table,$id,$swapWith);
}
/**
* Callback function for traversing the FlexForm structure in relation to ...
*
* @param array Array of parameters in num-indexes: table, uid, field
* @param array TCA field configuration (from Data Structure XML)
* @param string The value of the flexForm field
* @param string Not used.
* @param string Not used.
* @param string Path in flexforms
* @return array Result array with key "value" containing the value of the processing.
* @see version_remapMMForVersionSwap(), checkValue_flex_procInData_travDS()
*/
function version_remapMMForVersionSwap_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $path) {
// Extract parameters:
list($table, $uid, $field) = $pParams;
if ($this->isReferenceField($dsConf)) {
$allowedTables = $dsConf['type']=='group' ? $dsConf['allowed'] : $dsConf['foreign_table'].','.$dsConf['neg_foreign_table'];
$prependName = $dsConf['type']=='group' ? $dsConf['prepend_tname'] : $dsConf['neg_foreign_table'];
if ($dsConf['MM']) {
$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
/* @var $dbAnalysis t3lib_loadDBGroup */
$dbAnalysis->start('', $allowedTables, $dsConf['MM'], $uid, $table, $dsConf);
$this->version_remapMMForVersionSwap_reg[$uid][$field.'/'.$path] = array($dbAnalysis, $dsConf['MM'], $prependName);
}
}
}
/**
* Performing the remapping operations found necessary in version_remapMMForVersionSwap()
* It must be done in three steps with an intermediate "fake" uid. The UID can be something else than -$id (fx. 9999999+$id if you dare... :-)- as long as it is unique.
*
* @param string Table for the two input records
* @param integer Current record (about to go offline)
* @param integer Swap record (about to go online)
* @return void
* @see version_remapMMForVersionSwap()
*/
function version_remapMMForVersionSwap_execSwap($table,$id,$swapWith) {
if (is_array($this->version_remapMMForVersionSwap_reg[$id])) {
foreach($this->version_remapMMForVersionSwap_reg[$id] as $field => $str) {
$str[0]->remapMM($str[1],$id,-$id,$str[2]);
}
}
if (is_array($this->version_remapMMForVersionSwap_reg[$swapWith])) {
foreach($this->version_remapMMForVersionSwap_reg[$swapWith] as $field => $str) {
$str[0]->remapMM($str[1],$swapWith,$id,$str[2]);
}
}
if (is_array($this->version_remapMMForVersionSwap_reg[$id])) {
foreach($this->version_remapMMForVersionSwap_reg[$id] as $field => $str) {
$str[0]->remapMM($str[1],-$id,$swapWith,$str[2]);
}
}
}
......
// If a change has been done, set the new value(s)
if ($set) {
if ($conf['MM']) {
$dbAnalysis->writeMM($conf['MM'], $theUidToUpdate, $prependName);
$dbAnalysis->writeMM($conf['MM'], $MM_localUid, $prependName);
} else {
$vArray = $dbAnalysis->getValueArray($prependName);
if ($conf['type']=='select') {
......
function dbAnalysisStoreExec() {
reset($this->dbAnalysisStore);
while(list($k,$v)=each($this->dbAnalysisStore)) {
$id = $this->substNEWwithIDs[$v[2]];
$id = t3lib_BEfunc::wsMapId($v[4],$this->substNEWwithIDs[$v[2]]);
if ($id) {
$v[2] = $id;
$v[0]->writeMM($v[1],$v[2],$v[3]);
(12-12/13)