Project

General

Profile

Bug #15579 » class.t3lib_loaddbgroup.php

Administrator Admin, 2006-03-16 12:16

 
<?php
/***************************************************************
* Copyright notice
*
* (c) 1999-2005 Kasper Skaarhoj (kasperYYYY@typo3.com)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
* A copy is found in the textfile GPL.txt and important notices to the license
* from the author is found in LICENSE.txt distributed with these scripts.
*
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/**
* Contains class for loading database groups
*
* $Id: class.t3lib_loaddbgroup.php,v 1.12.6.3 2006/03/16 11:12:12 rfritz Exp $
* Revised for TYPO3 3.6 September/2003 by Kasper Skaarhoj
*
* @author Kasper Skaarhoj <kasperYYYY@typo3.com>
*/
/**
* [CLASS/FUNCTION INDEX of SCRIPT]
*
*
*
* 72: class t3lib_loadDBGroup
* 99: function start($itemlist,$tablelist, $MMtable='',$MMuid=0)
* 140: function readList($itemlist)
* 186: function readMM($tableName,$uid)
* 215: function writeMM($tableName,$uid,$prependTableName=0)
* 251: function getValueArray($prependTableName='')
* 279: function convertPosNeg($valueArray,$fTable,$nfTable)
* 301: function getFromDB()
* 333: function readyForInterface()
*
* TOTAL FUNCTIONS: 8
* (This index is automatically created/updated by the extension "extdeveval")
*
*/










/**
* Load database groups (relations)
* Used to process the relations created by the TCA element types "group" and "select" for database records. Manages MM-relations as well.
*
* @author Kasper Skaarhoj <kasperYYYY@typo3.com>
* @package TYPO3
* @subpackage t3lib
*/
class t3lib_loadDBGroup {

/**
* Means that only uid and the label-field is returned
*/
var $fromTC = true;

/**
* Will exclude deleted records.
* deleted-column is added to $additionalWhere...
*/
var $checkIfDeleted = true;

/**
* If set, values that are not ids in tables are normally discarded.
* By this options they will be preserved and stored in $itemArray.
*/
var $registerNonTableValues = false;

/**
* Usded to collect NON-table elements if registerNonTableValues = true
*/
var $nonTableArray = array();



/**
* Contains the table names htat are allowed for the relation as keys.
* The values are the id-values for each table. Should ONLY contain proper table names.
*/
var $tableArray = array();

/**
* Contains items in an numeric array (table/id for each). Tablenames here might be "_NO_TABLE"
*/
var $itemArray = array();



var $additionalWhere = array(); // used for additional where clause like "AND table.delete=0"
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)



// MM stuff for foreign select

/**
* field value pairs that should match while select and to be set while insert
*/
var $MMmatchFields = array();

/**
* Extra field value pairs that should be set while insert
*/
var $MMinsertFields = array();

/**
* The name of the local table. Needed for foreign select
*/
var $MMlocalTable = '';

/**
* The tablenames field should match this list
*/
var $MMmatchTablenames = '';

/**
* Extra table where clause
*/
var $MMtableWhere = '';

/**
* If true this is a foregin select and uid's needs to be swapped
*/
var $MMswapLocalForeign = false;




/**
* Initialization of the class.
*
* Known parameter from TCA:
*
* MM_foreign_select
* MM_table_where
* MM_insert_fields
* prepend_tname
* allowed
*
* @param string Name of the local table
* @param array Configuration array coming from TCA.
* @return void
*/
function init($thisTable, $MMconf) {

// the local table name, needed for foreign select
$this->MMlocalTable = $thisTable;

// If set, uid_local and uid_foreign field names will be swapped
$this->MMswapLocalForeign = $MMconf['MM_foreign_select'];

// extra MM table where
$this->MMtableWhere = $MMconf['MM_table_where'];

// array of fields value pairs that should match while SELECT and will be written into MM table
$this->MMmatchFields = is_array($MMconf['MM_match_fields']) ? $MMconf['MM_match_fields'] : array();

// array of fields and value pairs used for insert in MM table
$this->MMinsertFields = is_array($MMconf['MM_insert_fields']) ? $MMconf['MM_insert_fields'] : $this->MMmatchFields;

// the "tablenames" field will be queried with this table name list if needed.
$this->MMmatchTablenames = '';
if ($MMconf['prepend_tname'] && $MMconf['MM_foreign_select']) {
$this->MMmatchTablenames = $this->MMlocalTable;
}
}


