* Added reference index table and class. See mail sent to Dev-list
authorKasper Skårhøj <kasper@typo3.org>
Sat, 17 Dec 2005 14:26:22 +0000 (14:26 +0000)
committerKasper Skårhøj <kasper@typo3.org>
Sat, 17 Dec 2005 14:26:22 +0000 (14:26 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@915 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
t3lib/class.t3lib_befunc.php
t3lib/class.t3lib_db.php
t3lib/class.t3lib_div.php
t3lib/class.t3lib_refindex.php [new file with mode: 0755]
t3lib/class.t3lib_tcemain.php
t3lib/stddb/tables.sql
typo3/sysext/impexp/class.tx_impexp.php
typo3/sysext/lowlevel/dbint/index.php

index 4608d0b..bdf85aa 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2005-12-17  Kasper Skårhøj  <kasper2005@typo3.com>
+
+       * Added reference index table and class. See mail sent to Dev-list 
+
+2005-12-15  Kasper Skårhøj  <kasper2005@typo3.com>
 2005-12-16     Robert Lemke    <robert@typo3.org>
        * Fixed a bug in t3lib_beFunc::getRecordWSOL - it now makes sure that uid, pid and t3ver_swapmode are selected internally if they are not specified in $fields
 
index e053f64..ee13bd1 100755 (executable)
@@ -958,10 +958,11 @@ class t3lib_BEfunc        {
         * @param       array           Record data
         * @param       string          The table name
         * @param       string          Optional fieldname passed to hook object
+        * @param       boolean         Boolean; If set, workspace overlay is applied to records. This is correct behaviour for all presentation and export, but NOT if you want a true reflection of how things are in the live workspace.
         * @return      mixed           If array, the data structure was found and returned as an array. Otherwise (string) it is an error message.
         * @see t3lib_TCEforms::getSingleField_typeFlex()
         */
-       function getFlexFormDS($conf,$row,$table,$fieldName='') {
+       function getFlexFormDS($conf,$row,$table,$fieldName='',$WSOL=TRUE)      {
                global $TYPO3_CONF_VARS;
 
                        // Get pointer field etc from TCA-config:
@@ -996,8 +997,10 @@ class t3lib_BEfunc {
                                // Searching recursively back if 'ds_pointerField_searchParent' is defined (typ. a page rootline, or maybe a tree-table):
                        if ($ds_searchParentField && !$srcPointer)      {
                                $rr = t3lib_BEfunc::getRecord($table,$row['uid'],'uid,'.$ds_searchParentField); // Get the "pid" field - we cannot know that it is in the input record!
-                               t3lib_BEfunc::workspaceOL($table,$rr);  // KASPER: Not tested, but assumed correct
-                               t3lib_BEfunc::fixVersioningPid($table,$rr);
+                               if ($WSOL)      {
+                                       t3lib_BEfunc::workspaceOL($table,$rr);
+                                       t3lib_BEfunc::fixVersioningPid($table,$rr);
+                               }
                                $uidAcc=array();        // Used to avoid looping, if any should happen.
                                $subFieldPointer = $conf['ds_pointerField_searchParent_subField'];
                                while(!$srcPointer)             {
@@ -1012,8 +1015,10 @@ class t3lib_BEfunc       {
                                        if (!is_array($rr) || isset($uidAcc[$rr['uid']]))       break;
                                        $uidAcc[$rr['uid']]=1;
 
-                                       t3lib_BEfunc::workspaceOL($table,$rr);  // KASPER: Not tested, but assumed correct
-                                       t3lib_BEfunc::fixVersioningPid($table,$rr);
+                                       if ($WSOL)      {
+                                               t3lib_BEfunc::workspaceOL($table,$rr);
+                                               t3lib_BEfunc::fixVersioningPid($table,$rr);
+                                       }
                                        $srcPointer = ($subFieldPointer && $rr[$subFieldPointer]) ? $rr[$subFieldPointer] : $rr[$ds_pointerField];
                                }
                        }
@@ -1023,7 +1028,10 @@ class t3lib_BEfunc       {
                                if (t3lib_div::testInt($srcPointer))    {       // If integer, then its a record we will look up:
                                        list($tName,$fName) = explode(':',$ds_tableField,2);
                                        if ($tName && $fName && is_array($GLOBALS['TCA'][$tName]))      {
-                                               $dataStructRec = t3lib_BEfunc::getRecordWSOL($tName, $srcPointer);
+                                               $dataStructRec = t3lib_BEfunc::getRecord($tName, $srcPointer);
+                                               if ($WSOL)      {
+                                                       t3lib_BEfunc::workspaceOL($tName,$dataStructRec);
+                                               }
                                                $dataStructArray = t3lib_div::xml2array($dataStructRec[$fName]);
                                        } else $dataStructArray = 'No tablename ('.$tName.') or fieldname ('.$fName.') was found an valid!';
                                } else {        // Otherwise expect it to be a file:
index 7a19800..07f08ac 100755 (executable)
@@ -541,6 +541,21 @@ class t3lib_DB {
        }
 
        /**
+        * Will fullquote all values in the one-dimentional array so they are ready to "implode" for an sql query.
+        *
+        * @param       array           Array with values
+        * @param       string          Table name for which to quote.
+        * @return      array           The input array with all values passed through intval()
+        * @see cleanIntArray()
+        */
+       function fullQuoteArray($arr, $table)   {
+               foreach($arr as $k => $v)       {
+                       $arr[$k] = $this->fullQuoteStr($arr[$k], $table);
+               }
+               return $arr;
+       }
+
+       /**
         * Substitution for PHP function "addslashes()"
         * Use this function instead of the PHP addslashes() function when you build queries - this will prepare your code for DBAL.
         * NOTICE: You must wrap the output of this function in SINGLE QUOTES to be DBAL compatible. Unless you have to apply the single quotes yourself you should rather use ->fullQuoteStr()!
index e3127f6..df57341 100755 (executable)
@@ -2524,7 +2524,44 @@ class t3lib_div {
                } else return 'N/A';
        }
 
+       function debugRows($rows,$header)       {
+               if (is_array($rows))    {
+                       reset($rows);
+                       $firstEl = current($rows);
+                       if (is_array($firstEl)) {
+                               $headerColumns = array_keys($firstEl);
+                               $tRows = array();
+
+                                       // Header:
+                               $tRows[] = '<tr><td colspan="'.count($headerColumns).'" style="background-color:#bbbbbb; font-family: verdana,arial; font-weight: bold; font-size: 10px;"><strong>'.htmlspecialchars($header).'</strong></td></tr>';
+                               $tCells = array();
+                               foreach($headerColumns as $key) {
+                                       $tCells[] = '
+                                                       <td><font face="Verdana,Arial" size="1"><strong>'.htmlspecialchars($key).'</strong></font></td>';
+                               }
+                               $tRows[] = '
+                                               <tr>'.implode('',$tCells).'
+                                               </tr>';
+
+                                       // Rows:
+                               foreach($rows as $singleRow)    {
+                                       $tCells = array();
+                                       foreach($headerColumns as $key) {
+                                               $tCells[] = '
+                                                       <td><font face="Verdana,Arial" size="1">'.htmlspecialchars($singleRow[$key]).'</font></td>';
+                                       }
+                                       $tRows[] = '
+                                               <tr>'.implode('',$tCells).'
+                                               </tr>';
+                               }
 
+                               $table = '
+                                       <table border="1" cellpadding="1" cellspacing="0" bgcolor="white">'.implode('',$tRows).'
+                                       </table>';
+                               echo $table;
+                       } else debug('Empty array of rows',$header);
+               } else debug('No array of rows',$header);
+       }
 
 
 
diff --git a/t3lib/class.t3lib_refindex.php b/t3lib/class.t3lib_refindex.php
new file mode 100755 (executable)
index 0000000..d5991ed
--- /dev/null
@@ -0,0 +1,619 @@
+<?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!
+***************************************************************/
+/**
+ * Reference index processing
+ *
+ * $Id$
+ *
+ * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
+ */
+/**
+ * [CLASS/FUNCTION INDEX of SCRIPT]
+ *
+ *
+ *
+ *   74: class t3lib_refindex
+ *   91:     function updateRefIndexTable($table,$uid,$testOnly=FALSE)
+ *  162:     function generateRefIndexData($table,$uid)
+ *  235:     function createEntryData($table,$uid,$field,$flexpointer,$ref_table,$ref_uid,$ref_string='',$sort=-1,$softref_key='',$softref_id='')
+ *  260:     function createEntryData_dbRels($table,$uid,$fieldname,$flexpointer,$items)
+ *  276:     function createEntryData_fileRels($table,$uid,$fieldname,$flexpointer,$items)
+ *  296:     function createEntryData_softreferences($table,$uid,$fieldname,$flexpointer,$keys)
+ *
+ *              SECTION: Get relations from table row
+ *  351:     function getRelations($table,$row)
+ *  456:     function getRelations_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $structurePath)
+ *  503:     function getRelations_procFiles($value, $conf, $uid)
+ *  553:     function getRelations_procDB($value, $conf, $uid)
+ *
+ *              SECTION: Helper functions
+ *  590:     function isReferenceField($conf)
+ *  600:     function destPathFromUploadFolder($folder)
+ *  610:     function error($msg)
+ *
+ * TOTAL FUNCTIONS: 13
+ * (This index is automatically created/updated by the extension "extdeveval")
+ *
+ */
+
+require_once(PATH_t3lib.'class.t3lib_tcemain.php');
+
+
+
+/**
+ * Reference index processing and relation extraction
+ *
+ * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class t3lib_refindex {
+
+       var $temp_flexRelations = array();
+       var $errorLog = array();
+       var $WSOL = FALSE;
+       var $relations = array();
+       var $hashVersion = 1;   // Number which we can increase if a change in the code means we will have to force a re-generation of the index.
+
+
+       /**
+        * Call this function to update the sys_refindex table for a record.
+        *
+        * @param       string          Table name
+        * @param       uid             UID of record
+        * @param       boolean         If set, nothing will be written to the index but the result value will still report statistics on what as added, deleted and kept. Can be used for mere analysis.
+        * @return      array           Array with statistics about how many index records were added, deleted and not altered plus the complete reference set for the record.
+        */
+       function updateRefIndexTable($table,$uid,$testOnly=FALSE)       {
+
+                       // First, secure that the index table is not updated with workspace tainted relations:
+               $this->WSOL = FALSE;
+
+                       // Init:
+               $result = array(
+                       'keptNodes' => 0,
+                       'deletedNodes' => 0,
+                       'addedNodes' => 0
+               );
+
+                       // Get current index from Database:
+               $currentRels = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                       '*',
+                       'sys_refindex',
+                       'tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table,'sys_refindex').
+                               ' AND recuid='.intval($uid),
+                       '','','','hash'
+               );
+
+                       // First, test to see if the record exists (being deleted also means it doesn't exist!)
+               if (t3lib_BEfunc::getRecord($table,$uid,'uid')) {
+
+                               // Then, get relations:
+                       $relations = $this->generateRefIndexData($table,$uid);
+
+                       if (is_array($relations))       {
+
+                                       // Traverse the generated index:
+                               foreach($relations as $k => $datRec)    {
+                                       $relations[$k]['hash'] = md5(implode('///',$relations[$k]).'///'.$this->hashVersion);
+
+                                               // First, check if already indexed and if so, unset that row (so in the end we know which rows to remove!)
+                                       if (isset($currentRels[$relations[$k]['hash']]))        {
+                                               unset($currentRels[$relations[$k]['hash']]);
+                                               $result['keptNodes']++;
+                                               $relations[$k]['_ACTION'] = 'KEPT';
+                                       } else {
+                                                       // If new, add it:
+                                               if (!$testOnly) $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_refindex',$relations[$k]);
+                                               $result['addedNodes']++;
+                                               $relations[$k]['_ACTION'] = 'ADDED';
+                                       }
+                               }
+
+                               $result['relations'] = $relations;
+                       } else return FALSE;    // Weird mistake I would say...
+               }
+
+                       // If any old are left, remove them:
+               if (count($currentRels))        {
+                       $hashList = array_keys($currentRels);
+                       if (count($hashList))   {
+                               $result['deletedNodes'] = count($hashList);
+                               $result['deletedNodes_hashList'] = implode(',',$hashList);
+                               if (!$testOnly) $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_refindex','hash IN ('.implode(',',$GLOBALS['TYPO3_DB']->fullQuoteArray($hashList,'sys_refindex')).')');
+                       }
+               }
+
+               return $result;
+       }
+
+       /**
+        * Returns array of arrays with an index of all references found in record from table/uid
+        * If the result is used to update the sys_refindex table then ->WSOL must NOT be true (no workspace overlay anywhere!)
+        *
+        * @param       string          Table name from $TCA
+        * @param       integer         Record UID
+        * @return      array           Index Rows
+        */
+       function generateRefIndexData($table,$uid)      {
+               global $TCA;
+
+               if (isset($TCA[$table]))        {
+                               // Get raw record from DB:
+                       list($record) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*',$table,'uid='.intval($uid));
+
+                       if (is_array($record))  {
+
+                                       // Get all relations from record:
+                               $dbrels = $this->getRelations($table,$record);
+
+                                       // Traverse those relations, compile records to insert in table:
+                               $this->relations = array();
+                               foreach($dbrels as $fieldname => $dat)  {
+
+                                               // Based on type,
+                                       switch((string)$dat['type'])    {
+                                               case 'db':
+                                                       $this->createEntryData_dbRels($table,$uid,$fieldname,'',$dat['itemArray']);
+                                               break;
+                                               case 'file':
+                                                       $this->createEntryData_fileRels($table,$uid,$fieldname,'',$dat['newValueFiles']);
+                                               break;
+                                               case 'flex':
+                                                               // DB references:
+                                                       if (is_array($dat['flexFormRels']['db']))       {
+                                                               foreach($dat['flexFormRels']['db'] as $flexpointer => $subList) {
+                                                                       $this->createEntryData_dbRels($table,$uid,$fieldname,$flexpointer,$subList);
+                                                               }
+                                                       }
+                                                               // File references (NOT TESTED!)
+                                                       if (is_array($dat['flexFormRels']['file']))     {       // Not tested
+                                                               foreach($dat['flexFormRels']['file'] as $flexpointer => $subList)       {
+                                                                       $this->createEntryData_fileRels($table,$uid,$fieldname,$flexpointer,$subList);
+                                                               }
+                                                       }
+                                                               // Soft references in flexforms (NOT TESTED!)
+                                                       if (is_array($dat['flexFormRels']['softrefs'])) {
+                                                               foreach($dat['flexFormRels']['softrefs'] as $flexpointer => $subList)   {
+                                                                       $this->createEntryData_softreferences($table,$uid,$fieldname,$flexpointer,$subList['keys']);
+                                                               }
+                                                       }
+                                               break;
+                                       }
+
+                                               // Softreferences in the field:
+                                       if (is_array($dat['softrefs'])) {
+                                               $this->createEntryData_softreferences($table,$uid,$fieldname,'',$dat['softrefs']['keys']);
+                                       }
+                               }
+
+                               return $this->relations;
+                       }
+               }
+       }
+
+       /**
+        * Create array with field/value pairs ready to insert in database.
+        * The "hash" field is a fingerprint value across this table.
+        *
+        * @param       string          Tablename of source record (where reference is located)
+        * @param       integer         UID of source record (where reference is located)
+        * @param       string          Fieldname of source record (where reference is located)
+        * @param       string          Pointer to location inside flexform structure where reference is located in [field]
+        * @param       string          For database references; the tablename the reference points to. Special keyword "_FILE" indicates that "ref_string" is a file reference either absolute or relative to PATH_site. Special keyword "_STRING" indicates some special usage (typ. softreference) where "ref_string" is used for the value.
+        * @param       integer         For database references; The UID of the record (zero "ref_table" is "_FILE" or "_STRING")
+        * @param       string          For "_FILE" or "_STRING" references: The filepath (relative to PATH_site or absolute) or other string.
+        * @param       integer         The sorting order of references if many (the "group" or "select" TCA types). -1 if no sorting order is specified.
+        * @param       string          If the reference is a soft reference, this is the soft reference parser key. Otherwise empty.
+        * @param       string          Soft reference ID for key. Might be useful for replace operations.
+        * @return      array           Array record to insert into table.
+        */
+       function createEntryData($table,$uid,$field,$flexpointer,$ref_table,$ref_uid,$ref_string='',$sort=-1,$softref_key='',$softref_id='')    {
+               return array(
+                       'tablename' => $table,
+                       'recuid' => $uid,
+                       'field' => $field,
+                       'flexpointer' => $flexpointer,
+                       'softref_key' => $softref_key,
+                       'softref_id' => $softref_id,
+                       'sorting' => $sort,
+                       'ref_table' => $ref_table,
+                       'ref_uid' => $ref_uid,
+                       'ref_string' => $ref_string,
+               );
+       }
+
+       /**
+        * Enter database references to ->relations array
+        *
+        * @param       string          [See createEntryData, arg 1]
+        * @param       integer         [See createEntryData, arg 2]
+        * @param       string          [See createEntryData, arg 3]
+        * @param       string          [See createEntryData, arg 4]
+        * @param       array           Data array with databaes relations (table/id)
+        * @return      void
+        */
+       function createEntryData_dbRels($table,$uid,$fieldname,$flexpointer,$items)     {
+               foreach($items as $sort => $i)  {
+                       $this->relations[] = $this->createEntryData($table,$uid,$fieldname,$flexpointer,$i['table'],$i['id'],'',$sort);
+               }
+       }
+
+       /**
+        * Enter file references to ->relations array
+        *
+        * @param       string          [See createEntryData, arg 1]
+        * @param       integer         [See createEntryData, arg 2]
+        * @param       string          [See createEntryData, arg 3]
+        * @param       string          [See createEntryData, arg 4]
+        * @param       array           Data array with file relations
+        * @return      void
+        */
+       function createEntryData_fileRels($table,$uid,$fieldname,$flexpointer,$items)   {
+               foreach($items as $sort => $i)  {
+                       $filePath = $i['ID_absFile'];
+                       if (t3lib_div::isFirstPartOfStr($filePath,PATH_site))   {
+                               $filePath = substr($filePath,strlen(PATH_site));
+                       }
+                       $this->relations[] = $this->createEntryData($table,$uid,$fieldname,$flexpointer,'_FILE',0,$filePath,$sort);
+               }
+       }
+
+       /**
+        * Enter softref references to ->relations array
+        *
+        * @param       string          [See createEntryData, arg 1]
+        * @param       integer         [See createEntryData, arg 2]
+        * @param       string          [See createEntryData, arg 3]
+        * @param       string          [See createEntryData, arg 4]
+        * @param       array           Data array with soft reference keys
+        * @return      void
+        */
+       function createEntryData_softreferences($table,$uid,$fieldname,$flexpointer,$keys)      {
+               if (is_array($keys))    {
+                       foreach($keys as $spKey => $elements)   {
+                               if (is_array($elements))        {
+                                       foreach($elements as $subKey => $el)    {
+                                               if (is_array($el['subst']))     {
+                                                       switch((string)$el['subst']['type'])    {
+                                                                case 'db':
+                                                                       list($tableName,$recordId) = explode(':',$el['subst']['recordRef']);
+                                                                       $this->relations[] = $this->createEntryData($table,$uid,$fieldname,$flexpointer,$tableName,$recordId,'',-1,$spKey,$subKey);
+                                                                break;
+                                                                case 'file':
+                                                                       $this->relations[] = $this->createEntryData($table,$uid,$fieldname,$flexpointer,'_FILE',0,$el['subst']['relFileName'],-1,$spKey,$subKey);
+                                                                break;
+                                                                case 'string':
+                                                                       $this->relations[] = $this->createEntryData($table,$uid,$fieldname,$flexpointer,'_STRING',0,$el['subst']['tokenValue'],-1,$spKey,$subKey);
+                                                                break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+       /*******************************
+        *
+        * Get relations from table row
+        *
+        *******************************/
+
+       /**
+        * Returns relation information for a $table/$row-array
+        * Traverses all fields in input row which are configured in TCA/columns
+        * It looks for hard relations to files and records in the TCA types "select" and "group"
+        *
+        * @param       string          Table
+        * @param       array           Row from table
+        * @return      array           Array with information about relations
+        * @see export_addRecord()
+        */
+       function getRelations($table,$row)      {
+               global $TCA;
+
+                       // Load full table description
+               t3lib_div::loadTCA($table);
+
+                       // Initialize:
+               $uid = $row['uid'];
+               $nonFields = explode(',','uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,pid');
+
+               $outRow = array();
+               foreach($row as $field => $value)       {
+                       if (!in_array($field,$nonFields) && is_array($TCA[$table]['columns'][$field]))  {
+                               $conf = $TCA[$table]['columns'][$field]['config'];
+
+                                       // Add files
+                               if ($result = $this->getRelations_procFiles($value, $conf, $uid))       {
+                                               // Creates an entry for the field with all the files:
+                                       $outRow[$field] = array(
+                                               'type' => 'file',
+                                               'newValueFiles' => $result,
+                                       );
+                               }
+
+                                       // Add DB:
+                               if ($result = $this->getRelations_procDB($value, $conf, $uid))  {
+                                               // Create an entry for the field with all DB relations:
+                                       $outRow[$field] = array(
+                                               'type' => 'db',
+                                               'itemArray' => $result,
+                                       );
+                               }
+
+                                       // For "flex" fieldtypes we need to traverse the structure looking for file and db references of course!
+                               if ($conf['type']=='flex')      {
+
+                                               // Get current value array:
+                                       $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $row, $table,'',$this->WSOL);
+                                       $currentValueArray = t3lib_div::xml2array($value);
+
+                                               // Traversing the XML structure, processing files:
+                                       if (is_array($currentValueArray))       {
+                                               $this->temp_flexRelations = array(
+                                                       'db' => array(),
+                                                       'file' => array(),
+                                                       'softrefs' => array()
+                                               );
+
+                                               $iteratorObj = t3lib_div::makeInstance('t3lib_TCEmain');
+                                               $iteratorObj->callBackObj = &$this;
+                                               $iteratorObj->checkValue_flex_procInData(
+                                                                       $currentValueArray['data'],
+                                                                       array(),        // Not used.
+                                                                       array(),        // Not used.
+                                                                       $dataStructArray,
+                                                                       array($table,$uid,$field),      // Parameters.
+                                                                       'getRelations_flexFormCallBack'
+                                                               );
+
+                                                       // Create an entry for the field:
+                                               $outRow[$field] = array(
+                                                       'type' => 'flex',
+                                                       'flexFormRels' => $this->temp_flexRelations,
+                                               );
+                                       }
+                               }
+
+                                       // Soft References:
+                               if (strlen($value) && $softRefs = t3lib_BEfunc::explodeSoftRefParserList($conf['softref'], $table, $field))     {
+                                       $softRefValue = $value;
+                                       foreach($softRefs as $spKey => $spParams)       {
+                                               $softRefObj = &t3lib_BEfunc::softRefParserObj($spKey);
+                                               if (is_object($softRefObj))     {
+                                                       $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams);
+                                                       if (is_array($resultArray))     {
+                                                               $outRow[$field]['softrefs']['keys'][$spKey] = $resultArray['elements'];
+                                                               if (strlen($resultArray['content'])) {
+                                                                       $softRefValue = $resultArray['content'];
+                                                               }
+                                                       }
+                                               }
+                                       }
+
+                                       if (is_array($outRow[$field]['softrefs']) && count($outRow[$field]['softrefs']) && strcmp($value,$softRefValue) && strstr($softRefValue,'{softref:'))   {
+                                               $outRow[$field]['softrefs']['tokenizedContent'] = $softRefValue;
+                                       }
+                               }
+                       }
+               }
+
+               return $outRow;
+       }
+
+       /**
+        * Callback function for traversing the FlexForm structure in relation to finding file and DB references!
+        *
+        * @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 of where in the data structure this element is.
+        * @return      array           Result array with key "value" containing the value of the processing.
+        * @see t3lib_TCEmain::checkValue_flex_procInData_travDS()
+        */
+       function getRelations_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $structurePath) {
+
+                       // Implode parameter values:
+               list($table, $uid, $field) = $pParams;
+
+                       // Add files
+               if ($result = $this->getRelations_procFiles($dataValue, $dsConf, $uid)) {
+
+                               // Creates an entry for the field with all the files:
+                       $this->temp_flexRelations['file'][$structurePath] = $result;
+               }
+
+                       // Add DB:
+               if ($result = $this->getRelations_procDB($dataValue, $dsConf, $uid))    {
+
+                               // Create an entry for the field with all DB relations:
+                       $this->temp_flexRelations['db'][$structurePath] = $result;
+               }
+
+                       // Soft References:
+               if (strlen($dataValue) && $softRefs = t3lib_BEfunc::explodeSoftRefParserList($dsConf['softref'], $table, $field))       {
+                       $softRefValue = $dataValue;
+                       foreach($softRefs as $spKey => $spParams)       {
+                               $softRefObj = &t3lib_BEfunc::softRefParserObj($spKey);
+                               if (is_object($softRefObj))     {
+                                       $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams, $structurePath);
+                                       if (is_array($resultArray) && is_array($resultArray['elements']))       {
+                                               $this->temp_flexRelations['softrefs'][$structurePath]['keys'][$spKey] = $resultArray['elements'];
+                                               if (strlen($resultArray['content'])) $softRefValue = $resultArray['content'];
+                                       }
+                               }
+                       }
+
+                       if (count($this->temp_flexRelations['softrefs']) && strcmp($dataValue,$softRefValue))   {
+                               $this->temp_flexRelations['softrefs'][$structurePath]['tokenizedContent'] = $softRefValue;
+                       }
+               }
+       }
+
+       /**
+        * Check field configuration if it is a file relation field and extract file relations if any
+        *
+        * @param       string          Field value
+        * @param       array           Field configuration array of type "TCA/columns"
+        * @param       integer         Field uid
+        * @return      array           If field type is OK it will return an array with the files inside. Else false
+        */
+       function getRelations_procFiles($value, $conf, $uid)    {
+                       // Take care of files...
+               if ($conf['type']=='group' && $conf['internal_type']=='file')   {
+
+                               // Collect file values in array:
+                       if ($conf['MM'])        {
+                               $theFileValues = array();
+                               $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
+                               $dbAnalysis->start('', 'files', $conf['MM'], $uid);
+
+                               foreach($dbAnalysis->itemArray as $somekey => $someval) {
+                                       if ($someval['id'])     {
+                                               $theFileValues[] = $someval['id'];
+                                       }
+                               }
+                       } else {
+                               $theFileValues = explode(',',$value);
+                       }
+
+                               // Traverse the files and add them:
+                       $uploadFolder = $conf['uploadfolder'];
+                       $dest = $this->destPathFromUploadFolder($uploadFolder);
+                       $newValue = array();
+                       $newValueFiles = array();
+
+                       foreach($theFileValues as $file)        {
+                               if (trim($file))        {
+                                       $realFile = $dest.'/'.trim($file);
+                                       if (@is_file($realFile))        {
+                                               $newValueFiles[] = array(
+                                                       'filename' => $file,
+                                                       'ID' => md5($realFile),
+                                                       'ID_absFile' => $realFile
+                                               );      // the order should be preserved here because.. (?)
+                                       } else $this->error('Missing file: '.$realFile);
+                               }
+                       }
+
+                       return $newValueFiles;
+               }
+       }
+
+       /**
+        * Check field configuration if it is a DB relation field and extract DB relations if any
+        *
+        * @param       string          Field value
+        * @param       array           Field configuration array of type "TCA/columns"
+        * @param       integer         Field uid
+        * @return      array           If field type is OK it will return an array with the database relations. Else false
+        */
+       function getRelations_procDB($value, $conf, $uid)       {
+
+                       // DB record lists:
+               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'];
+
+                       $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
+                       $dbAnalysis->start($value,$allowedTables,$conf['MM'],$uid);
+
+                       return $dbAnalysis->itemArray;
+               }
+       }
+
+
+
+
+
+
+
+
+
+
+
+
+       /*******************************
+        *
+        * Helper functions
+        *
+        *******************************/
+
+       /**
+        * Returns true if the TCA/columns field type is a DB reference field
+        *
+        * @param       array           config array for TCA/columns field
+        * @return      boolean         True if DB reference field (group/db or select with foreign-table)
+        */
+       function isReferenceField($conf)        {
+               return ($conf['type']=='group' && $conf['internal_type']=='db') ||      ($conf['type']=='select' && $conf['foreign_table']);
+       }
+
+       /**
+        * Returns destination path to an upload folder given by $folder
+        *
+        * @param       string          Folder relative to PATH_site
+        * @return      string          Input folder prefixed with PATH_site. No checking for existence is done. Output must be a folder without trailing slash.
+        */
+       function destPathFromUploadFolder($folder)      {
+               return PATH_site.$folder;
+       }
+
+       /**
+        * Sets error message in the internal error log
+        *
+        * @param       string          Error message
+        * @return      void
+        */
+       function error($msg)    {
+               $this->errorLog[]=$msg;
+       }
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_refindex.php']) {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_refindex.php']);
+}
+?>
\ No newline at end of file
index 4c951e8..a5f1c43 100755 (executable)
  *
  *
  *
- *  226: class t3lib_TCEmain
- *  344:     function start($data,$cmd,$altUserObject='')
- *  379:     function setMirror($mirror)
- *  404:     function setDefaultsFromUserTS($userTS)
- *  427:     function process_uploads($postFiles)
- *  465:     function process_uploads_traverseArray(&$outputArr,$inputArr,$keyToSet)
+ *  227: class t3lib_TCEmain
+ *  346:     function start($data,$cmd,$altUserObject='')
+ *  381:     function setMirror($mirror)
+ *  406:     function setDefaultsFromUserTS($userTS)
+ *  429:     function process_uploads($postFiles)
+ *  467:     function process_uploads_traverseArray(&$outputArr,$inputArr,$keyToSet)
  *
  *              SECTION: PROCESSING DATA
- *  501:     function process_datamap()
- *  797:     function placeholderShadowing($table,$id)
- *  833:     function fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$realPid,$status,$tscPID)
+ *  503:     function process_datamap()
+ *  800:     function placeholderShadowing($table,$id)
+ *  836:     function fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$realPid,$status,$tscPID)
  *
  *              SECTION: Evaluation of input values
- * 1053:     function checkValue($table,$field,$value,$id,$status,$realPid,$tscPID)
- * 1113:     function checkValue_SW($res,$value,$tcaFieldConf,$table,$id,$curValue,$status,$realPid,$recFID,$field,$uploadedFiles,$tscPID)
- * 1159:     function checkValue_input($res,$value,$tcaFieldConf,$PP,$field='')
- * 1197:     function checkValue_check($res,$value,$tcaFieldConf,$PP)
- * 1220:     function checkValue_radio($res,$value,$tcaFieldConf,$PP)
- * 1246:     function checkValue_group_select($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field)
- * 1346:     function checkValue_group_select_file($valueArray,$tcaFieldConf,$curValue,$uploadedFileArray,$status,$table,$id,$recFID)
- * 1499:     function checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field)
- * 1572:     function checkValue_flexArray2Xml($array)
- * 1589:     function _DELETE_FLEX_FORMdata(&$valueArrayToRemoveFrom,$deleteCMDS)
- * 1611:     function _MOVE_FLEX_FORMdata(&$valueArrayToMoveIn, $moveCMDS, $direction)
+ * 1057:     function checkValue($table,$field,$value,$id,$status,$realPid,$tscPID)
+ * 1117:     function checkValue_SW($res,$value,$tcaFieldConf,$table,$id,$curValue,$status,$realPid,$recFID,$field,$uploadedFiles,$tscPID)
+ * 1163:     function checkValue_input($res,$value,$tcaFieldConf,$PP,$field='')
+ * 1201:     function checkValue_check($res,$value,$tcaFieldConf,$PP)
+ * 1224:     function checkValue_radio($res,$value,$tcaFieldConf,$PP)
+ * 1250:     function checkValue_group_select($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field)
+ * 1350:     function checkValue_group_select_file($valueArray,$tcaFieldConf,$curValue,$uploadedFileArray,$status,$table,$id,$recFID)
+ * 1503:     function checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field)
+ * 1576:     function checkValue_flexArray2Xml($array)
+ * 1593:     function _DELETE_FLEX_FORMdata(&$valueArrayToRemoveFrom,$deleteCMDS)
+ * 1615:     function _MOVE_FLEX_FORMdata(&$valueArrayToMoveIn, $moveCMDS, $direction)
  *
  *              SECTION: Helper functions for evaluation functions.
- * 1673:     function getUnique($table,$field,$value,$id,$newPid=0)
- * 1711:     function checkValue_input_Eval($value,$evalArray,$is_in)
- * 1799:     function checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,$type)
- * 1832:     function checkValue_group_select_explodeSelectGroupValue($value)
- * 1855:     function checkValue_flex_procInData($dataPart,$dataPart_current,$uploadedFiles,$dataStructArray,$pParams,$callBackFunc='')
- * 1894:     function checkValue_flex_procInData_travDS(&$dataValues,$dataValues_current,$uploadedFiles,$DSelements,$pParams,$callBackFunc,$structurePath)
+ * 1677:     function getUnique($table,$field,$value,$id,$newPid=0)
+ * 1715:     function checkValue_input_Eval($value,$evalArray,$is_in)
+ * 1803:     function checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,$type)
+ * 1836:     function checkValue_group_select_explodeSelectGroupValue($value)
+ * 1859:     function checkValue_flex_procInData($dataPart,$dataPart_current,$uploadedFiles,$dataStructArray,$pParams,$callBackFunc='')
+ * 1898:     function checkValue_flex_procInData_travDS(&$dataValues,$dataValues_current,$uploadedFiles,$DSelements,$pParams,$callBackFunc,$structurePath)
  *
  *              SECTION: PROCESSING COMMANDS
