|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com) 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00027 /** 00028 * Contains class for loading database groups 00029 * 00030 * $Id: class.t3lib_loaddbgroup.php 10121 2011-01-18 20:15:30Z ohader $ 00031 * Revised for TYPO3 3.6 September/2003 by Kasper Skårhøj 00032 * 00033 * @author Kasper Skårhøj <kasperYYYY@typo3.com> 00034 */ 00035 /** 00036 * [CLASS/FUNCTION INDEX of SCRIPT] 00037 * 00038 * 00039 * 00040 * 76: class t3lib_loadDBGroup 00041 * 111: function start($itemlist, $tablelist, $MMtable='', $MMuid=0, $currentTable='', $conf=array()) 00042 * 179: function readList($itemlist) 00043 * 225: function readMM($tableName,$uid) 00044 * 276: function writeMM($tableName,$uid,$prependTableName=0) 00045 * 352: function readForeignField($uid, $conf) 00046 * 435: function writeForeignField($conf, $parentUid, $updateToUid=0) 00047 * 510: function getValueArray($prependTableName='') 00048 * 538: function convertPosNeg($valueArray,$fTable,$nfTable) 00049 * 560: function getFromDB() 00050 * 595: function readyForInterface() 00051 * 621: function countItems($returnAsArray = true) 00052 * 636: function updateRefIndex($table,$id) 00053 * 00054 * TOTAL FUNCTIONS: 12 00055 * (This index is automatically created/updated by the extension "extdeveval") 00056 * 00057 */ 00058 00059 00060 /** 00061 * Load database groups (relations) 00062 * Used to process the relations created by the TCA element types "group" and "select" for database records. Manages MM-relations as well. 00063 * 00064 * @author Kasper Skårhøj <kasperYYYY@typo3.com> 00065 * @package TYPO3 00066 * @subpackage t3lib 00067 */ 00068 class t3lib_loadDBGroup { 00069 // External, static: 00070 var $fromTC = 1; // Means that only uid and the label-field is returned 00071 var $registerNonTableValues = 0; // If set, values that are not ids in tables are normally discarded. By this options they will be preserved. 00072 00073 // Internal, dynamic: 00074 var $tableArray = Array(); // Contains the table names as keys. The values are the id-values for each table. Should ONLY contain proper table names. 00075 var $itemArray = Array(); // Contains items in an numeric array (table/id for each). Tablenames here might be "_NO_TABLE" 00076 var $nonTableArray = array(); // Array for NON-table elements 00077 var $additionalWhere = array(); 00078 var $checkIfDeleted = 1; // deleted-column is added to additionalWhere... if this is set... 00079 var $dbPaths = Array(); 00080 var $firstTable = ''; // Will contain the first table name in the $tablelist (for positive ids) 00081 var $secondTable = ''; // Will contain the second table name in the $tablelist (for negative ids) 00082 // private 00083 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" 00084 var $MM_oppositeField = ''; // field name at the "local" side of the MM relation 00085 var $MM_oppositeTable = ''; // only set if MM_is_foreign is set 00086 var $MM_oppositeFieldConf = ''; // only set if MM_is_foreign is set 00087 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) 00088 var $currentTable; // current table => Only needed for reverse relations 00089 var $undeleteRecord; // if a record should be undeleted (so do not use the $useDeleteClause on t3lib_BEfunc) 00090 00091 00092 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 00093 var $MM_insert_fields = array(); // array of fields and value pairs used for insert in MM table 00094 var $MM_table_where = ''; // extra MM table where 00095 00096 /** 00097 * @var boolean 00098 */ 00099 protected $updateReferenceIndex = TRUE; 00100 00101 /** 00102 * Initialization of the class. 00103 * 00104 * @param string List of group/select items 00105 * @param string Comma list of tables, first table takes priority if no table is set for an entry in the list. 00106 * @param string Name of a MM table. 00107 * @param integer Local UID for MM lookup 00108 * @param string current table name 00109 * @param integer TCA configuration for current field 00110 * @return void 00111 */ 00112 function start($itemlist, $tablelist, $MMtable = '', $MMuid = 0, $currentTable = '', $conf = array()) { 00113 // SECTION: MM reverse relations 00114 $this->MM_is_foreign = ($conf['MM_opposite_field'] ? 1 : 0); 00115 $this->MM_oppositeField = $conf['MM_opposite_field']; 00116 $this->MM_table_where = $conf['MM_table_where']; 00117 $this->MM_hasUidField = $conf['MM_hasUidField']; 00118 $this->MM_match_fields = is_array($conf['MM_match_fields']) ? $conf['MM_match_fields'] : array(); 00119 $this->MM_insert_fields = is_array($conf['MM_insert_fields']) ? $conf['MM_insert_fields'] : $this->MM_match_fields; 00120 00121 $this->currentTable = $currentTable; 00122 if ($this->MM_is_foreign) { 00123 $tmp = ($conf['type'] === 'group' ? $conf['allowed'] : $conf['foreign_table']); 00124 // 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'] 00125 $tmp = t3lib_div::trimExplode(',', $tmp); 00126 $this->MM_oppositeTable = $tmp[0]; 00127 unset($tmp); 00128 00129 // only add the current table name if there is more than one allowed field 00130 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. 00131 $this->MM_oppositeFieldConf = $GLOBALS['TCA'][$this->MM_oppositeTable]['columns'][$this->MM_oppositeField]['config']; 00132 00133 if ($this->MM_oppositeFieldConf['allowed']) { 00134 $oppositeFieldConf_allowed = explode(',', $this->MM_oppositeFieldConf['allowed']); 00135 if (count($oppositeFieldConf_allowed) > 1) { 00136 $this->MM_isMultiTableRelationship = $oppositeFieldConf_allowed[0]; 00137 } 00138 } 00139 } 00140 00141 // SECTION: normal MM relations 00142 00143 // If the table list is "*" then all tables are used in the list: 00144 if (!strcmp(trim($tablelist), '*')) { 00145 $tablelist = implode(',', array_keys($GLOBALS['TCA'])); 00146 } 00147 00148 // The tables are traversed and internal arrays are initialized: 00149 $tempTableArray = t3lib_div::trimExplode(',', $tablelist, 1); 00150 foreach ($tempTableArray as $key => $val) { 00151 $tName = trim($val); 00152 $this->tableArray[$tName] = Array(); 00153 if ($this->checkIfDeleted && $GLOBALS['TCA'][$tName]['ctrl']['delete']) { 00154 $fieldN = $tName . '.' . $GLOBALS['TCA'][$tName]['ctrl']['delete']; 00155 $this->additionalWhere[$tName] .= ' AND ' . $fieldN . '=0'; 00156 } 00157 } 00158 00159 if (is_array($this->tableArray)) { 00160 reset($this->tableArray); 00161 } else { 00162 return 'No tables!'; 00163 } 00164 00165 // Set first and second tables: 00166 $this->firstTable = key($this->tableArray); // Is the first table 00167 next($this->tableArray); 00168 $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... 00169 00170 // Now, populate the internal itemArray and tableArray arrays: 00171 if ($MMtable) { // If MM, then call this function to do that: 00172 if ($MMuid) { 00173 $this->readMM($MMtable, $MMuid); 00174 } else { // Revert to readList() for new records in order to load possible default values from $itemlist 00175 $this->readList($itemlist); 00176 } 00177 } elseif ($MMuid && $conf['foreign_field']) { 00178 // If not MM but foreign_field, the read the records by the foreign_field 00179 $this->readForeignField($MMuid, $conf); 00180 } else { 00181 // If not MM, then explode the itemlist by "," and traverse the list: 00182 $this->readList($itemlist); 00183 // do automatic default_sortby, if any 00184 if ($conf['foreign_default_sortby']) { 00185 $this->sortList($conf['foreign_default_sortby']); 00186 } 00187 } 00188 } 00189 00190 /** 00191 * Sets whether the reference index shall be updated. 00192 * 00193 * @param boolean $updateReferenceIndex Whether the reference index shall be updated 00194 * @return void 00195 */ 00196 public function setUpdateReferenceIndex($updateReferenceIndex) { 00197 $this->updateReferenceIndex = (bool) $updateReferenceIndex; 00198 } 00199 00200 /** 00201 * Explodes the item list and stores the parts in the internal arrays itemArray and tableArray from MM records. 00202 * 00203 * @param string Item list 00204 * @return void 00205 */ 00206 function readList($itemlist) { 00207 if ((string) trim($itemlist) != '') { 00208 $tempItemArray = t3lib_div::trimExplode(',', $itemlist); // Changed to trimExplode 31/3 04; HMENU special type "list" didn't work if there were spaces in the list... I suppose this is better overall... 00209 foreach ($tempItemArray as $key => $val) { 00210 $isSet = 0; // Will be set to "1" if the entry was a real table/id: 00211 00212 // Extract table name and id. This is un the formular [tablename]_[id] where table name MIGHT contain "_", hence the reversion of the string! 00213 $val = strrev($val); 00214 $parts = explode('_', $val, 2); 00215 $theID = strrev($parts[0]); 00216 00217 // Check that the id IS an integer: 00218 if (t3lib_div::testInt($theID)) { 00219 // Get the table name: If a part of the exploded string, use that. Otherwise if the id number is LESS than zero, use the second table, otherwise the first table 00220 $theTable = trim($parts[1]) ? strrev(trim($parts[1])) : ($this->secondTable && $theID < 0 ? $this->secondTable : $this->firstTable); 00221 // If the ID is not blank and the table name is among the names in the inputted tableList, then proceed: 00222 if ((string) $theID != '' && $theID && $theTable && isset($this->tableArray[$theTable])) { 00223 // Get ID as the right value: 00224 $theID = $this->secondTable ? abs(intval($theID)) : intval($theID); 00225 // Register ID/table name in internal arrays: 00226 $this->itemArray[$key]['id'] = $theID; 00227 $this->itemArray[$key]['table'] = $theTable; 00228 $this->tableArray[$theTable][] = $theID; 00229 // Set update-flag: 00230 $isSet = 1; 00231 } 00232 } 00233 00234 // If it turns out that the value from the list was NOT a valid reference to a table-record, then we might still set it as a NO_TABLE value: 00235 if (!$isSet && $this->registerNonTableValues) { 00236 $this->itemArray[$key]['id'] = $tempItemArray[$key]; 00237 $this->itemArray[$key]['table'] = '_NO_TABLE'; 00238 $this->nonTableArray[] = $tempItemArray[$key]; 00239 } 00240 } 00241 } 00242 } 00243 00244 /** 00245 * Does a sorting on $this->itemArray depending on a default sortby field. 00246 * This is only used for automatic sorting of comma separated lists. 00247 * This function is only relevant for data that is stored in comma separated lists! 00248 * 00249 * @param string $sortby: The default_sortby field/command (e.g. 'price DESC') 00250 * @return void 00251 */ 00252 function sortList($sortby) { 00253 // sort directly without fetching addional data 00254 if ($sortby == 'uid') { 00255 usort($this->itemArray, create_function('$a,$b', 'return $a["id"] < $b["id"] ? -1 : 1;')); 00256 // only useful if working on the same table 00257 } elseif (count($this->tableArray) == 1) { 00258 reset($this->tableArray); 00259 $table = key($this->tableArray); 00260 $uidList = implode(',', current($this->tableArray)); 00261 00262 if ($uidList) { 00263 $this->itemArray = array(); 00264 $this->tableArray = array(); 00265 00266 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'uid IN (' . $uidList . ')', '', $sortby); 00267 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { 00268 $this->itemArray[] = array('id' => $row['uid'], 'table' => $table); 00269 $this->tableArray[$table][] = $row['uid']; 00270 } 00271 $GLOBALS['TYPO3_DB']->sql_free_result($res); 00272 } 00273 } 00274 } 00275 00276 /** 00277 * Reads the record tablename/id into the internal arrays itemArray and tableArray from MM records. 00278 * You can call this function after start if you supply no list to start() 00279 * 00280 * @param string MM Tablename 00281 * @param integer Local UID 00282 * @return void 00283 */ 00284 function readMM($tableName, $uid) { 00285 $key = 0; 00286 $additionalWhere = ''; 00287 00288 if ($this->MM_is_foreign) { // in case of a reverse relation 00289 $uidLocal_field = 'uid_foreign'; 00290 $uidForeign_field = 'uid_local'; 00291 $sorting_field = 'sorting_foreign'; 00292 00293 if ($this->MM_isMultiTableRelationship) { 00294 $additionalWhere .= ' AND ( tablenames=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->currentTable, $tableName); 00295 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. 00296 $additionalWhere .= ' OR tablenames=\'\''; 00297 } 00298 $additionalWhere .= ' ) '; 00299 } 00300 $theTable = $this->MM_oppositeTable; 00301 } else { // default 00302 $uidLocal_field = 'uid_local'; 00303 $uidForeign_field = 'uid_foreign'; 00304 $sorting_field = 'sorting'; 00305 } 00306 00307 00308 if ($this->MM_table_where) { 00309 $additionalWhere .= LF . str_replace('###THIS_UID###', intval($uid), $this->MM_table_where); 00310 } 00311 foreach ($this->MM_match_fields as $field => $value) { 00312 $additionalWhere .= ' AND ' . $field . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($value, $tableName); 00313 } 00314 00315 // Select all MM relations: 00316 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $tableName, $uidLocal_field . '=' . intval($uid) . $additionalWhere, '', $sorting_field); 00317 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { 00318 if (!$this->MM_is_foreign) { // default 00319 $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... 00320 } 00321 if (($row[$uidForeign_field] || $theTable == 'pages') && $theTable && isset($this->tableArray[$theTable])) { 00322 00323 $this->itemArray[$key]['id'] = $row[$uidForeign_field]; 00324 $this->itemArray[$key]['table'] = $theTable; 00325 $this->tableArray[$theTable][] = $row[$uidForeign_field]; 00326 } elseif ($this->registerNonTableValues) { 00327 $this->itemArray[$key]['id'] = $row[$uidForeign_field]; 00328 $this->itemArray[$key]['table'] = '_NO_TABLE'; 00329 $this->nonTableArray[] = $row[$uidForeign_field]; 00330 } 00331 $key++; 00332 } 00333 $GLOBALS['TYPO3_DB']->sql_free_result($res); 00334 } 00335 00336 /** 00337 * Writes the internal itemArray to MM table: 00338 * 00339 * @param string MM table name 00340 * @param integer Local UID 00341 * @param boolean If set, then table names will always be written. 00342 * @return void 00343 */ 00344 function writeMM($MM_tableName, $uid, $prependTableName = 0) { 00345 00346 if ($this->MM_is_foreign) { // in case of a reverse relation 00347 $uidLocal_field = 'uid_foreign'; 00348 $uidForeign_field = 'uid_local'; 00349 $sorting_field = 'sorting_foreign'; 00350 } else { // default 00351 $uidLocal_field = 'uid_local'; 00352 $uidForeign_field = 'uid_foreign'; 00353 $sorting_field = 'sorting'; 00354 } 00355 00356 // If there are tables... 00357 $tableC = count($this->tableArray); 00358 if ($tableC) { 00359 $prep = ($tableC > 1 || $prependTableName || $this->MM_isMultiTableRelationship) ? 1 : 0; // boolean: does the field "tablename" need to be filled? 00360 $c = 0; 00361 00362 $additionalWhere_tablenames = ''; 00363 if ($this->MM_is_foreign && $prep) { 00364 $additionalWhere_tablenames = ' AND tablenames=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->currentTable, $MM_tableName); 00365 } 00366 00367 $additionalWhere = ''; 00368 // add WHERE clause if configured 00369 if ($this->MM_table_where) { 00370 $additionalWhere .= LF . str_replace('###THIS_UID###', intval($uid), $this->MM_table_where); 00371 } 00372 // Select, update or delete only those relations that match the configured fields 00373 foreach ($this->MM_match_fields as $field => $value) { 00374 $additionalWhere .= ' AND ' . $field . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($value, $MM_tableName); 00375 } 00376 00377 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 00378 $uidForeign_field . ($prep ? ', tablenames' : '') . ($this->MM_hasUidField ? ', uid' : ''), 00379 $MM_tableName, 00380 $uidLocal_field . '=' . $uid . $additionalWhere_tablenames . $additionalWhere, 00381 '', 00382 $sorting_field 00383 ); 00384 00385 $oldMMs = array(); 00386 $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 00387 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { 00388 if (!$this->MM_is_foreign && $prep) { 00389 $oldMMs[] = array($row['tablenames'], $row[$uidForeign_field]); 00390 } else { 00391 $oldMMs[] = $row[$uidForeign_field]; 00392 } 00393 $oldMMs_inclUid[] = array($row['tablenames'], $row[$uidForeign_field], $row['uid']); 00394 } 00395 00396 // For each item, insert it: 00397 foreach ($this->itemArray as $val) { 00398 $c++; 00399 00400 if ($prep || $val['table'] == '_NO_TABLE') { 00401 if ($this->MM_is_foreign) { // insert current table if needed 00402 $tablename = $this->currentTable; 00403 } else { 00404 $tablename = $val['table']; 00405 } 00406 } else { 00407 $tablename = ''; 00408 } 00409 00410 if (!$this->MM_is_foreign && $prep) { 00411 $item = array($val['table'], $val['id']); 00412 } else { 00413 $item = $val['id']; 00414 } 00415 00416 if (in_array($item, $oldMMs)) { 00417 $oldMMs_index = array_search($item, $oldMMs); 00418 00419 $whereClause = $uidLocal_field . '=' . $uid . ' AND ' . $uidForeign_field . '=' . $val['id'] . 00420 ($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. 00421 if ($tablename) { 00422 $whereClause .= ' AND tablenames=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($tablename, $MM_tableName); 00423 } 00424 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($MM_tableName, $whereClause . $additionalWhere, array($sorting_field => $c)); 00425 00426 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. 00427 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. 00428 } else { 00429 00430 $insertFields = $this->MM_insert_fields; 00431 $insertFields[$uidLocal_field] = $uid; 00432 $insertFields[$uidForeign_field] = $val['id']; 00433 $insertFields[$sorting_field] = $c; 00434 if ($tablename) { 00435 $insertFields['tablenames'] = $tablename; 00436 } 00437 00438 $GLOBALS['TYPO3_DB']->exec_INSERTquery($MM_tableName, $insertFields); 00439 00440 if ($this->MM_is_foreign) { 00441 $this->updateRefIndex($val['table'], $val['id']); 00442 } 00443 } 00444 } 00445 00446 // Delete all not-used relations: 00447 if (is_array($oldMMs) && count($oldMMs) > 0) { 00448 $removeClauses = array(); 00449 $updateRefIndex_records = array(); 00450 foreach ($oldMMs as $oldMM_key => $mmItem) { 00451 if ($this->MM_hasUidField) { // If UID field is present, of course we need only use that for deleting...: 00452 $removeClauses[] = 'uid=' . intval($oldMMs_inclUid[$oldMM_key][2]); 00453 $elDelete = $oldMMs_inclUid[$oldMM_key]; 00454 } else { 00455 if (is_array($mmItem)) { 00456 $removeClauses[] = 'tablenames=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($mmItem[0], $MM_tableName) . ' AND ' . $uidForeign_field . '=' . $mmItem[1]; 00457 } else { 00458 $removeClauses[] = $uidForeign_field . '=' . $mmItem; 00459 } 00460 } 00461 if ($this->MM_is_foreign) { 00462 if (is_array($mmItem)) { 00463 $updateRefIndex_records[] = array($mmItem[0], $mmItem[1]); 00464 } else { 00465 $updateRefIndex_records[] = array($this->firstTable, $mmItem); 00466 } 00467 } 00468 } 00469 $deleteAddWhere = ' AND (' . implode(' OR ', $removeClauses) . ')'; 00470 $GLOBALS['TYPO3_DB']->exec_DELETEquery($MM_tableName, $uidLocal_field . '=' . intval($uid) . $deleteAddWhere . $additionalWhere_tablenames . $additionalWhere); 00471 00472 // Update ref index: 00473 foreach ($updateRefIndex_records as $pair) { 00474 $this->updateRefIndex($pair[0], $pair[1]); 00475 } 00476 } 00477 00478 // 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 ... 00479 $this->updateRefIndex($this->currentTable, $uid); 00480 } 00481 } 00482 00483 /** 00484 * Remaps MM table elements from one local uid to another 00485 * Does NOT update the reference index for you, must be called subsequently to do that! 00486 * 00487 * @param string MM table name 00488 * @param integer Local, current UID 00489 * @param integer Local, new UID 00490 * @param boolean If set, then table names will always be written. 00491 * @return void 00492 */ 00493 function remapMM($MM_tableName, $uid, $newUid, $prependTableName = 0) { 00494 00495 if ($this->MM_is_foreign) { // in case of a reverse relation 00496 $uidLocal_field = 'uid_foreign'; 00497 } else { // default 00498 $uidLocal_field = 'uid_local'; 00499 } 00500 00501 // If there are tables... 00502 $tableC = count($this->tableArray); 00503 if ($tableC) { 00504 $prep = ($tableC > 1 || $prependTableName || $this->MM_isMultiTableRelationship) ? 1 : 0; // boolean: does the field "tablename" need to be filled? 00505 $c = 0; 00506 00507 $additionalWhere_tablenames = ''; 00508 if ($this->MM_is_foreign && $prep) { 00509 $additionalWhere_tablenames = ' AND tablenames=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->currentTable, $MM_tableName); 00510 } 00511 00512 $additionalWhere = ''; 00513 // add WHERE clause if configured 00514 if ($this->MM_table_where) { 00515 $additionalWhere .= LF . str_replace('###THIS_UID###', intval($uid), $this->MM_table_where); 00516 } 00517 // Select, update or delete only those relations that match the configured fields 00518 foreach ($this->MM_match_fields as $field => $value) { 00519 $additionalWhere .= ' AND ' . $field . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($value, $MM_tableName); 00520 } 00521 00522 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($MM_tableName, $uidLocal_field . '=' . intval($uid) . $additionalWhere_tablenames . $additionalWhere, array($uidLocal_field => $newUid)); 00523 } 00524 } 00525 00526 /** 00527 * Reads items from a foreign_table, that has a foreign_field (uid of the parent record) and 00528 * stores the parts in the internal array itemArray and tableArray. 00529 * 00530 * @param integer $uid: The uid of the parent record (this value is also on the foreign_table in the foreign_field) 00531 * @param array $conf: TCA configuration for current field 00532 * @return void 00533 */ 00534 function readForeignField($uid, $conf) { 00535 $key = 0; 00536 $uid = intval($uid); 00537 $whereClause = ''; 00538 $foreign_table = $conf['foreign_table']; 00539 $foreign_table_field = $conf['foreign_table_field']; 00540 $useDeleteClause = $this->undeleteRecord ? FALSE : TRUE; 00541 00542 // search for $uid in foreign_field, and if we have symmetric relations, do this also on symmetric_field 00543 if ($conf['symmetric_field']) { 00544 $whereClause = '(' . $conf['foreign_field'] . '=' . $uid . ' OR ' . $conf['symmetric_field'] . '=' . $uid . ')'; 00545 } else { 00546 $whereClause = $conf['foreign_field'] . '=' . $uid; 00547 } 00548 // use the deleteClause (e.g. "deleted=0") on this table 00549 if ($useDeleteClause) { 00550 $whereClause .= t3lib_BEfunc::deleteClause($foreign_table); 00551 } 00552 // if it's requested to look for the parent uid AND the parent table, 00553 // add an additional SQL-WHERE clause 00554 if ($foreign_table_field && $this->currentTable) { 00555 $whereClause .= ' AND ' . $foreign_table_field . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->currentTable, $foreign_table); 00556 } 00557 00558 // Select children in the same workspace: 00559 if (t3lib_BEfunc::isTableWorkspaceEnabled($this->currentTable) && t3lib_BEfunc::isTableWorkspaceEnabled($foreign_table)) { 00560 $currentRecord = t3lib_BEfunc::getRecord($this->currentTable, $uid, 't3ver_wsid', '', $useDeleteClause); 00561 $whereClause .= t3lib_BEfunc::getWorkspaceWhereClause($foreign_table, $currentRecord['t3ver_wsid']); 00562 } 00563 00564 // get the correct sorting field 00565 if ($conf['foreign_sortby']) { // specific manual sortby for data handled by this field 00566 if ($conf['symmetric_sortby'] && $conf['symmetric_field']) { 00567 // sorting depends on, from which side of the relation we're looking at it 00568 $sortby = ' 00569 CASE 00570 WHEN ' . $conf['foreign_field'] . '=' . $uid . ' 00571 THEN ' . $conf['foreign_sortby'] . ' 00572 ELSE ' . $conf['symmetric_sortby'] . ' 00573 END'; 00574 } else { 00575 // regular single-side behaviour 00576 $sortby = $conf['foreign_sortby']; 00577 } 00578 } elseif ($conf['foreign_default_sortby']) { // specific default sortby for data handled by this field 00579 $sortby = $conf['foreign_default_sortby']; 00580 } elseif ($GLOBALS['TCA'][$foreign_table]['ctrl']['sortby']) { // manual sortby for all table records 00581 $sortby = $GLOBALS['TCA'][$foreign_table]['ctrl']['sortby']; 00582 } elseif ($GLOBALS['TCA'][$foreign_table]['ctrl']['default_sortby']) { // default sortby for all table records 00583 $sortby = $GLOBALS['TCA'][$foreign_table]['ctrl']['default_sortby']; 00584 } 00585 00586 // strip a possible "ORDER BY" in front of the $sortby value 00587 $sortby = $GLOBALS['TYPO3_DB']->stripOrderBy($sortby); 00588 // get the rows from storage 00589 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid', $foreign_table, $whereClause, '', $sortby); 00590 00591 if (count($rows)) { 00592 foreach ($rows as $row) { 00593 $this->itemArray[$key]['id'] = $row['uid']; 00594 $this->itemArray[$key]['table'] = $foreign_table; 00595 $this->tableArray[$foreign_table][] = $row['uid']; 00596 $key++; 00597 } 00598 } 00599 } 00600 00601 /** 00602 * Write the sorting values to a foreign_table, that has a foreign_field (uid of the parent record) 00603 * 00604 * @param array $conf: TCA configuration for current field 00605 * @param integer $parentUid: The uid of the parent record 00606 * @param boolean $updateToUid: Whether to update the foreign field with the $parentUid (on Copy) 00607 * @param boolean $skipSorting: Do not update the sorting columns, this could happen for imported values 00608 * @return void 00609 */ 00610 function writeForeignField($conf, $parentUid, $updateToUid = 0, $skipSorting = FALSE) { 00611 $c = 0; 00612 $foreign_table = $conf['foreign_table']; 00613 $foreign_field = $conf['foreign_field']; 00614 $symmetric_field = $conf['symmetric_field']; 00615 $foreign_table_field = $conf['foreign_table_field']; 00616 00617 // if there are table items and we have a proper $parentUid 00618 if (t3lib_div::testInt($parentUid) && count($this->tableArray)) { 00619 // if updateToUid is not a positive integer, set it to '0', so it will be ignored 00620 if (!(t3lib_div::testInt($updateToUid) && $updateToUid > 0)) { 00621 $updateToUid = 0; 00622 } 00623 00624 $considerWorkspaces = ($GLOBALS['BE_USER']->workspace !== 0 && t3lib_BEfunc::isTableWorkspaceEnabled($foreign_table)); 00625 00626 $fields = 'uid,' . $foreign_field; 00627 // Consider the symmetric field if defined: 00628 if ($symmetric_field) { 00629 $fields .= ',' . $symmetric_field; 00630 } 00631 // Consider workspaces if defined and currently used: 00632 if ($considerWorkspaces) { 00633 $fields .= ',' . 't3ver_state,t3ver_oid'; 00634 } 00635 00636 // update all items 00637 foreach ($this->itemArray as $val) { 00638 $uid = $val['id']; 00639 $table = $val['table']; 00640 00641 // fetch the current (not overwritten) relation record if we should handle symmetric relations 00642 if ($symmetric_field || $considerWorkspaces) { 00643 $row = t3lib_BEfunc::getRecord($table, $uid, $fields, '', FALSE); 00644 } 00645 if ($symmetric_field) { 00646 $isOnSymmetricSide = t3lib_loadDBGroup::isOnSymmetricSide($parentUid, $conf, $row); 00647 } 00648 00649 $updateValues = array(); 00650 $workspaceValues = array(); 00651 00652 // no update to the uid is requested, so this is the normal behaviour 00653 // just update the fields and care about sorting 00654 if (!$updateToUid) { 00655 // Always add the pointer to the parent uid 00656 if ($isOnSymmetricSide) { 00657 $updateValues[$symmetric_field] = $parentUid; 00658 } else { 00659 $updateValues[$foreign_field] = $parentUid; 00660 } 00661 00662 // if it is configured in TCA also to store the parent table in the child record, just do it 00663 if ($foreign_table_field && $this->currentTable) { 00664 $updateValues[$foreign_table_field] = $this->currentTable; 00665 } 00666 00667 // update sorting columns if not to be skipped 00668 if (!$skipSorting) { 00669 // get the correct sorting field 00670 if ($conf['foreign_sortby']) { // specific manual sortby for data handled by this field 00671 $sortby = $conf['foreign_sortby']; 00672 } elseif ($GLOBALS['TCA'][$foreign_table]['ctrl']['sortby']) { // manual sortby for all table records 00673 $sortby = $GLOBALS['TCA'][$foreign_table]['ctrl']['sortby']; 00674 } 00675 // Apply sorting on the symmetric side (it depends on who created the relation, so what uid is in the symmetric_field): 00676 if ($isOnSymmetricSide && isset($conf['symmetric_sortby']) && $conf['symmetric_sortby']) { 00677 $sortby = $conf['symmetric_sortby']; 00678 // Strip a possible "ORDER BY" in front of the $sortby value: 00679 } else { 00680 $sortby = $GLOBALS['TYPO3_DB']->stripOrderBy($sortby); 00681 } 00682 00683 if ($sortby) { 00684 $updateValues[$sortby] = $workspaceValues[$sortby] = ++$c; 00685 } 00686 } 00687 00688 // update to a foreign_field/symmetric_field pointer is requested, normally used on record copies 00689 // only update the fields, if the old uid is found somewhere - for select fields, TCEmain is doing this already! 00690 } else { 00691 if ($isOnSymmetricSide) { 00692 $updateValues[$symmetric_field] = $updateToUid; 00693 } else { 00694 $updateValues[$foreign_field] = $updateToUid; 00695 } 00696 } 00697 00698 // Update accordant fields in the database: 00699 if (count($updateValues)) { 00700 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($uid), $updateValues); 00701 $this->updateRefIndex($table, $uid); 00702 } 00703 // Update accordant fields in the database for workspaces overlays/placeholders: 00704 if (count($workspaceValues) && $considerWorkspaces) { 00705 if (isset($row['t3ver_oid']) && $row['t3ver_oid'] && $row['t3ver_state'] == -1) { 00706 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($row['t3ver_oid']), $workspaceValues); 00707 } 00708 } 00709 } 00710 } 00711 } 00712 00713 /** 00714 * After initialization you can extract an array of the elements from the object. Use this function for that. 00715 * 00716 * @param boolean If set, then table names will ALWAYS be prepended (unless its a _NO_TABLE value) 00717 * @return array A numeric array. 00718 */ 00719 function getValueArray($prependTableName = '') { 00720 // INIT: 00721 $valueArray = Array(); 00722 $tableC = count($this->tableArray); 00723 00724 // If there are tables in the table array: 00725 if ($tableC) { 00726 // If there are more than ONE table in the table array, then always prepend table names: 00727 $prep = ($tableC > 1 || $prependTableName) ? 1 : 0; 00728 00729 // Traverse the array of items: 00730 foreach ($this->itemArray as $val) { 00731 $valueArray[] = (($prep && $val['table'] != '_NO_TABLE') ? $val['table'] . '_' : '') . 00732 $val['id']; 00733 } 00734 } 00735 // Return the array 00736 return $valueArray; 00737 } 00738 00739 /** 00740 * Converts id numbers from negative to positive. 00741 * 00742 * @param array Array of [table]_[id] pairs. 00743 * @param string Foreign table (the one used for positive numbers) 00744 * @param string NEGative foreign table 00745 * @return array The array with ID integer values, converted to positive for those where the table name was set but did NOT match the positive foreign table. 00746 */ 00747 function convertPosNeg($valueArray, $fTable, $nfTable) { 00748 if (is_array($valueArray) && $fTable) { 00749 foreach ($valueArray as $key => $val) { 00750 $val = strrev($val); 00751 $parts = explode('_', $val, 2); 00752 $theID = strrev($parts[0]); 00753 $theTable = strrev($parts[1]); 00754 00755 if (t3lib_div::testInt($theID) && (!$theTable || !strcmp($theTable, $fTable) || !strcmp($theTable, $nfTable))) { 00756 $valueArray[$key] = $theTable && strcmp($theTable, $fTable) ? $theID * -1 : $theID; 00757 } 00758 } 00759 } 00760 return $valueArray; 00761 } 00762 00763 /** 00764 * Reads all records from internal tableArray into the internal ->results array where keys are table names and for each table, records are stored with uids as their keys. 00765 * If $this->fromTC is set you can save a little memory since only uid,pid and a few other fields are selected. 00766 * 00767 * @return void 00768 */ 00769 function getFromDB() { 00770 // Traverses the tables listed: 00771 foreach ($this->tableArray as $key => $val) { 00772 if (is_array($val)) { 00773 $itemList = implode(',', $val); 00774 if ($itemList) { 00775 $from = '*'; 00776 if ($this->fromTC) { 00777 $from = 'uid,pid'; 00778 if ($GLOBALS['TCA'][$key]['ctrl']['label']) { 00779 $from .= ',' . $GLOBALS['TCA'][$key]['ctrl']['label']; // Titel 00780 } 00781 if ($GLOBALS['TCA'][$key]['ctrl']['label_alt']) { 00782 $from .= ',' . $GLOBALS['TCA'][$key]['ctrl']['label_alt']; // Alternative Title-Fields 00783 } 00784 if ($GLOBALS['TCA'][$key]['ctrl']['thumbnail']) { 00785 $from .= ',' . $GLOBALS['TCA'][$key]['ctrl']['thumbnail']; // Thumbnail 00786 } 00787 } 00788 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($from, $key, 'uid IN (' . $itemList . ')' . $this->additionalWhere[$key]); 00789 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { 00790 $this->results[$key][$row['uid']] = $row; 00791 } 00792 } 00793 } 00794 } 00795 return $this->results; 00796 } 00797 00798 /** 00799 * Prepare items from itemArray to be transferred to the TCEforms interface (as a comma list) 00800 * 00801 * @return string 00802 * @see t3lib_transferdata::renderRecord() 00803 */ 00804 function readyForInterface() { 00805 global $TCA; 00806 00807 if (!is_array($this->itemArray)) { 00808 return FALSE; 00809 } 00810 00811 $output = array(); 00812 $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1); // For use when getting the paths.... 00813 $titleLen = intval($GLOBALS['BE_USER']->uc['titleLen']); 00814 00815 foreach ($this->itemArray as $key => $val) { 00816 $theRow = $this->results[$val['table']][$val['id']]; 00817 if ($theRow && is_array($TCA[$val['table']])) { 00818 $label = t3lib_div::fixed_lgd_cs(strip_tags(t3lib_BEfunc::getRecordTitle($val['table'], $theRow)), $titleLen); 00819 $label = ($label) ? $label : '[...]'; 00820 $output[] = str_replace(',', '', $val['table'] . '_' . $val['id'] . '|' . rawurlencode($label)); 00821 } 00822 } 00823 return implode(',', $output); 00824 } 00825 00826 /** 00827 * Counts the items in $this->itemArray and puts this value in an array by default. 00828 * 00829 * @param boolean Whether to put the count value in an array 00830 * @return mixed The plain count as integer or the same inside an array 00831 */ 00832 function countItems($returnAsArray = TRUE) { 00833 $count = count($this->itemArray); 00834 if ($returnAsArray) { 00835 $count = array($count); 00836 } 00837 return $count; 00838 } 00839 00840 /** 00841 * Update Reference Index (sys_refindex) for a record 00842 * Should be called any almost any update to a record which could affect references inside the record. 00843 * (copied from TCEmain) 00844 * 00845 * @param string Table name 00846 * @param integer Record UID 00847 * @return array Information concerning modifications delivered by t3lib_refindex::updateRefIndexTable() 00848 */ 00849 function updateRefIndex($table, $id) { 00850 if ($this->updateReferenceIndex === TRUE) { 00851 /** @var $refIndexObj t3lib_refindex */ 00852 $refIndexObj = t3lib_div::makeInstance('t3lib_refindex'); 00853 return $refIndexObj->updateRefIndexTable($table, $id); 00854 } 00855 } 00856 00857 /** 00858 * Checks, if we're looking from the "other" side, the symmetric side, to a symmetric relation. 00859 * 00860 * @param string $parentUid: The uid of the parent record 00861 * @param array $parentConf: The TCA configuration of the parent field embedding the child records 00862 * @param array $childRec: The record row of the child record 00863 * @return boolean Returns true if looking from the symmetric ("other") side to the relation. 00864 */ 00865 function isOnSymmetricSide($parentUid, $parentConf, $childRec) { 00866 return t3lib_div::testInt($childRec['uid']) && $parentConf['symmetric_field'] && $parentUid == $childRec[$parentConf['symmetric_field']] 00867 ? TRUE 00868 : FALSE; 00869 } 00870 } 00871 00872 00873 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_loaddbgroup.php'])) { 00874 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_loaddbgroup.php']); 00875 } 00876 00877 ?>
1.8.0