/**
* Start of the MM handling. Reads relations.
*
* @param string List of group/select items. Possible format: tablename_uid,tablename2_uid
* @param string Comma list of allowed tables, first table takes priority if no table is set for an entry in the item list.
* @param string Name of a MM table.
* @param integer Local UID for MM lookup
* @return void
*/
function start($itemlist, $tablelist, $MMtable='', $MMuid=0) {

// If the table list is "*" then all tables are used in the list:
if (!strcmp(trim($tablelist),'*')) {
$tablelist = implode(',',array_keys($GLOBALS['TCA']));
} else {
// add MMmatchTablenames which might be the local table for foreign access
$tablelist = $tablelist.','.$this->MMmatchTablenames;
$tablelist = implode(',', array_unique(t3lib_div::trimExplode(',',$tablelist,1)));
}

// 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 NOT '.$fieldN;
}
}

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...

$this->itemArray = array();

// Now, populate the internal itemArray and tableArray arrays:
if ($MMtable) { // If MM, then call this function to do that:

// used here to get defVals when set - [tablename]_[id]
if(strpos($itemlist, '_')) {
$this->readList($itemlist);

// remap submitted defVals from form to local table if in foreign mode
if ($this->MMswapLocalForeign && $this->MMlocalTable) {
foreach ($this->itemArray as $key => $val) {
$this->itemArray[$key]['table_relation'] = $this->MMlocalTable; // is the current table
}
}
}

$this->readMM($MMtable, $MMuid, $this->MMmatchTablenames);

} else {
// If not MM, then explode the itemlist by "," and traverse the list:
$this->readList($itemlist);
}
}

/**
* Explodes the item list and stores the parts in the internal arrays itemArray and tableArray from MM records.
*
* @param string Item list
* @return void
*/
function readList($itemlist) {
if ((string)trim($itemlist)!='') {
$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...
foreach($tempItemArray as $key => $val) {
$isSet = 0; // Will be set to "1" if the entry was a real table/id:

// Extract table name and id. This is un the formular [tablename]_[id] where table name MIGHT contain "_", hence the reversion of the string!
$val = strrev($val);
$parts = explode('_',$val,2);
$theID = strrev($parts[0]);

// Check that the id IS an integer:
if (t3lib_div::testInt($theID)) {
// 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
$theTable = trim($parts[1]) ? strrev(trim($parts[1])) : ($this->secondTable && $theID<0 ? $this->secondTable : $this->firstTable);
// If the ID is not blank and the table name is among the names in the inputted tableList, then proceed:
if ((string)$theID!='' && $theID && $theTable && isset($this->tableArray[$theTable])) {
// Get ID as the right value:
$theID = $this->secondTable ? abs(intval($theID)) : intval($theID);
// Register ID/table name in internal arrays:
$this->itemArray[$key]['id'] = $theID;
$this->itemArray[$key]['table'] = $theTable;
$this->tableArray[$theTable][] = $theID;
// Set update-flag:
$isSet=1;
}
}

// 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:
if (!$isSet && $this->registerNonTableValues) {
$this->itemArray[$key]['id'] = $tempItemArray[$key];
$this->itemArray[$key]['table'] = '_NO_TABLE';
$this->nonTableArray[] = $tempItemArray[$key];
}
}
}
}