- * 2040:     function process_cmdmap()
+ * 2044:     function process_cmdmap()
  *
  *              SECTION: Cmd: Copying
- * 2173:     function copyRecord($table,$uid,$destPid,$first=0,$overrideValues=array(),$excludeFields='')
- * 2294:     function copyPages($uid,$destPid)
- * 2348:     function copySpecificPage($uid,$destPid,$copyTablesArray,$first=0)
- * 2382:     function copyRecord_raw($table,$uid,$pid,$overrideArray=array())
- * 2444:     function rawCopyPageContent($old_pid,$new_pid,$copyTablesArray)
- * 2468:     function insertNewCopyVersion($table,$fieldArray,$realPid)
- * 2519:     function copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf)
- * 2575:     function copyRecord_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2)
- * 2603:     function copyRecord_procFilesRefs($conf, $uid, $value)
+ * 2180:     function copyRecord($table,$uid,$destPid,$first=0,$overrideValues=array(),$excludeFields='')
+ * 2302:     function copyPages($uid,$destPid)
+ * 2356:     function copySpecificPage($uid,$destPid,$copyTablesArray,$first=0)
+ * 2390:     function copyRecord_raw($table,$uid,$pid,$overrideArray=array())
+ * 2452:     function rawCopyPageContent($old_pid,$new_pid,$copyTablesArray)
+ * 2476:     function insertNewCopyVersion($table,$fieldArray,$realPid)
+ * 2527:     function copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf)
+ * 2583:     function copyRecord_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2)
+ * 2611:     function copyRecord_procFilesRefs($conf, $uid, $value)
  *
  *              SECTION: Cmd: Moving, Localizing
