Documentation TYPO3 par Ameos |
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2006 Kasper Skaarhoj (kasperYYYY@typo3.com) 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00064 require_once(PATH_t3lib.'class.t3lib_tcemain.php'); 00065 require_once(PATH_t3lib.'class.t3lib_flexformtools.php'); 00066 00067 00068 00083 class t3lib_refindex { 00084 00085 var $temp_flexRelations = array(); 00086 var $errorLog = array(); 00087 var $WSOL = FALSE; 00088 var $relations = array(); 00089 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. 00090 00091 00101 function updateRefIndexTable($table,$uid,$testOnly=FALSE) { 00102 00103 // First, secure that the index table is not updated with workspace tainted relations: 00104 $this->WSOL = FALSE; 00105 00106 // Init: 00107 $result = array( 00108 'keptNodes' => 0, 00109 'deletedNodes' => 0, 00110 'addedNodes' => 0 00111 ); 00112 00113 // Get current index from Database: 00114 $currentRels = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows( 00115 '*', 00116 'sys_refindex', 00117 'tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table,'sys_refindex'). 00118 ' AND recuid='.intval($uid), 00119 '','','','hash' 00120 ); 00121 00122 // First, test to see if the record exists (being deleted also means it doesn't exist!) 00123 if (t3lib_BEfunc::getRecordRaw($table,'uid='.intval($uid),'uid')) { 00124 00125 // Then, get relations: 00126 $relations = $this->generateRefIndexData($table,$uid); 00127 00128 if (is_array($relations)) { 00129 00130 // Traverse the generated index: 00131 foreach($relations as $k => $datRec) { 00132 $relations[$k]['hash'] = md5(implode(' 00133 00134 // First, check if already indexed and if so, unset that row (so in the end we know which rows to remove!) 00135 if (isset($currentRels[$relations[$k]['hash']])) { 00136 unset($currentRels[$relations[$k]['hash']]); 00137 $result['keptNodes']++; 00138 $relations[$k]['_ACTION'] = 'KEPT'; 00139 } else { 00140 // If new, add it: 00141 if (!$testOnly) $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_refindex',$relations[$k]); 00142 $result['addedNodes']++; 00143 $relations[$k]['_ACTION'] = 'ADDED'; 00144 } 00145 } 00146 00147 $result['relations'] = $relations; 00148 } else return FALSE; // Weird mistake I would say... 00149 } 00150 00151 // If any old are left, remove them: 00152 if (count($currentRels)) { 00153 $hashList = array_keys($currentRels); 00154 if (count($hashList)) { 00155 $result['deletedNodes'] = count($hashList); 00156 $result['deletedNodes_hashList'] = implode(',',$hashList); 00157 if (!$testOnly) $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_refindex','hash IN ('.implode(',',$GLOBALS['TYPO3_DB']->fullQuoteArray($hashList,'sys_refindex')).')'); 00158 } 00159 } 00160 00161 return $result; 00162 } 00163 00172 function generateRefIndexData($table,$uid) { 00173 global $TCA; 00174 00175 if (isset($TCA[$table])) { 00176 // Get raw record from DB: 00177 list($record) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*',$table,'uid='.intval($uid)); 00178 00179 if (is_array($record)) { 00180 00181 // Deleted: 00182 $deleted = $TCA[$table]['ctrl']['delete'] ? ($record[$TCA[$table]['ctrl']['delete']]?1:0) : 0; 00183 00184 // Get all relations from record: 00185 $dbrels = $this->getRelations($table,$record); 00186 00187 // Traverse those relations, compile records to insert in table: 00188 $this->relations = array(); 00189 foreach($dbrels as $fieldname => $dat) { 00190 00191 // Based on type, 00192 switch((string)$dat['type']) { 00193 case 'db': 00194 $this->createEntryData_dbRels($table,$uid,$fieldname,'',$deleted,$dat['itemArray']); 00195 break; 00196 case 'file': 00197 $this->createEntryData_fileRels($table,$uid,$fieldname,'',$deleted,$dat['newValueFiles']); 00198 break; 00199 case 'flex': 00200 // DB references: 00201 if (is_array($dat['flexFormRels']['db'])) { 00202 foreach($dat['flexFormRels']['db'] as $flexpointer => $subList) { 00203 $this->createEntryData_dbRels($table,$uid,$fieldname,$flexpointer,$deleted,$subList); 00204 } 00205 } 00206 // File references (NOT TESTED!) 00207 if (is_array($dat['flexFormRels']['file'])) { // Not tested 00208 foreach($dat['flexFormRels']['file'] as $flexpointer => $subList) { 00209 $this->createEntryData_fileRels($table,$uid,$fieldname,$flexpointer,$deleted,$subList); 00210 } 00211 } 00212 // Soft references in flexforms (NOT TESTED!) 00213 if (is_array($dat['flexFormRels']['softrefs'])) { 00214 foreach($dat['flexFormRels']['softrefs'] as $flexpointer => $subList) { 00215 $this->createEntryData_softreferences($table,$uid,$fieldname,$flexpointer,$deleted,$subList['keys']); 00216 } 00217 } 00218 break; 00219 } 00220 00221 // Softreferences in the field: 00222 if (is_array($dat['softrefs'])) { 00223 $this->createEntryData_softreferences($table,$uid,$fieldname,'',$deleted,$dat['softrefs']['keys']); 00224 } 00225 } 00226 00227 return $this->relations; 00228 } 00229 } 00230 } 00231 00249 function createEntryData($table,$uid,$field,$flexpointer,$deleted,$ref_table,$ref_uid,$ref_string='',$sort=-1,$softref_key='',$softref_id='') { 00250 return array( 00251 'tablename' => $table, 00252 'recuid' => $uid, 00253 'field' => $field, 00254 'flexpointer' => $flexpointer, 00255 'softref_key' => $softref_key, 00256 'softref_id' => $softref_id, 00257 'sorting' => $sort, 00258 'deleted' => $deleted, 00259 'ref_table' => $ref_table, 00260 'ref_uid' => $ref_uid, 00261 'ref_string' => $ref_string, 00262 ); 00263 } 00264 00276 function createEntryData_dbRels($table,$uid,$fieldname,$flexpointer,$deleted,$items) { 00277 foreach($items as $sort => $i) { 00278 $this->relations[] = $this->createEntryData($table,$uid,$fieldname,$flexpointer,$deleted,$i['table'],$i['id'],'',$sort); 00279 } 00280 } 00281 00293 function createEntryData_fileRels($table,$uid,$fieldname,$flexpointer,$deleted,$items) { 00294 foreach($items as $sort => $i) { 00295 $filePath = $i['ID_absFile']; 00296 if (t3lib_div::isFirstPartOfStr($filePath,PATH_site)) { 00297 $filePath = substr($filePath,strlen(PATH_site)); 00298 } 00299 $this->relations[] = $this->createEntryData($table,$uid,$fieldname,$flexpointer,$deleted,'_FILE',0,$filePath,$sort); 00300 } 00301 } 00302 00314 function createEntryData_softreferences($table,$uid,$fieldname,$flexpointer,$deleted,$keys) { 00315 if (is_array($keys)) { 00316 foreach($keys as $spKey => $elements) { 00317 if (is_array($elements)) { 00318 foreach($elements as $subKey => $el) { 00319 if (is_array($el['subst'])) { 00320 switch((string)$el['subst']['type']) { 00321 case 'db': 00322 list($tableName,$recordId) = explode(':',$el['subst']['recordRef']); 00323 $this->relations[] = $this->createEntryData($table,$uid,$fieldname,$flexpointer,$deleted,$tableName,$recordId,'',-1,$spKey,$subKey); 00324 break; 00325 case 'file': 00326 $this->relations[] = $this->createEntryData($table,$uid,$fieldname,$flexpointer,$deleted,'_FILE',0,$el['subst']['relFileName'],-1,$spKey,$subKey); 00327 break; 00328 case 'string': 00329 $this->relations[] = $this->createEntryData($table,$uid,$fieldname,$flexpointer,$deleted,'_STRING',0,$el['subst']['tokenValue'],-1,$spKey,$subKey); 00330 break; 00331 } 00332 } 00333 } 00334 } 00335 } 00336 } 00337 } 00338 00339 00340 00341 00342 00343 00344 00345 00346 00347 00348 00349 00350 00351 00352 00353 /******************************* 00354 * 00355 * Get relations from table row 00356 * 00357 *******************************/ 00358 00369 function getRelations($table,$row) { 00370 global $TCA; 00371 00372 // Load full table description 00373 t3lib_div::loadTCA($table); 00374 00375 // Initialize: 00376 $uid = $row['uid']; 00377 $nonFields = explode(',','uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,pid'); 00378 00379 $outRow = array(); 00380 foreach($row as $field => $value) { 00381 if (!in_array($field,$nonFields) && is_array($TCA[$table]['columns'][$field])) { 00382 $conf = $TCA[$table]['columns'][$field]['config']; 00383 00384 // Add files 00385 if ($result = $this->getRelations_procFiles($value, $conf, $uid)) { 00386 // Creates an entry for the field with all the files: 00387 $outRow[$field] = array( 00388 'type' => 'file', 00389 'newValueFiles' => $result, 00390 ); 00391 } 00392 00393 // Add DB: 00394 if ($result = $this->getRelations_procDB($value, $conf, $uid)) { 00395 // Create an entry for the field with all DB relations: 00396 $outRow[$field] = array( 00397 'type' => 'db', 00398 'itemArray' => $result, 00399 ); 00400 } 00401 00402 // For "flex" fieldtypes we need to traverse the structure looking for file and db references of course! 00403 if ($conf['type']=='flex') { 00404 00405 // Get current value array: 00406 $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $row, $table,'',$this->WSOL); 00407 $currentValueArray = t3lib_div::xml2array($value); 00408 00409 // Traversing the XML structure, processing files: 00410 if (is_array($currentValueArray)) { 00411 $this->temp_flexRelations = array( 00412 'db' => array(), 00413 'file' => array(), 00414 'softrefs' => array() 00415 ); 00416 00417 // Create and call iterator object: 00418 $flexObj = t3lib_div::makeInstance('t3lib_flexformtools'); 00419 $flexObj->traverseFlexFormXMLData($table,$field,$row,$this,'getRelations_flexFormCallBack'); 00420 00421 // Create an entry for the field: 00422 $outRow[$field] = array( 00423 'type' => 'flex', 00424 'flexFormRels' => $this->temp_flexRelations, 00425 ); 00426 } 00427 } 00428 00429 // Soft References: 00430 if (strlen($value) && $softRefs = t3lib_BEfunc::explodeSoftRefParserList($conf['softref'])) { 00431 $softRefValue = $value; 00432 foreach($softRefs as $spKey => $spParams) { 00433 $softRefObj = &t3lib_BEfunc::softRefParserObj($spKey); 00434 if (is_object($softRefObj)) { 00435 $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams); 00436 if (is_array($resultArray)) { 00437 $outRow[$field]['softrefs']['keys'][$spKey] = $resultArray['elements']; 00438 if (strlen($resultArray['content'])) { 00439 $softRefValue = $resultArray['content']; 00440 } 00441 } 00442 } 00443 } 00444 00445 if (is_array($outRow[$field]['softrefs']) && count($outRow[$field]['softrefs']) && strcmp($value,$softRefValue) && strstr($softRefValue,'{softref:')) { 00446 $outRow[$field]['softrefs']['tokenizedContent'] = $softRefValue; 00447 } 00448 } 00449 } 00450 } 00451 00452 return $outRow; 00453 } 00454 00466 function getRelations_flexFormCallBack($dsArr, $dataValue, $PA, $structurePath, &$pObj) { 00467 $structurePath = substr($structurePath,5).'/'; // removing "data/" in the beginning of path (which points to location in data array) 00468 00469 $dsConf = $dsArr['TCEforms']['config']; 00470 00471 // Implode parameter values: 00472 list($table, $uid, $field) = array($PA['table'],$PA['uid'],$PA['field']); 00473 00474 // Add files 00475 if ($result = $this->getRelations_procFiles($dataValue, $dsConf, $uid)) { 00476 00477 // Creates an entry for the field with all the files: 00478 $this->temp_flexRelations['file'][$structurePath] = $result; 00479 } 00480 00481 // Add DB: 00482 if ($result = $this->getRelations_procDB($dataValue, $dsConf, $uid)) { 00483 00484 // Create an entry for the field with all DB relations: 00485 $this->temp_flexRelations['db'][$structurePath] = $result; 00486 } 00487 00488 // Soft References: 00489 if (strlen($dataValue) && $softRefs = t3lib_BEfunc::explodeSoftRefParserList($dsConf['softref'])) { 00490 $softRefValue = $dataValue; 00491 foreach($softRefs as $spKey => $spParams) { 00492 $softRefObj = &t3lib_BEfunc::softRefParserObj($spKey); 00493 if (is_object($softRefObj)) { 00494 $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams, $structurePath); 00495 if (is_array($resultArray) && is_array($resultArray['elements'])) { 00496 $this->temp_flexRelations['softrefs'][$structurePath]['keys'][$spKey] = $resultArray['elements']; 00497 if (strlen($resultArray['content'])) $softRefValue = $resultArray['content']; 00498 } 00499 } 00500 } 00501 00502 if (count($this->temp_flexRelations['softrefs']) && strcmp($dataValue,$softRefValue)) { 00503 $this->temp_flexRelations['softrefs'][$structurePath]['tokenizedContent'] = $softRefValue; 00504 } 00505 } 00506 } 00507 00516 function getRelations_procFiles($value, $conf, $uid) { 00517 // Take care of files... 00518 if ($conf['type']=='group' && $conf['internal_type']=='file') { 00519 00520 // Collect file values in array: 00521 if ($conf['MM']) { 00522 $theFileValues = array(); 00523 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup'); 00524 $dbAnalysis->start('', 'files', $conf['MM'], $uid); 00525 00526 foreach($dbAnalysis->itemArray as $somekey => $someval) { 00527 if ($someval['id']) { 00528 $theFileValues[] = $someval['id']; 00529 } 00530 } 00531 } else { 00532 $theFileValues = explode(',',$value); 00533 } 00534 00535 // Traverse the files and add them: 00536 $uploadFolder = $conf['uploadfolder']; 00537 $dest = $this->destPathFromUploadFolder($uploadFolder); 00538 $newValue = array(); 00539 $newValueFiles = array(); 00540 00541 foreach($theFileValues as $file) { 00542 if (trim($file)) { 00543 $realFile = $dest.'/'.trim($file); 00544 if (@is_file($realFile)) { 00545 $newValueFiles[] = array( 00546 'filename' => $file, 00547 'ID' => md5($realFile), 00548 'ID_absFile' => $realFile 00549 ); // the order should be preserved here because.. (?) 00550 } else $this->error('Missing file: '.$realFile); 00551 } 00552 } 00553 00554 return $newValueFiles; 00555 } 00556 } 00557 00566 function getRelations_procDB($value, $conf, $uid) { 00567 00568 // DB record lists: 00569 if ($this->isReferenceField($conf)) { 00570 $allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table']; 00571 $prependName = $conf['type']=='group' ? $conf['prepend_tname'] : $conf['neg_foreign_table']; 00572 00573 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup'); 00574 $dbAnalysis->start($value,$allowedTables,$conf['MM'],$uid); 00575 00576 return $dbAnalysis->itemArray; 00577 } 00578 } 00579 00580 00581 00582 00583 00584 00585 00586 00587 00588 00589 00590 00591 /******************************* 00592 * 00593 * Helper functions 00594 * 00595 *******************************/ 00596 00603 function isReferenceField($conf) { 00604 return ($conf['type']=='group' && $conf['internal_type']=='db') || ($conf['type']=='select' && $conf['foreign_table']); 00605 } 00606 00613 function destPathFromUploadFolder($folder) { 00614 return PATH_site.$folder; 00615 } 00616 00623 function error($msg) { 00624 $this->errorLog[]=$msg; 00625 } 00626 00634 function updateIndex($testOnly,$cli_echo=FALSE) { 00635 global $TCA, $TYPO3_DB; 00636 00637 $errors = array(); 00638 $tableNames = array(); 00639 $recCount=0; 00640 $tableCount=0; 00641 00642 $headerContent = $testOnly ? 'Reference Index TESTED (nothing written)' : 'Reference Index Updated'; 00643 if ($cli_echo) echo 00644 '*******************************************'.chr(10). 00645 $headerContent.chr(10). 00646 '*******************************************'.chr(10); 00647 00648 // Traverse all tables: 00649 foreach ($TCA as $tableName => $cfg) { 00650 $tableNames[] = $tableName; 00651 $tableCount++; 00652 00653 // Traverse all non-deleted records in tables: 00654 $allRecs = $TYPO3_DB->exec_SELECTgetRows('uid',$tableName,'1=1'); //.t3lib_BEfunc::deleteClause($tableName) 00655 $uidList = array(0); 00656 foreach ($allRecs as $recdat) { 00657 $refIndexObj = t3lib_div::makeInstance('t3lib_refindex'); 00658 $result = $refIndexObj->updateRefIndexTable($tableName,$recdat['uid'],$testOnly); 00659 $uidList[]= $recdat['uid']; 00660 $recCount++; 00661 00662 if ($result['addedNodes'] || $result['deletedNodes']) { 00663 $Err = 'Record '.$tableName.':'.$recdat['uid'].' had '.$result['addedNodes'].' added indexes and '.$result['deletedNodes'].' deleted indexes'; 00664 $errors[]= $Err; 00665 if ($cli_echo) echo $Err.chr(10); 00666 #$errors[] = t3lib_div::view_array($result); 00667 } 00668 } 00669 00670 // Searching lost indexes for this table: 00671 $where = 'tablename='.$TYPO3_DB->fullQuoteStr($tableName,'sys_refindex').' AND recuid NOT IN ('.implode(',',$uidList).')'; 00672 $lostIndexes = $TYPO3_DB->exec_SELECTgetRows('hash','sys_refindex',$where); 00673 if (count($lostIndexes)) { 00674 $Err = 'Table '.$tableName.' has '.count($lostIndexes).' lost indexes which are now deleted'; 00675 $errors[]= $Err; 00676 if ($cli_echo) echo $Err.chr(10); 00677 if (!$testOnly) $TYPO3_DB->exec_DELETEquery('sys_refindex',$where); 00678 } 00679 } 00680 00681 // Searching lost indexes for non-existing tables: 00682 $where = 'tablename NOT IN ('.implode(',',$TYPO3_DB->fullQuoteArray($tableNames,'sys_refindex')).')'; 00683 $lostTables = $TYPO3_DB->exec_SELECTgetRows('hash','sys_refindex',$where); 00684 if (count($lostTables)) { 00685 $Err = 'Index table hosted '.count($lostTables).' indexes for non-existing tables, now removed'; 00686 $errors[]= $Err; 00687 if ($cli_echo) echo $Err.chr(10); 00688 if (!$testOnly) $TYPO3_DB->exec_DELETEquery('sys_refindex',$where); 00689 } 00690 00691 $testedHowMuch = $recCount.' records from '.$tableCount.' tables were checked/updated.'.chr(10); 00692 00693 $bodyContent = $testedHowMuch.(count($errors)?implode(chr(10),$errors):'Index Integrity was perfect!'); 00694 if ($cli_echo) echo $testedHowMuch.(count($errors)?'Updates: '.count($errors):'Index Integrity was perfect!').chr(10); 00695 00696 return array($headerContent,$bodyContent); 00697 } 00698 } 00699 00700 00701 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_refindex.php']) { 00702 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_refindex.php']); 00703 } 00704 ?>