/**
* Reads the record tablename/id into the internal arrays itemArray and tableArray from MM records.
* You can call this function after start if you supply no list to start()
*
* @param string MM Tablename
* @param integer Local UID
* @param string The "tablenames" field will be queried with this table name list
* @return void
*/
function readMM($tableName, $uid, $tableList='') {
$key=count($this->itemArray);

if ($this->MMswapLocalForeign) {
$uid_foreign = 'uid_local';
$uid_local = 'uid_foreign';
} else {
$uid_local = 'uid_local';
$uid_foreign = 'uid_foreign';
}

$where = $uid_local.'='.intval($uid);
if ($this->MMtableWhere) {
$where.= "\n".str_replace('###THIS_UID###', intval($uid), $this->MMtableWhere);
}
foreach ($this->MMmatchFields as $field => $value) {
$where.= ' AND '.$field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($value, $tableName);
}
if ($tableList) {
$tableArr = t3lib_div::trimExplode(',', $tableList, 1);
$whereArr = array();
foreach($tableArr as $foreignTable) {
$whereArr[] = 'tablenames='.$GLOBALS['TYPO3_DB']->fullQuoteStr($foreignTable, $tableName);
}
$where.= ' AND ( '.implode(' OR ', $whereArr).' ) ';
}

// Select all MM relations:
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $tableName, $where, '', 'sorting');
while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {

// in foreign_select mode firstTable is the right table - tablenames should then be the current table
$theTable = ($row['tablenames'] AND !$this->MMswapLocalForeign) ? $row['tablenames'] : $this->firstTable;

if (($row[$uid_foreign] || $theTable=='pages') && $theTable && isset($this->tableArray[$theTable])) {
$this->itemArray[$key]['id'] = $row[$uid_foreign];
$this->itemArray[$key]['table'] = $theTable;
$this->itemArray[$key]['table_relation'] = $row['tablenames'];
$this->tableArray[$theTable][]= $row[$uid_foreign];
} elseif ($this->registerNonTableValues) {
$this->itemArray[$key]['id'] = $row[$uid_foreign];
$this->itemArray[$key]['table'] = '_NO_TABLE';
$this->itemArray[$key]['table_relation'] = '_NO_TABLE';
$this->nonTableArray[] = $row[$uid_foreign];
}
$this->itemArray[$key]['foreign_select'] = $this->MMswapLocalForeign;
$key++;
}

$GLOBALS['TYPO3_DB']->sql_free_result($res);
}

/**
* 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($tableName, $uid, $prependTableName=0) {

if ($this->MMswapLocalForeign) {
$uid_foreign = 'uid_local';
$uid_local = 'uid_foreign';
} else {
$uid_local = 'uid_local';
$uid_foreign = 'uid_foreign';
}

// If there are tables...
$tableC = count($this->tableArray);
if ($tableC) {
$prep = ($tableC>1||$prependTableName) ? 1 : 0;
}

// delete all relations with local uid
$where = $uid_local.'='.intval($uid);

// add WHERE clause if configured
if ($this->MMtableWhere) {
$where.= "\n".str_replace('###THIS_UID###', intval($uid), $this->MMtableWhere);
}
// delete those relations that match the configured fields
foreach ($this->MMmatchFields as $field => $value) {
$where.= ' AND '.$field.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($value, $tableName);
}

// if prepend table name is configured the 'tablenames' have to match those
if ($prep) {
$whereArr = array();
foreach($this->tableArray as $matchTable => $dummy) {
$whereArr[] = 'tablenames='.$GLOBALS['TYPO3_DB']->fullQuoteStr($matchTable, $tableName);
}
$where.= ' AND ( '.implode(' OR ', $whereArr).' ) ';
}


// Delete all relations:
$GLOBALS['TYPO3_DB']->exec_DELETEquery($tableName, $where);



if ($tableC) {
// For each item, insert it:
$c=0;
foreach($this->itemArray as $val) {
$c++;

$insertFields = $this->MMinsertFields;
$insertFields[$uid_local] = $uid;
$insertFields[$uid_foreign] = $val['id'];
$insertFields['sorting'] = $c;

if ($prep || $val['table']=='_NO_TABLE') {
$insertFields['tablenames'] = $val['table_relation'] ? $val['table_relation'] : $val['table'];
}

$GLOBALS['TYPO3_DB']->exec_INSERTquery($tableName, $insertFields);
}
}
}

/**
* After initialization you can extract an array of the elements from the object. Use this function for that.
*
* @param boolean If set, then table names will ALWAYS be prepended (unless its a _NO_TABLE value)
* @return array A numeric array.
*/
function getValueArray($prependTableName=false) {
// INIT:
$valueArray=array();
$tableC = count($this->tableArray);

// If there are tables in the table array:
if ($tableC) {
// If there are more than ONE table in the table array, then always prepend table names:
$prep = ($tableC>1||$prependTableName) ? 1 : 0;

// Traverse the array of items:
foreach($this->itemArray as $val) {
$valueArray[]=(($prep && $val['table']!='_NO_TABLE') ? $val['table'].'_' : '').
$val['id'];
}
}
// Return the array
return $valueArray;
}