- * 2672:     function moveRecord($table,$uid,$destPid)
- * 2836:     function localize($table,$uid,$language)
+ * 2680:     function moveRecord($table,$uid,$destPid)
+ * 2867:     function localize($table,$uid,$language)
  *
  *              SECTION: Cmd: Deleting
- * 2910:     function deleteAction($table, $id)
- * 2957:     function deleteEl($table, $uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE)
- * 2977:     function deleteRecord($table,$uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE)
- * 3033:     function deletePages($uid,$force=FALSE,$forceHardDelete=FALSE)
- * 3061:     function deleteSpecificPage($uid,$forceHardDelete=FALSE)
- * 3084:     function canDeletePage($uid)
- * 3111:     function cannotDeleteRecord($table,$id)
+ * 2941:     function deleteAction($table, $id)
+ * 2988:     function deleteEl($table, $uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE)
+ * 3008:     function deleteRecord($table,$uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE)
+ * 3068:     function deletePages($uid,$force=FALSE,$forceHardDelete=FALSE)
+ * 3096:     function deleteSpecificPage($uid,$forceHardDelete=FALSE)
+ * 3119:     function canDeletePage($uid)
+ * 3146:     function cannotDeleteRecord($table,$id)
  *
  *              SECTION: Cmd: Versioning
- * 3149:     function versionizeRecord($table,$id,$label,$delete=FALSE,$versionizeTree=-1)
- * 3225:     function versionizePages($uid,$label,$versionizeTree)
- * 3288:     function version_swap($table,$id,$swapWith,$swapIntoWS=0)
- * 3445:     function version_clearWSID($table,$id)
- * 3478:     function version_setStage($table,$id,$stageId,$comment='')
+ * 3184:     function versionizeRecord($table,$id,$label,$delete=FALSE,$versionizeTree=-1)
+ * 3260:     function versionizePages($uid,$label,$versionizeTree)
+ * 3323:     function version_swap($table,$id,$swapWith,$swapIntoWS=0)
+ * 3485:     function version_clearWSID($table,$id)
+ * 3518:     function version_setStage($table,$id,$stageId,$comment='')
  *
  *              SECTION: Cmd: Helper functions
- * 3523:     function remapListedDBRecords()
- * 3600:     function remapListedDBRecords_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2)
- * 3626:     function remapListedDBRecords_procDBRefs($conf, $value, $MM_localUid)
+ * 3563:     function remapListedDBRecords()
+ * 3640:     function remapListedDBRecords_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2)
+ * 3666:     function remapListedDBRecords_procDBRefs($conf, $value, $MM_localUid)
  *
  *              SECTION: Access control / Checking functions