/**
* Converts id numbers from negative to positive.
*
* @param array Array of [table]_[id] pairs.
* @param string Foreign table (the one used for positive numbers)
* @param string NEGative foreign table
* @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.
*/
function convertPosNeg($valueArray,$fTable,$nfTable) {
if (is_array($valueArray) && $fTable) {
foreach($valueArray as $key => $val) {
$val = strrev($val);
$parts = explode('_',$val,2);
$theID = strrev($parts[0]);
$theTable = strrev($parts[1]);

if ( t3lib_div::testInt($theID) && (!$theTable || !strcmp($theTable,$fTable) || !strcmp($theTable,$nfTable)) ) {
$valueArray[$key]= $theTable && strcmp($theTable,$fTable) ? $theID*-1 : $theID;
}
}
}
return $valueArray;
}

/**
* 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.
* If $this->fromTC is set you can save a little memory since only uid,pid and a few other fields are selected.
*
* @return void
*/
function getFromDB() {
// Traverses the tables listed:
foreach($this->tableArray as $table => $val) {
if (is_array($val)) {
$itemList = implode(',',$val);
if ($itemList) {
$from = '*';
if ($this->fromTC) {
$from = 'uid,pid';
if ($GLOBALS['TCA'][$table]['ctrl']['label']) {
$from.= ','.$GLOBALS['TCA'][$table]['ctrl']['label']; // Title
}
if ($GLOBALS['TCA'][$table]['ctrl']['thumbnail']) {
$from.= ','.$GLOBALS['TCA'][$table]['ctrl']['thumbnail']; // Thumbnail
}
}
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($from, $table, 'uid IN ('.$itemList.')'.$this->additionalWhere[$table]);
while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
$this->results[$table][$row['uid']]=$row;
}
}
}
}
return $this->results;
}

/**
* Prepare items from itemArray to be transferred to the TCEforms interface (as a comma list)
*
* @return string
* @see t3lib_transferdata::renderRecord()
*/
function readyForInterface() {
global $TCA;

if (!is_array($this->itemArray)) {return false;}

$output=array();
$perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1); // For use when getting the paths....
$titleLen=intval($GLOBALS['BE_USER']->uc['titleLen']);

foreach($this->itemArray as $key => $val) {
$theRow = $this->results[$val['table']][$val['id']];
if ($theRow && is_array($TCA[$val['table']])) {
$label = t3lib_div::fixed_lgd_cs(strip_tags($theRow[$TCA[$val['table']]['ctrl']['label']]),$titleLen);
$label = ($label)?$label:'[...]';
$output[]=str_replace(',','',$val['table'].'_'.$val['id'].'|'.rawurlencode($label));
}
}
return implode(',',$output);
}
}


if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_loaddbgroup.php']) {
include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_loaddbgroup.php']);
}
?>
(2-2/4)