- * 3690:     function checkModifyAccessList($table)
- * 3702:     function isRecordInWebMount($table,$id)
- * 3716:     function isInWebMount($pid)
- * 3730:     function checkRecordUpdateAccess($table,$id)
- * 3754:     function checkRecordInsertAccess($insertTable,$pid,$action=1)
- * 3788:     function isTableAllowedForThisPage($page_uid, $checkTable)
- * 3821:     function doesRecordExist($table,$id,$perms)
- * 3883:     function doesRecordExist_pageLookUp($id, $perms)
- * 3909:     function doesBranchExist($inList,$pid,$perms,$recurse)
- * 3943:     function tableReadOnly($table)
- * 3955:     function tableAdminOnly($table)
- * 3969:     function destNotInsideSelf($dest,$id)
- * 4001:     function getExcludeListArray()
- * 4024:     function doesPageHaveUnallowedTables($page_uid,$doktype)
+ * 3730:     function checkModifyAccessList($table)
+ * 3742:     function isRecordInWebMount($table,$id)
+ * 3756:     function isInWebMount($pid)
+ * 3770:     function checkRecordUpdateAccess($table,$id)
+ * 3794:     function checkRecordInsertAccess($insertTable,$pid,$action=1)
+ * 3828:     function isTableAllowedForThisPage($page_uid, $checkTable)
+ * 3861:     function doesRecordExist($table,$id,$perms)
+ * 3923:     function doesRecordExist_pageLookUp($id, $perms)
+ * 3949:     function doesBranchExist($inList,$pid,$perms,$recurse)
+ * 3983:     function tableReadOnly($table)
+ * 3995:     function tableAdminOnly($table)
+ * 4009:     function destNotInsideSelf($dest,$id)
+ * 4041:     function getExcludeListArray()
+ * 4064:     function doesPageHaveUnallowedTables($page_uid,$doktype)
  *
  *              SECTION: Information lookup
- * 4073:     function pageInfo($id,$field)
- * 4093:     function recordInfo($table,$id,$fieldList)
- * 4112:     function getRecordProperties($table,$id)
- * 4126:     function getRecordPropertiesFromRow($table,$row)
+ * 4113:     function pageInfo($id,$field)
+ * 4133:     function recordInfo($table,$id,$fieldList)
+ * 4154:     function getRecordProperties($table,$id,$noWSOL=FALSE)
+ * 4170:     function getRecordPropertiesFromRow($table,$row)
  *
  *              SECTION: Storing data to Database Layer
- * 4169:     function updateDB($table,$id,$fieldArray)
- * 4217:     function insertDB($table,$id,$fieldArray,$newVersion=FALSE,$suggestedUid=0,$dontSetNewIdIndex=FALSE)
- * 4287:     function checkStoredRecord($table,$id,$fieldArray,$action)
- * 4324:     function setHistory($table,$id,$logId)
- * 4363:     function clearHistory($table,$id,$keepEntries=10,$maxAgeSeconds=604800)
+ * 4213:     function updateDB($table,$id,$fieldArray)
+ * 4265:     function insertDB($table,$id,$fieldArray,$newVersion=FALSE,$suggestedUid=0,$dontSetNewIdIndex=FALSE)
+ * 4338:     function checkStoredRecord($table,$id,$fieldArray,$action)
+ * 4375:     function setHistory($table,$id,$logId)
+ * 4414:     function clearHistory($table,$id,$keepEntries=10,$maxAgeSeconds=604800)
+ * 4441:     function updateRefIndex($table,$id)
  *
  *              SECTION: Misc functions
- * 4412:     function getSortNumber($table,$uid,$pid)
- * 4485:     function resorting($table,$pid,$sortRow, $return_SortNumber_After_This_Uid)
- * 4516:     function setTSconfigPermissions($fieldArray,$TSConfig_p)
- * 4533:     function newFieldArray($table)
- * 4565:     function overrideFieldArray($table,$data)
- * 4581:     function compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray)
- * 4627:     function assemblePermissions($string)
- * 4644:     function rmComma($input)
- * 4654:     function convNumEntityToByteValue($input)
- * 4676:     function destPathFromUploadFolder($folder)
- * 4686:     function deleteClause($table)
- * 4702:     function getTCEMAIN_TSconfig($tscPID)
- * 4717:     function getTableEntries($table,$TSconfig)
- * 4730:     function getPID($table,$uid)
- * 4743:     function dbAnalysisStoreExec()
- * 4759:     function removeRegisteredFiles()
- * 4771:     function removeCacheFiles()
- * 4796:     function int_pageTreeInfo($CPtable,$pid,$counter, $rootID)
- * 4817:     function compileAdminTables()
- * 4834:     function fixUniqueInPid($table,$uid)
- * 4870:     function fixCopyAfterDuplFields($table,$uid,$prevUid,$update, $newData=array())
- * 4895:     function extFileFields($table)
- * 4916:     function getUniqueFields($table)
- * 4941:     function isReferenceField($conf)
- * 4956:     function getCopyHeader($table,$pid,$field,$value,$count,$prevTitle='')
- * 4985:     function prependLabel($table)
- * 5002:     function resolvePid($table,$pid)
- * 5032:     function clearPrefixFromValue($table,$value)
- * 5047:     function extFileFunctions($table,$field,$filelist,$func)
- * 5077:     function noRecordsFromUnallowedTables($inList)
- * 5103:     function notifyStageChange($stat,$stageId,$table,$id,$comment)
- * 5198:     function notifyStageChange_getEmails($listOfUsers,$noTablePrefix=FALSE)
+ * 4473:     function getSortNumber($table,$uid,$pid)
+ * 4546:     function resorting($table,$pid,$sortRow, $return_SortNumber_After_This_Uid)
+ * 4577:     function setTSconfigPermissions($fieldArray,$TSConfig_p)
+ * 4594:     function newFieldArray($table)
+ * 4626:     function overrideFieldArray($table,$data)
+ * 4642:     function compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray)
+ * 4688:     function assemblePermissions($string)
+ * 4705:     function rmComma($input)
+ * 4715:     function convNumEntityToByteValue($input)
+ * 4737:     function destPathFromUploadFolder($folder)
+ * 4747:     function deleteClause($table)
+ * 4763:     function getTCEMAIN_TSconfig($tscPID)
+ * 4778:     function getTableEntries($table,$TSconfig)
+ * 4791:     function getPID($table,$uid)
+ * 4804:     function dbAnalysisStoreExec()
+ * 4820:     function removeRegisteredFiles()
+ * 4832:     function removeCacheFiles()
+ * 4857:     function int_pageTreeInfo($CPtable,$pid,$counter, $rootID)
+ * 4878:     function compileAdminTables()
+ * 4895:     function fixUniqueInPid($table,$uid)
+ * 4931:     function fixCopyAfterDuplFields($table,$uid,$prevUid,$update, $newData=array())
+ * 4956:     function extFileFields($table)
+ * 4977:     function getUniqueFields($table)
+ * 5002:     function isReferenceField($conf)
+ * 5017:     function getCopyHeader($table,$pid,$field,$value,$count,$prevTitle='')
+ * 5046:     function prependLabel($table)
+ * 5063:     function resolvePid($table,$pid)
+ * 5093:     function clearPrefixFromValue($table,$value)
+ * 5108:     function extFileFunctions($table,$field,$filelist,$func)
+ * 5138:     function noRecordsFromUnallowedTables($inList)
+ * 5164:     function notifyStageChange($stat,$stageId,$table,$id,$comment)
+ * 5259:     function notifyStageChange_getEmails($listOfUsers,$noTablePrefix=FALSE)
  *
  *              SECTION: Clearing cache
- * 5244:     function clear_cache($table,$uid)
- * 5353:     function clear_cacheCmd($cacheCmd)
+ * 5305:     function clear_cache($table,$uid)
+ * 5414:     function clear_cacheCmd($cacheCmd)
  *
  *              SECTION: Logging
- * 5459:     function log($table,$recuid,$action,$recpid,$error,$details,$details_nr=-1,$data=array(),$event_pid=-1,$NEWid='')
- * 5476:     function newlog($message, $error=0)
- * 5486:     function printLogErrorMessages($redirect)
+ * 5520:     function log($table,$recuid,$action,$recpid,$error,$details,$details_nr=-1,$data=array(),$event_pid=-1,$NEWid='')
+ * 5537:     function newlog($message, $error=0)
+ * 5547:     function printLogErrorMessages($redirect)
  *
- * TOTAL FUNCTIONS: 112
+ * TOTAL FUNCTIONS: 113
  * (This index is automatically created/updated by the extension "extdeveval")
  *
  */
@@ -196,7 +197,7 @@ require_once (PATH_t3lib.'class.t3lib_loaddbgroup.php');
 require_once (PATH_t3lib.'class.t3lib_parsehtml_proc.php');
 require_once (PATH_t3lib.'class.t3lib_stdgraphic.php');
 require_once (PATH_t3lib.'class.t3lib_basicfilefunc.php');
-
+require_once (PATH_t3lib."class.t3lib_refindex.php");
 
 
 
@@ -3049,6 +3050,9 @@ class t3lib_TCEmain       {
                                        $this->log($table,$uid,3,0,100,$GLOBALS['TYPO3_DB']->sql_error());
                                }
 
+                                       // Update reference index:
+                               $this->updateRefIndex($table,$uid);
+
                        } else $this->log($table,$uid,3,0,1,'Attempt to delete record without delete-permissions');
                }
        }
@@ -3424,6 +3428,10 @@ class t3lib_TCEmain      {
                                                                                if (!count($sqlErrors)) {
                                                                                        $this->newlog('Swapping successful for table "'.$table.'" uid '.$id.'=>'.$swapWith);
 
+                                                                                               // Update reference index:
+                                                                                       $this->updateRefIndex($table,$id);
+                                                                                       $this->updateRefIndex($table,$swapWith);
+
                                                                                                // SWAPPING pids for subrecords:
                                                                                        if ($table=='pages' && $swapVersion['t3ver_swapmode']>=0)       {
 
@@ -4215,10 +4223,14 @@ $this->log($table,$id,6,0,0,'Stage raised...',30,array('comment'=>$comment,'stag
 
                                        // If succees, do...:
                                if (!$GLOBALS['TYPO3_DB']->sql_error()) {
+
                                        if ($this->checkStoredRecords)  {
                                                $newRow = $this->checkStoredRecord($table,$id,$fieldArray,2);
                                        }
 
+                                               // Update reference index:
+                                       $this->updateRefIndex($table,$id);
+
                                                // Set log entry:
                                        $propArr = $this->getRecordPropertiesFromRow($table,$newRow);
                                        $theLogId = $this->log($table,$id,2,$recpid,0,"Record '%s' (%s) was updated.",10,array($propArr['header'],$table.':'.$id),$propArr['event_pid']);
@@ -4291,6 +4303,9 @@ $this->log($table,$id,6,0,0,'Stage raised...',30,array('comment'=>$comment,'stag
                                                $newRow = $this->checkStoredRecord($table,$id,$fieldArray,1);
                                        }
 
+                                               // Update reference index:
+                                       $this->updateRefIndex($table,$id);
+
                                        if ($newVersion)        {
                                                $this->log($table,$id,1,0,0,"New version created of table '%s', uid '%s'",10,array($table,$fieldArray['t3ver_oid']),$newRow['pid'],$NEW_id);
                                        } else {
@@ -4416,7 +4431,18 @@ $this->log($table,$id,6,0,0,'Stage raised...',30,array('comment'=>$comment,'stag
                }
        }
 
-
+       /**
+        * Update Reference Index (sys_refindex) for a record
+        * Should be called any almost any update to a record which could affect references inside the record.
+        *
+        * @param       string          Table name
+        * @param       integer         Record UID
+        * @return      void
+        */
+       function updateRefIndex($table,$id)     {
+               $refIndexObj = t3lib_div::makeInstance('t3lib_refindex');
+               $result = $refIndexObj->updateRefIndexTable($table,$id);
+       }
 
 
 
index afadc4f..cc62458 100755 (executable)
@@ -252,6 +252,28 @@ CREATE TABLE sys_lockedrecords (
 );
 
 #
+# Table structure for table 'sys_refindex'
+#
+CREATE TABLE sys_refindex (
+  hash varchar(32) DEFAULT '' NOT NULL,
+  tablename varchar(40) DEFAULT '' NOT NULL,
+  recuid int(11) DEFAULT '0' NOT NULL,
+  field varchar(40) DEFAULT '' NOT NULL,
+  flexpointer tinytext NOT NULL,
+  softref_key varchar(30) DEFAULT '' NOT NULL,
+  softref_id varchar(40) DEFAULT '' NOT NULL,
+  sorting int(11) DEFAULT '0' NOT NULL,
+  ref_table varchar(40) DEFAULT '' NOT NULL,
+  ref_uid int(11) DEFAULT '0' NOT NULL,
+  ref_string varchar(40) DEFAULT '' NOT NULL,
+
+  PRIMARY KEY (hash),
+  KEY lookup_rec (tablename,recuid),
+  KEY lookup_uid (ref_table,ref_uid),
+  KEY lookup_string (ref_table,ref_string)
+);
+
+#
 # Table structure for table 'sys_log'
 #
 CREATE TABLE sys_log (
index abcceea..058d7c9 100755 (executable)
@@ -183,6 +183,7 @@ require_once (PATH_t3lib.'class.t3lib_parsehtml.php');
 
 require_once (PATH_t3lib.'class.t3lib_basicfilefunc.php');
 require_once (PATH_t3lib.'class.t3lib_extfilefunc.php');
+require_once (PATH_t3lib.'class.t3lib_refindex.php');
 
 
 
@@ -514,10 +515,15 @@ class tx_impexp {
                                                        // Create entry in the PID lookup:
                                                $this->dat['header']['pid_lookup'][$row['pid']][$table][$row['uid']]=1;
 
+                                                       // Initialize reference index object:
+                                               $refIndexObj = t3lib_div::makeInstance('t3lib_refindex');
+                                               $refIndexObj->WSOL = TRUE;      // Yes to workspace overlays for exporting....
+
                                                        // Data:
                                                $this->dat['records'][$table.':'.$row['uid']] = array();
                                                $this->dat['records'][$table.':'.$row['uid']]['data'] = $row;
-                                               $this->dat['records'][$table.':'.$row['uid']]['rels'] = $this->getRelations($table,$row);
+                                               $this->dat['records'][$table.':'.$row['uid']]['rels'] = $refIndexObj->getRelations($table,$row);
+                                               $this->errorLog = array_merge($this->errorLog,$refIndexObj->errorLog);  // Merge error logs.
 
                                                        // Add information about the relations in the record in the header:
                                                $this->dat['header']['records'][$table][$row['uid']]['rels'] = $this->flatDBrels($this->dat['records'][$table.':'.$row['uid']]['rels']);
@@ -888,236 +894,6 @@ class tx_impexp {
        }
 
        /**
-        * Returns relation information for a $table/$row-array
-        * Traverses all fields in input row which are configured in TCA/columns
-        * It looks for hard relations to files and records in the TCA types "select" and "group"
-        *
-        * @param       string          Table
-        * @param       array           Row from table
-        * @return      array           Array with information about relations
-        * @see export_addRecord()
-        */
-       function getRelations($table,$row)      {
-               global $TCA;
-
-                       // Load full table description
-               t3lib_div::loadTCA($table);
-
-                       // Initialize:
-               $uid = $row['uid'];
-               $nonFields = explode(',','uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,pid');
-
-               $outRow = array();
-               foreach($row as $field => $value)       {
-                       if (!in_array($field,$nonFields) && is_array($TCA[$table]['columns'][$field]))  {
-                               $conf = $TCA[$table]['columns'][$field]['config'];
-
-                                       // Add files
-                               if ($result = $this->getRelations_procFiles($value, $conf, $uid))       {
-                                               // Creates an entry for the field with all the files:
-                                       $outRow[$field] = array(
-                                               'type' => 'file',
-                                               'newValueFiles' => $result,
-                                       );
-                               }
-
-                                       // Add DB:
-                               if ($result = $this->getRelations_procDB($value, $conf, $uid))  {
-                                               // Create an entry for the field with all DB relations:
-                                       $outRow[$field] = array(
-                                               'type' => 'db',
-                                               'itemArray' => $result,
-                                       );
-                               }
-
-                                       // For "flex" fieldtypes we need to traverse the structure looking for file and db references of course!
-                               if ($conf['type']=='flex')      {
-
-                                               // Get current value array:
-                                       $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $row, $table);
-                                       $currentValueArray = t3lib_div::xml2array($value);
-
-                                               // Traversing the XML structure, processing files:
-                                       if (is_array($currentValueArray))       {
-                                               $this->temp_flexRelations = array(
-                                                       'db' => array(),
-                                                       'file' => array(),
-                                                       'softrefs' => array()
-                                               );
-
-                                               $iteratorObj = t3lib_div::makeInstance('t3lib_TCEmain');
-                                               $iteratorObj->callBackObj = &$this;
-                                               $iteratorObj->checkValue_flex_procInData(
-                                                                       $currentValueArray['data'],
-                                                                       array(),        // Not used.
-                                                                       array(),        // Not used.
-                                                                       $dataStructArray,
-                                                                       array($table,$uid,$field),      // Parameters.
-                                                                       'getRelations_flexFormCallBack'
-                                                               );
-
-                                                       // Create an entry for the field:
-                                               $outRow[$field] = array(
-                                                       'type' => 'flex',
-                                                       'flexFormRels' => $this->temp_flexRelations,
-                                               );
-#debug($outRow[$field]);
-                                       }
-                               }
-
-                                       // Soft References:
-                               if (strlen($value) && $softRefs = t3lib_BEfunc::explodeSoftRefParserList($conf['softref'], $table, $field))     {
-                                       $softRefValue = $value;
-                                       foreach($softRefs as $spKey => $spParams)       {
-                                               $softRefObj = &t3lib_BEfunc::softRefParserObj($spKey);
-                                               if (is_object($softRefObj))     {
-                                                       $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams);
-                                                       if (is_array($resultArray))     {
-                                                               $outRow[$field]['softrefs']['keys'][$spKey] = $resultArray['elements'];
-                                                               if (strlen($resultArray['content'])) {
-                                                                       $softRefValue = $resultArray['content'];
-                                                               }
-                                                       }
-                                               }
-                                       }
-
-                                       if (is_array($outRow[$field]['softrefs']) && count($outRow[$field]['softrefs']) && strcmp($value,$softRefValue) && strstr($softRefValue,'{softref:'))   {
-#debug($softRefValue,'tokenizedContent');
-                                               $outRow[$field]['softrefs']['tokenizedContent'] = $softRefValue;
-                                       }
-                               }
-                       }
-               }
-
-               return $outRow;
-       }
-
-       /**
-        * Callback function for traversing the FlexForm structure in relation to finding file and DB references!
-        *
-        * @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 of where in the data structure this element is.
-        * @return      array           Result array with key "value" containing the value of the processing.
-        * @see t3lib_TCEmain::checkValue_flex_procInData_travDS()
-        */
-       function getRelations_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $structurePath) {
-
-                       // Implode parameter values:
-               list($table, $uid, $field) = $pParams;
-
-                       // Add files
-               if ($result = $this->getRelations_procFiles($dataValue, $dsConf, $uid)) {
-
-                               // Creates an entry for the field with all the files:
-                       $this->temp_flexRelations['file'][$structurePath] = $result;
-               }
-
-                       // Add DB:
-               if ($result = $this->getRelations_procDB($dataValue, $dsConf, $uid))    {
-
-                               // Create an entry for the field with all DB relations:
-                       $this->temp_flexRelations['db'][$structurePath] = $result;
-               }
-
-                       // Soft References:
-               if (strlen($dataValue) && $softRefs = t3lib_BEfunc::explodeSoftRefParserList($dsConf['softref'], $table, $field))       {
-#debug($softRefs);
-                       $softRefValue = $dataValue;
-                       foreach($softRefs as $spKey => $spParams)       {
-                               $softRefObj = &t3lib_BEfunc::softRefParserObj($spKey);
-                               if (is_object($softRefObj))     {
-                                       $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams, $structurePath);
-                                       if (is_array($resultArray) && is_array($resultArray['elements']))       {
-                                               $this->temp_flexRelations['softrefs'][$structurePath]['keys'][$spKey] = $resultArray['elements'];
-                                               if (strlen($resultArray['content'])) $softRefValue = $resultArray['content'];
-                                       }
-                               }
-                       }
-
-                       if (count($this->temp_flexRelations['softrefs']) && strcmp($dataValue,$softRefValue))   {
-                               $this->temp_flexRelations['softrefs'][$structurePath]['tokenizedContent'] = $softRefValue;
-#debug($this->temp_flexRelations['softrefs'][$structurePath], $structurePath);
-                       }
-               }
-       }
-
-       /**
-        * Check field configuration if it is a file relation field and extract file relations if any
-        *
-        * @param       string          Field value
-        * @param       array           Field configuration array of type "TCA/columns"
-        * @param       integer         Field uid
-        * @return      array           If field type is OK it will return an array with the files inside. Else false
-        */
-       function getRelations_procFiles($value, $conf, $uid)    {
-                       // Take care of files...
-               if ($conf['type']=='group' && $conf['internal_type']=='file')   {
-
-                               // Collect file values in array:
-                       if ($conf['MM'])        {
-                               $theFileValues = array();
-                               $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
-                               $dbAnalysis->start('', 'files', $conf['MM'], $uid);
-
-                               foreach($dbAnalysis->itemArray as $somekey => $someval) {
-                                       if ($someval['id'])     {
-                                               $theFileValues[] = $someval['id'];
-                                       }
-                               }
-                       } else {
-                               $theFileValues = explode(',',$value);
-                       }
-
-                               // Traverse the files and add them:
-                       $uploadFolder = $conf['uploadfolder'];
-                       $dest = $this->destPathFromUploadFolder($uploadFolder);
-                       $newValue = array();
-                       $newValueFiles = array();
-
-                       foreach($theFileValues as $file)        {
-                               if (trim($file))        {
-                                       $realFile = $dest.'/'.trim($file);
-                                       if (@is_file($realFile))        {
-                                               $newValueFiles[] = array(
-                                                       'filename' => $file,
-                                                       'ID' => md5($realFile),
-                                                       'ID_absFile' => $realFile
-                                               );      // the order should be preserved here because.. (?)
-                                       } else $this->error('Missing file: '.$realFile);
-                               }
-                       }
-
-                       return $newValueFiles;
-               }
-       }
-
-       /**
-        * Check field configuration if it is a DB relation field and extract DB relations if any
-        *
-        * @param       string          Field value
-        * @param       array           Field configuration array of type "TCA/columns"
-        * @param       integer         Field uid
-        * @return      array           If field type is OK it will return an array with the database relations. Else false
-        */
-       function getRelations_procDB($value, $conf, $uid)       {
-
-                       // DB record lists:
-               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'];
-
-                       $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
-                       $dbAnalysis->start($value,$allowedTables,$conf['MM'],$uid);
-
-                       return $dbAnalysis->itemArray;
-               }
-       }
-
-       /**
         * DB relations flattend to 1-dim array.
         * The list will be unique, no table/uid combination will appear twice.
         *
@@ -1192,15 +968,6 @@ class tx_impexp {
                return $list;
        }
 
-       /**
-        * Returns destination path to an upload folder given by $folder
-        *
-        * @param       string          Folder relative to PATH_site
-        * @return      string          Input folder prefixed with PATH_site. No checking for existence is done. Output must be a folder without trailing slash.
-        */
-       function destPathFromUploadFolder($folder)      {
-               return PATH_site.$folder;
-       }
 
 
 
@@ -3332,16 +3099,6 @@ class tx_impexp {
        }
 
        /**
-        * Returns true if the TCA/columns field type is a DB reference field
-        *
-        * @param       array           config array for TCA/columns field
-        * @return      boolean         True if DB reference field (group/db or select with foreign-table)
-        */
-       function isReferenceField($conf)        {
-               return ($conf['type']=='group' && $conf['internal_type']=='db') ||      ($conf['type']=='select' && $conf['foreign_table']);
-       }
-
-       /**
         * Checking if a PID is in the webmounts of the user
         *
         * @param       integer         Page ID to check
index d36f8b7..3e70af2 100755 (executable)
@@ -42,6 +42,7 @@ require_once (PATH_t3lib."class.t3lib_loaddbgroup.php");
 require_once (PATH_t3lib."class.t3lib_querygenerator.php");
 require_once (PATH_t3lib."class.t3lib_xml.php");
 require_once (PATH_t3lib."class.t3lib_fullsearch.php");
+require_once (PATH_t3lib."class.t3lib_refindex.php");
 
 $BE_USER->modAccess($MCONF,1);
 
@@ -144,7 +145,8 @@ class SC_mod_tools_dbint_index {
                                "tree" => "Total Page Tree",
                                "relations" => "Database Relations",
                                "search" => "Full search",
-                               "filesearch" => "Find filename"
+                               "filesearch" => "Find filename",
+                               'refindex' => 'Manage Reference Index',
                        ),
                        "search" => array(
                                "raw" => "Raw search in all fields",
@@ -214,6 +216,9 @@ class SC_mod_tools_dbint_index {
                        case "filesearch":
                                $this->func_filesearch();
                        break;
+                       case 'refindex':
+                               $this->func_refindex();
+                       break;
                        default:
                                $this->func_default();
                        break;
@@ -234,6 +239,67 @@ class SC_mod_tools_dbint_index {
                echo $this->content;
        }
 
+       function func_refindex()        {
+               global $TCA,$TYPO3_DB;
+
+               $this->content.=$this->doc->section('',$this->menu);//$this->doc->divider(5);
+               $this->content.=$this->doc->section('',$menu2).$this->doc->spacer(10);
+
+               if (t3lib_div::_GP('_update') || t3lib_div::_GP('_check'))      {
+                       $testOnly = t3lib_div::_GP('_check')?TRUE:FALSE;
+                       $errors = array();
+                       $tableNames = array();
+                       $recCount=0;
+                       $tableCount=0;
+
+                               // Traverse all tables:
+                       foreach($TCA as $tableName => $cfg)     {
+                               $tableNames[] = $tableName;
+                               $tableCount++;
+
+                                       // Traverse all non-deleted records in tables:
+                               $allRecs = $TYPO3_DB->exec_SELECTgetRows('uid',$tableName,'1'.t3lib_BEfunc::deleteClause($tableName));
+                               $uidList = array(0);
+                               foreach($allRecs as $recdat)    {
+                                       $refIndexObj = t3lib_div::makeInstance('t3lib_refindex');
+                                       $result = $refIndexObj->updateRefIndexTable($tableName,$recdat['uid'],$testOnly);
+                                       $uidList[]= $recdat['uid'];
+                                       $recCount++;
+
+                                       if ($result['addedNodes'] || $result['deletedNodes'])   {
+                                               $errors[] = 'Record '.$tableName.':'.$recdat['uid'].' had '.$result['addedNodes'].' added indexes and '.$result['deletedNodes'].' deleted indexes';
+                                               #$errors[] = t3lib_div::view_array($result);
+                                       }
+                               }
+
+                                       // Searching lost indexes for this table:
+                               $where = 'tablename='.$TYPO3_DB->fullQuoteStr($tableName,'sys_refindex').' AND recuid NOT IN ('.implode(',',$uidList).')';
+                               $lostIndexes = $TYPO3_DB->exec_SELECTgetRows('hash','sys_refindex',$where);
+                               if (count($lostIndexes))        {
+                                       $errors[] = 'Table '.$tableName.' has '.count($lostIndexes).' lost indexes which are now deleted';
+                                       if (!$testOnly) $TYPO3_DB->exec_DELETEquery('sys_refindex',$where);
+                               }
+                       }
+
+                               // Searching lost indexes for non-existing tables:
+                       $where = 'tablename NOT IN ('.implode(',',$TYPO3_DB->fullQuoteArray($tableNames,'sys_refindex')).')';
+                       $lostTables = $TYPO3_DB->exec_SELECTgetRows('hash','sys_refindex',$where);
+                       if (count($lostTables)) {
+                               $errors[] = 'Index table hosted '.count($lostTables).' indexes for non-existing tables, now removed';
+                               if (!$testOnly) $TYPO3_DB->exec_DELETEquery('sys_refindex',$where);
+                       }
+
+                       $testedHowMuch = $recCount.' records from '.$tableCount.' tables were checked/updated.<br/>';
+                               // Output content:
+                       $this->content.=$this->doc->section($testOnly ? 'Reference Index TESTED (nothing written)' : 'Reference Index Updated',$testedHowMuch.(count($errors)?implode('<br/>',$errors):'Index Integrity was perfect!'),0,1);
+               }
+
+                       // Output content:
+               $content = 'Click here to update reference index: <input type="submit" name="_update" value="Update now!" /><br/>';
+               $content.= 'Click here to test reference index: <input type="submit" name="_check" value="Check now!" />';
+               $this->content.=$this->doc->section('Update reference index',$content,0,1);
+       }
+
        /**
         * @return      [type]          ...
         */