TYPO3 CMS  TYPO3_6-2
ReferenceIndex.php
Go to the documentation of this file.
1 <?php
3 
19 
33 
48  static protected $nonRelationTables = array(
49  'sys_log' => TRUE,
50  'sys_history' => TRUE,
51  'tx_extensionmanager_domain_model_extension' => TRUE
52  );
53 
65  static protected $nonRelationFields = array(
66  'uid' => TRUE,
67  'perms_userid' => TRUE,
68  'perms_groupid' => TRUE,
69  'perms_user' => TRUE,
70  'perms_group' => TRUE,
71  'perms_everybody' => TRUE,
72  'pid' => TRUE
73  );
74 
81  static protected $cachePrefixTableRelationFields = 'core-refidx-tblRelFields-';
82 
87  public $temp_flexRelations = array();
88 
92  public $errorLog = array();
93 
97  public $WSOL = FALSE;
98 
102  public $relations = array();
103 
107  public $words_strings = array();
108 
112  public $words = array();
113 
114  // Number which we can increase if a change in the code means we will have to force a re-generation of the index.
118  public $hashVersion = 1;
119 
123  protected $workspaceId = 0;
124 
128  protected $runtimeCache = NULL;
129 
133  public function __construct() {
134  $this->runtimeCache = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('cache_runtime');
135  }
136 
142  public function setWorkspaceId($workspaceId) {
143  $this->workspaceId = (int)$workspaceId;
144  }
145 
151  public function getWorkspaceId() {
152  return $this->workspaceId;
153  }
154 
165  public function updateRefIndexTable($tableName, $uid, $testOnly = FALSE) {
166 
167  // First, secure that the index table is not updated with workspace tainted relations:
168  $this->WSOL = FALSE;
169 
170  // Init:
171  $result = array(
172  'keptNodes' => 0,
173  'deletedNodes' => 0,
174  'addedNodes' => 0
175  );
176 
177  // If this table cannot contain relations, skip it
178  if (isset(static::$nonRelationTables[$tableName])) {
179  return $result;
180  }
181 
182  // Fetch tableRelationFields and save them in cache if not there yet
183  $cacheId = static::$cachePrefixTableRelationFields. $tableName;
184  if (!$this->runtimeCache->has($cacheId)) {
185  $tableRelationFields = $this->fetchTableRelationFields($tableName);
186  $this->runtimeCache->set($cacheId, $tableRelationFields);
187  } else {
188  $tableRelationFields = $this->runtimeCache->get($cacheId);
189  }
190 
191  // Get current index from Database with hash as index using $uidIndexField
192  $currentRelations = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
193  '*',
194  'sys_refindex',
195  'tablename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($tableName, 'sys_refindex')
196  . ' AND recuid=' . (int)$uid . ' AND workspace=' . (int)$this->getWorkspaceId(),
197  '', '', '', 'hash'
198  );
199 
200  // If the table has fields which could contain relations and the record does exist (including deleted-flagged)
201  if ($tableRelationFields !== '' && BackendUtility::getRecordRaw($tableName, 'uid=' . (int)$uid, 'uid')) {
202  // Then, get relations:
203  $relations = $this->generateRefIndexData($tableName, $uid);
204  if (is_array($relations)) {
205  // Traverse the generated index:
206  foreach ($relations as $k => $datRec) {
207  if (!is_array($relations[$k])) {
208  continue;
209  }
210  $relations[$k]['hash'] = md5(implode('
211  // First, check if already indexed and if so, unset that row (so in the end we know which rows to remove!)
212  if (isset($currentRelations[$relations[$k]['hash']])) {
213  unset($currentRelations[$relations[$k]['hash']]);
214  $result['keptNodes']++;
215  $relations[$k]['_ACTION'] = 'KEPT';
216  } else {
217  // If new, add it:
218  if (!$testOnly) {
219  $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_refindex', $relations[$k]);
220  }
221  $result['addedNodes']++;
222  $relations[$k]['_ACTION'] = 'ADDED';
223  }
224  }
225  $result['relations'] = $relations;
226  } else {
227  return FALSE;
228  }
229  }
230 
231  // If any old are left, remove them:
232  if (!empty($currentRelations)) {
233  $hashList = array_keys($currentRelations);
234  if (!empty($hashList)) {
235  $result['deletedNodes'] = count($hashList);
236  $result['deletedNodes_hashList'] = implode(',', $hashList);
237  if (!$testOnly) {
238  $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_refindex', 'hash IN (' . implode(',', $GLOBALS['TYPO3_DB']->fullQuoteArray($hashList, 'sys_refindex')) . ')');
239  }
240  }
241  }
242 
243  return $result;
244  }
245 
255  public function generateRefIndexData($tableName, $uid) {
256 
257  if (!isset($GLOBALS['TCA'][$tableName])) {
258  return NULL;
259  }
260 
261  $this->relations = array();
262 
263  // Fetch tableRelationFields and save them in cache if not there yet
264  $cacheId = static::$cachePrefixTableRelationFields . $tableName;
265  if (!$this->runtimeCache->has($cacheId)) {
266  $tableRelationFields = $this->fetchTableRelationFields($tableName);
267  $this->runtimeCache->set($cacheId, $tableRelationFields);
268  } else {
269  $tableRelationFields = $this->runtimeCache->get($cacheId);
270  }
271 
272  // Return if there are no fields which could contain relations
273  if ($tableRelationFields === '') {
274  return $this->relations;
275  }
276 
277  $deleteField = $GLOBALS['TCA'][$tableName]['ctrl']['delete'];
278 
279  if ($tableRelationFields === '*') {
280  // If one field of a record is of type flex, all fields have to be fetched to be passed to BackendUtility::getFlexFormDS
281  $selectFields = '*';
282  } else {
283  // otherwise only fields that might contain relations are fetched
284  $selectFields = 'uid,' . $tableRelationFields . ($deleteField ? ',' . $deleteField : '');
285  }
286 
287  // Get raw record from DB:
288  $record = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow($selectFields, $tableName, 'uid=' . (int)$uid);
289  if (!is_array($record)) {
290  return NULL;
291  }
292 
293  // Initialize:
294  $this->words_strings = array();
295  $this->words = array();
296 
297  // Deleted:
298  $deleted = $deleteField && $record[$deleteField] ? 1 : 0;
299 
300  // Get all relations from record:
301  $recordRelations = $this->getRelations($tableName, $record);
302  // Traverse those relations, compile records to insert in table:
303  foreach ($recordRelations as $fieldName => $fieldRelations) {
304  // Based on type,
305  switch ((string)$fieldRelations['type']) {
306  case 'db':
307  $this->createEntryData_dbRels($tableName, $uid, $fieldName, '', $deleted, $fieldRelations['itemArray']);
308  break;
309  case 'file_reference':
310  // not used (see getRelations()), but fallback to file
311  case 'file':
312  $this->createEntryData_fileRels($tableName, $uid, $fieldName, '', $deleted, $fieldRelations['newValueFiles']);
313  break;
314  case 'flex':
315  // DB references:
316  if (is_array($fieldRelations['flexFormRels']['db'])) {
317  foreach ($fieldRelations['flexFormRels']['db'] as $flexPointer => $subList) {
318  $this->createEntryData_dbRels($tableName, $uid, $fieldName, $flexPointer, $deleted, $subList);
319  }
320  }
321  // File references in flexforms
322  // @todo #65463 Test correct handling of file references in flexforms
323  if (is_array($fieldRelations['flexFormRels']['file'])) {
324  foreach ($fieldRelations['flexFormRels']['file'] as $flexPointer => $subList) {
325  $this->createEntryData_fileRels($tableName, $uid, $fieldName, $flexPointer, $deleted, $subList);
326  }
327  }
328  // Soft references in flexforms
329  // @todo #65464 Test correct handling of soft references in flexforms
330  if (is_array($fieldRelations['flexFormRels']['softrefs'])) {
331  foreach ($fieldRelations['flexFormRels']['softrefs'] as $flexPointer => $subList) {
332  $this->createEntryData_softreferences($tableName, $uid, $fieldName, $flexPointer, $deleted, $subList['keys']);
333  }
334  }
335  break;
336  }
337  // Soft references in the field:
338  if (is_array($fieldRelations['softrefs'])) {
339  $this->createEntryData_softreferences($tableName, $uid, $fieldName, '', $deleted, $fieldRelations['softrefs']['keys']);
340  }
341  }
342 
343  return $this->relations;
344  }
345 
364  public function createEntryData($table, $uid, $field, $flexpointer, $deleted, $ref_table, $ref_uid, $ref_string = '', $sort = -1, $softref_key = '', $softref_id = '') {
365  if (BackendUtility::isTableWorkspaceEnabled($table)) {
366  $element = BackendUtility::getRecord($table, $uid, 't3ver_wsid');
367  if ($element !== NULL && isset($element['t3ver_wsid']) && (int)$element['t3ver_wsid'] !== $this->getWorkspaceId()) {
368  //The given Element is ws-enabled but doesn't live in the selected workspace
369  // => don't add index as it's not actually there
370  return FALSE;
371  }
372  }
373  return array(
374  'tablename' => $table,
375  'recuid' => $uid,
376  'field' => $field,
377  'flexpointer' => $flexpointer,
378  'softref_key' => $softref_key,
379  'softref_id' => $softref_id,
380  'sorting' => $sort,
381  'deleted' => $deleted,
382  'workspace' => $this->getWorkspaceId(),
383  'ref_table' => $ref_table,
384  'ref_uid' => $ref_uid,
385  'ref_string' => $ref_string
386  );
387  }
388 
401  public function createEntryData_dbRels($table, $uid, $fieldname, $flexpointer, $deleted, $items) {
402  foreach ($items as $sort => $i) {
403  $this->relations[] = $this->createEntryData($table, $uid, $fieldname, $flexpointer, $deleted, $i['table'], $i['id'], '', $sort);
404  }
405  }
406 
419  public function createEntryData_fileRels($table, $uid, $fieldname, $flexpointer, $deleted, $items) {
420  foreach ($items as $sort => $i) {
421  $filePath = $i['ID_absFile'];
422  if (GeneralUtility::isFirstPartOfStr($filePath, PATH_site)) {
424  }
425  $this->relations[] = $this->createEntryData($table, $uid, $fieldname, $flexpointer, $deleted, '_FILE', 0, $filePath, $sort);
426  }
427  }
428 
441  public function createEntryData_softreferences($table, $uid, $fieldname, $flexpointer, $deleted, $keys) {
442  if (is_array($keys)) {
443  foreach ($keys as $spKey => $elements) {
444  if (is_array($elements)) {
445  foreach ($elements as $subKey => $el) {
446  if (is_array($el['subst'])) {
447  switch ((string) $el['subst']['type']) {
448  case 'db':
449  list($tableName, $recordId) = explode(':', $el['subst']['recordRef']);
450  $this->relations[] = $this->createEntryData($table, $uid, $fieldname, $flexpointer, $deleted, $tableName, $recordId, '', -1, $spKey, $subKey);
451  break;
452  case 'file_reference':
453  // not used (see getRelations()), but fallback to file
454  case 'file':
455  $this->relations[] = $this->createEntryData($table, $uid, $fieldname, $flexpointer, $deleted, '_FILE', 0, $el['subst']['relFileName'], -1, $spKey, $subKey);
456  break;
457  case 'string':
458  $this->relations[] = $this->createEntryData($table, $uid, $fieldname, $flexpointer, $deleted, '_STRING', 0, $el['subst']['tokenValue'], -1, $spKey, $subKey);
459  break;
460  }
461  }
462  }
463  }
464  }
465  }
466  }
467 
468  /*******************************
469  *
470  * Get relations from table row
471  *
472  *******************************/
485  public function getRelations($table, $row, $onlyField = '') {
486  // Initialize:
487  $uid = $row['uid'];
488  $outRow = array();
489  foreach ($row as $field => $value) {
490  if (!isset(static::$nonRelationFields[$field]) && is_array($GLOBALS['TCA'][$table]['columns'][$field]) && (!$onlyField || $onlyField === $field)) {
491  $conf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
492  // Add files
493  $resultsFromFiles = $this->getRelations_procFiles($value, $conf, $uid);
494  if (!empty($resultsFromFiles)) {
495  // We have to fill different arrays here depending on the result.
496  // internal_type file is still a relation of type file and
497  // since http://forge.typo3.org/issues/49538 internal_type file_reference
498  // is a database relation to a sys_file record
499  $fileResultsFromFiles = array();
500  $dbResultsFromFiles = array();
501  foreach ($resultsFromFiles as $resultFromFiles) {
502  if (isset($resultFromFiles['table']) && $resultFromFiles['table'] === 'sys_file') {
503  $dbResultsFromFiles[] = $resultFromFiles;
504  } else {
505  // Creates an entry for the field with all the files:
506  $fileResultsFromFiles[] = $resultFromFiles;
507  }
508  }
509  if (!empty($fileResultsFromFiles)) {
510  $outRow[$field] = array(
511  'type' => 'file',
512  'newValueFiles' => $fileResultsFromFiles
513  );
514  }
515  if (!empty($dbResultsFromFiles)) {
516  $outRow[$field] = array(
517  'type' => 'db',
518  'itemArray' => $dbResultsFromFiles
519  );
520  }
521  }
522  // Add a softref definition for link fields if the TCA does not specify one already
523  if ($conf['type'] === 'input' && isset($conf['wizards']['link']) && empty($conf['softref'])) {
524  $conf['softref'] = 'typolink';
525  }
526  // Add DB:
527  $resultsFromDatabase = $this->getRelations_procDB($value, $conf, $uid, $table, $field);
528  if (!empty($resultsFromDatabase)) {
529  // Create an entry for the field with all DB relations:
530  $outRow[$field] = array(
531  'type' => 'db',
532  'itemArray' => $resultsFromDatabase
533  );
534  }
535  // For "flex" fieldtypes we need to traverse the structure looking for file and db references of course!
536  if ($conf['type'] == 'flex') {
537  // Get current value array:
538  // NOTICE: failure to resolve Data Structures can lead to integrity problems with the reference index. Please look up the note in the JavaDoc documentation for the function \TYPO3\CMS\Backend\Utility\BackendUtility::getFlexFormDS()
539  $currentValueArray = GeneralUtility::xml2array($value);
540  // Traversing the XML structure, processing files:
541  if (is_array($currentValueArray)) {
542  $this->temp_flexRelations = array(
543  'db' => array(),
544  'file' => array(),
545  'softrefs' => array()
546  );
547  // Create and call iterator object:
548  $flexObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Configuration\\FlexForm\\FlexFormTools');
549  $flexObj->traverseFlexFormXMLData($table, $field, $row, $this, 'getRelations_flexFormCallBack');
550  // Create an entry for the field:
551  $outRow[$field] = array(
552  'type' => 'flex',
553  'flexFormRels' => $this->temp_flexRelations
554  );
555  }
556  }
557  // Soft References:
558  if ((string)$value !== '') {
559  $softRefValue = $value;
560  $softRefs = BackendUtility::explodeSoftRefParserList($conf['softref']);
561  if ($softRefs !== FALSE) {
562  foreach ($softRefs as $spKey => $spParams) {
563  $softRefObj = BackendUtility::softRefParserObj($spKey);
564  if (is_object($softRefObj)) {
565  $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams);
566  if (is_array($resultArray)) {
567  $outRow[$field]['softrefs']['keys'][$spKey] = $resultArray['elements'];
568  if ((string)$resultArray['content'] !== '') {
569  $softRefValue = $resultArray['content'];
570  }
571  }
572  }
573  }
574  }
575  if (!empty($outRow[$field]['softrefs']) && (string)$value !== (string)$softRefValue && strpos($softRefValue, '{softref:') !== FALSE) {
576  $outRow[$field]['softrefs']['tokenizedContent'] = $softRefValue;
577  }
578  }
579  }
580  }
581  return $outRow;
582  }
583 
596  public function getRelations_flexFormCallBack($dsArr, $dataValue, $PA, $structurePath, $pObj) {
597  // Removing "data/" in the beginning of path (which points to location in data array)
598  $structurePath = substr($structurePath, 5) . '/';
599  $dsConf = $dsArr['TCEforms']['config'];
600  // Implode parameter values:
601  list($table, $uid, $field) = array(
602  $PA['table'],
603  $PA['uid'],
604  $PA['field']
605  );
606  // Add files
607  $resultsFromFiles = $this->getRelations_procFiles($dataValue, $dsConf, $uid);
608  if (!empty($resultsFromFiles)) {
609  // We have to fill different arrays here depending on the result.
610  // internal_type file is still a relation of type file and
611  // since http://forge.typo3.org/issues/49538 internal_type file_reference
612  // is a database relation to a sys_file record
613  $fileResultsFromFiles = array();
614  $dbResultsFromFiles = array();
615  foreach ($resultsFromFiles as $resultFromFiles) {
616  if (isset($resultFromFiles['table']) && $resultFromFiles['table'] === 'sys_file') {
617  $dbResultsFromFiles[] = $resultFromFiles;
618  } else {
619  $fileResultsFromFiles[] = $resultFromFiles;
620  }
621  }
622  if (!empty($fileResultsFromFiles)) {
623  $this->temp_flexRelations['file'][$structurePath] = $fileResultsFromFiles;
624  }
625  if (!empty($dbResultsFromFiles)) {
626  $this->temp_flexRelations['db'][$structurePath] = $dbResultsFromFiles;
627  }
628  }
629  // Add a softref definition for link fields if the TCA does not specify one already
630  if ($dsConf['type'] === 'input' && isset($dsConf['wizards']['link']) && empty($dsConf['softref'])) {
631  $dsConf['softref'] = 'typolink';
632  }
633  // Add DB:
634  $resultsFromDatabase = $this->getRelations_procDB($dataValue, $dsConf, $uid, $table, $field);
635  if (!empty($resultsFromDatabase)) {
636  // Create an entry for the field with all DB relations:
637  $this->temp_flexRelations['db'][$structurePath] = $resultsFromDatabase;
638  }
639  // Soft References:
640  if (is_array($dataValue) || (string)$dataValue !== '') {
641  $softRefValue = $dataValue;
642  $softRefs = BackendUtility::explodeSoftRefParserList($dsConf['softref']);
643  if ($softRefs !== FALSE) {
644  foreach ($softRefs as $spKey => $spParams) {
645  $softRefObj = BackendUtility::softRefParserObj($spKey);
646  if (is_object($softRefObj)) {
647  $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams, $structurePath);
648  if (is_array($resultArray) && is_array($resultArray['elements'])) {
649  $this->temp_flexRelations['softrefs'][$structurePath]['keys'][$spKey] = $resultArray['elements'];
650  if ((string)$resultArray['content'] !== '') {
651  $softRefValue = $resultArray['content'];
652  }
653  }
654  }
655  }
656  }
657  if (!empty($this->temp_flexRelations['softrefs']) && (string)$dataValue !== (string)$softRefValue) {
658  $this->temp_flexRelations['softrefs'][$structurePath]['tokenizedContent'] = $softRefValue;
659  }
660  }
661  }
662 
672  public function getRelations_procFiles($value, $conf, $uid) {
673  if ($conf['type'] !== 'group' || ($conf['internal_type'] !== 'file' && $conf['internal_type'] !== 'file_reference')) {
674  return FALSE;
675  }
676 
677  // Collect file values in array:
678  if ($conf['MM']) {
679  $theFileValues = array();
680  $dbAnalysis = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Database\\RelationHandler');
681  $dbAnalysis->start('', 'files', $conf['MM'], $uid);
682  foreach ($dbAnalysis->itemArray as $someval) {
683  if ($someval['id']) {
684  $theFileValues[] = $someval['id'];
685  }
686  }
687  } else {
688  $theFileValues = explode(',', $value);
689  }
690  // Traverse the files and add them:
691  $uploadFolder = $conf['internal_type'] == 'file' ? $conf['uploadfolder'] : '';
692  $dest = $this->destPathFromUploadFolder($uploadFolder);
693  $newValueFiles = array();
694  foreach ($theFileValues as $file) {
695  if (trim($file)) {
696  $realFile = $dest . '/' . trim($file);
697  $newValueFile = array(
698  'filename' => basename($file),
699  'ID' => md5($realFile),
700  'ID_absFile' => $realFile
701  );
702  // Set sys_file and id for referenced files
703  if ($conf['internal_type'] === 'file_reference') {
704  try {
705  $file = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->retrieveFileOrFolderObject($file);
706  if ($file instanceof \TYPO3\CMS\Core\Resource\FileInterface) {
707  // For setting this as sys_file relation later, the keys filename, ID and ID_absFile
708  // have not to be included, because the are not evaluated for db relations.
709  $newValueFile = array(
710  'table' => 'sys_file',
711  'id' => $file->getUid()
712  );
713  }
714  } catch (\Exception $e) {
715 
716  }
717  }
718  $newValueFiles[] = $newValueFile;
719  }
720  }
721  return $newValueFiles;
722  }
723 
735  public function getRelations_procDB($value, $conf, $uid, $table = '', $field = '') {
736  // Get IRRE relations
737  if (empty($conf)) {
738  return FALSE;
739  } elseif ($conf['type'] === 'inline' && !empty($conf['foreign_table']) && empty($conf['MM'])) {
740  $dbAnalysis = $this->getRelationHandler();
741  $dbAnalysis->setUseLiveReferenceIds(FALSE);
742  $dbAnalysis->start($value, $conf['foreign_table'], '', $uid, $table, $conf);
743  return $dbAnalysis->itemArray;
744  // DB record lists:
745  } elseif ($this->isDbReferenceField($conf)) {
746  $allowedTables = $conf['type'] == 'group' ? $conf['allowed'] : $conf['foreign_table'] . ',' . $conf['neg_foreign_table'];
747  if ($conf['MM_opposite_field']) {
748  return array();
749  }
750  $dbAnalysis = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Database\\RelationHandler');
751  $dbAnalysis->start($value, $allowedTables, $conf['MM'], $uid, $table, $conf);
752  return $dbAnalysis->itemArray;
753  } elseif ($conf['type'] == 'inline' && $conf['foreign_table'] == 'sys_file_reference') {
754  // @todo It looks like this was never called before since isDbReferenceField also checks for type 'inline' and any 'foreign_table'
755  $files = (array)$GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid_local', 'sys_file_reference', ('tablenames=\'' . $table . '\' AND fieldname=\'' . $field . '\' AND uid_foreign=' . $uid . ' AND deleted=0'));
756  $fileArray = array();
757  foreach ($files as $fileUid) {
758  $fileArray[] = array(
759  'table' => 'sys_file',
760  'id' => $fileUid['uid_local']
761  );
762  }
763  return $fileArray;
764  }
765  }
766 
767  /*******************************
768  *
769  * Setting values
770  *
771  *******************************/
787  public function setReferenceValue($hash, $newValue, $returnDataArray = FALSE, $bypassWorkspaceAdminCheck = FALSE) {
788  if ($GLOBALS['BE_USER']->workspace === 0 && $GLOBALS['BE_USER']->isAdmin() || $bypassWorkspaceAdminCheck) {
789  // Get current index from Database:
790  $refRec = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', 'sys_refindex', 'hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($hash, 'sys_refindex'));
791  // Check if reference existed.
792  if (is_array($refRec)) {
793  if ($GLOBALS['TCA'][$refRec['tablename']]) {
794  // Get that record from database:
795  $record = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', $refRec['tablename'], 'uid=' . (int)$refRec['recuid']);
796  if (is_array($record)) {
797  // Get all relations from record, filter with fieldname:
798  $dbrels = $this->getRelations($refRec['tablename'], $record, $refRec['field']);
799  if ($dat = $dbrels[$refRec['field']]) {
800  // Initialize data array that is to be sent to TCEmain afterwards:
801  $dataArray = array();
802  // Based on type,
803  switch ((string) $dat['type']) {
804  case 'db':
805  $error = $this->setReferenceValue_dbRels($refRec, $dat['itemArray'], $newValue, $dataArray);
806  if ($error) {
807  return $error;
808  }
809  break;
810  case 'file_reference':
811  // not used (see getRelations()), but fallback to file
812  case 'file':
813  $error = $this->setReferenceValue_fileRels($refRec, $dat['newValueFiles'], $newValue, $dataArray);
814  if ($error) {
815  return $error;
816  }
817  break;
818  case 'flex':
819  // DB references:
820  if (is_array($dat['flexFormRels']['db'][$refRec['flexpointer']])) {
821  $error = $this->setReferenceValue_dbRels($refRec, $dat['flexFormRels']['db'][$refRec['flexpointer']], $newValue, $dataArray, $refRec['flexpointer']);
822  if ($error) {
823  return $error;
824  }
825  }
826  // File references
827  if (is_array($dat['flexFormRels']['file'][$refRec['flexpointer']])) {
828  $this->setReferenceValue_fileRels($refRec, $dat['flexFormRels']['file'][$refRec['flexpointer']], $newValue, $dataArray, $refRec['flexpointer']);
829  if ($error) {
830  return $error;
831  }
832  }
833  // Soft references in flexforms
834  if ($refRec['softref_key'] && is_array($dat['flexFormRels']['softrefs'][$refRec['flexpointer']]['keys'][$refRec['softref_key']])) {
835  $error = $this->setReferenceValue_softreferences($refRec, $dat['flexFormRels']['softrefs'][$refRec['flexpointer']], $newValue, $dataArray, $refRec['flexpointer']);
836  if ($error) {
837  return $error;
838  }
839  }
840  break;
841  }
842  // Softreferences in the field:
843  if ($refRec['softref_key'] && is_array($dat['softrefs']['keys'][$refRec['softref_key']])) {
844  $error = $this->setReferenceValue_softreferences($refRec, $dat['softrefs'], $newValue, $dataArray);
845  if ($error) {
846  return $error;
847  }
848  }
849  // Data Array, now ready to sent to TCEmain
850  if ($returnDataArray) {
851  return $dataArray;
852  } else {
853  // Execute CMD array:
854  $tce = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\DataHandling\\DataHandler');
855  $tce->stripslashes_values = FALSE;
856  $tce->dontProcessTransformations = TRUE;
857  $tce->bypassWorkspaceRestrictions = TRUE;
858  $tce->bypassFileHandling = TRUE;
859  // Otherwise this cannot update things in deleted records...
860  $tce->bypassAccessCheckForRecords = TRUE;
861  // Check has been done previously that there is a backend user which is Admin and also in live workspace
862  $tce->start($dataArray, array());
863  $tce->process_datamap();
864  // Return errors if any:
865  if (count($tce->errorLog)) {
866  return LF . 'TCEmain:' . implode((LF . 'TCEmain:'), $tce->errorLog);
867  }
868  }
869  }
870  }
871  } else {
872  return 'ERROR: Tablename "' . $refRec['tablename'] . '" was not in TCA!';
873  }
874  } else {
875  return 'ERROR: No reference record with hash="' . $hash . '" was found!';
876  }
877  } else {
878  return 'ERROR: BE_USER object is not admin OR not in workspace 0 (Live)';
879  }
880  }
881 
893  public function setReferenceValue_dbRels($refRec, $itemArray, $newValue, &$dataArray, $flexpointer = '') {
894  if ((int)$itemArray[$refRec['sorting']]['id'] === (int)$refRec['ref_uid'] && (string)$itemArray[$refRec['sorting']]['table'] === (string)$refRec['ref_table']) {
895  // Setting or removing value:
896  // Remove value:
897  if ($newValue === NULL) {
898  unset($itemArray[$refRec['sorting']]);
899  } else {
900  list($itemArray[$refRec['sorting']]['table'], $itemArray[$refRec['sorting']]['id']) = explode(':', $newValue);
901  }
902  // Traverse and compile new list of records:
903  $saveValue = array();
904  foreach ($itemArray as $pair) {
905  $saveValue[] = $pair['table'] . '_' . $pair['id'];
906  }
907  // Set in data array:
908  if ($flexpointer) {
909  $flexToolObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Configuration\\FlexForm\\FlexFormTools');
910  $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']]['data'] = array();
911  $flexToolObj->setArrayValueByPath(substr($flexpointer, 0, -1), $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']]['data'], implode(',', $saveValue));
912  } else {
913  $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']] = implode(',', $saveValue);
914  }
915  } else {
916  return 'ERROR: table:id pair "' . $refRec['ref_table'] . ':' . $refRec['ref_uid'] . '" did not match that of the record ("' . $itemArray[$refRec['sorting']]['table'] . ':' . $itemArray[$refRec['sorting']]['id'] . '") in sorting index "' . $refRec['sorting'] . '"';
917  }
918  }
919 
931  public function setReferenceValue_fileRels($refRec, $itemArray, $newValue, &$dataArray, $flexpointer = '') {
932  $ID_absFile = \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix($itemArray[$refRec['sorting']]['ID_absFile']);
933  if ($ID_absFile === (string)$refRec['ref_string'] && $refRec['ref_table'] === '_FILE') {
934  // Setting or removing value:
935  // Remove value:
936  if ($newValue === NULL) {
937  unset($itemArray[$refRec['sorting']]);
938  } else {
939  $itemArray[$refRec['sorting']]['filename'] = $newValue;
940  }
941  // Traverse and compile new list of records:
942  $saveValue = array();
943  foreach ($itemArray as $fileInfo) {
944  $saveValue[] = $fileInfo['filename'];
945  }
946  // Set in data array:
947  if ($flexpointer) {
948  $flexToolObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Configuration\\FlexForm\\FlexFormTools');
949  $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']]['data'] = array();
950  $flexToolObj->setArrayValueByPath(substr($flexpointer, 0, -1), $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']]['data'], implode(',', $saveValue));
951  } else {
952  $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']] = implode(',', $saveValue);
953  }
954  } else {
955  return 'ERROR: either "' . $refRec['ref_table'] . '" was not "_FILE" or file PATH_site+"' . $refRec['ref_string'] . '" did not match that of the record ("' . $itemArray[$refRec['sorting']]['ID_absFile'] . '") in sorting index "' . $refRec['sorting'] . '"';
956  }
957  }
958 
970  public function setReferenceValue_softreferences($refRec, $softref, $newValue, &$dataArray, $flexpointer = '') {
971  if (is_array($softref['keys'][$refRec['softref_key']][$refRec['softref_id']])) {
972  // Set new value:
973  $softref['keys'][$refRec['softref_key']][$refRec['softref_id']]['subst']['tokenValue'] = '' . $newValue;
974  // Traverse softreferences and replace in tokenized content to rebuild it with new value inside:
975  foreach ($softref['keys'] as $sfIndexes) {
976  foreach ($sfIndexes as $data) {
977  $softref['tokenizedContent'] = str_replace('{softref:' . $data['subst']['tokenID'] . '}', $data['subst']['tokenValue'], $softref['tokenizedContent']);
978  }
979  }
980  // Set in data array:
981  if (!strstr($softref['tokenizedContent'], '{softref:')) {
982  if ($flexpointer) {
983  $flexToolObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Configuration\\FlexForm\\FlexFormTools');
984  $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']]['data'] = array();
985  $flexToolObj->setArrayValueByPath(substr($flexpointer, 0, -1), $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']]['data'], $softref['tokenizedContent']);
986  } else {
987  $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']] = $softref['tokenizedContent'];
988  }
989  } else {
990  return 'ERROR: After substituting all found soft references there were still soft reference tokens in the text. (theoretically this does not have to be an error if the string "{softref:" happens to be in the field for another reason.)';
991  }
992  } else {
993  return 'ERROR: Soft reference parser key "' . $refRec['softref_key'] . '" or the index "' . $refRec['softref_id'] . '" was not found.';
994  }
995  }
996 
997  /*******************************
998  *
999  * Helper functions
1000  *
1001  *******************************/
1002 
1009  protected function isDbReferenceField(array $configuration) {
1010  return (
1011  ($configuration['type'] === 'group' && $configuration['internal_type'] === 'db')
1012  || (
1013  ($configuration['type'] === 'select' || $configuration['type'] === 'inline')
1014  && !empty($configuration['foreign_table'])
1015  )
1016  );
1017  }
1018 
1026  public function isReferenceField(array $configuration) {
1027  return (
1028  $this->isDbReferenceField($configuration)
1029  ||
1030  ($configuration['type'] === 'group' && ($configuration['internal_type'] === 'file' || $configuration['internal_type'] === 'file_reference')) // getRelations_procFiles
1031  ||
1032  ($configuration['type'] === 'input' && isset($configuration['wizards']['link'])) // getRelations_procDB
1033  ||
1034  $configuration['type'] === 'flex'
1035  ||
1036  isset($configuration['softref'])
1037  ||
1038  (
1039  // @deprecated global soft reference parsers are deprecated since TYPO3 CMS 7 and will be removed in TYPO3 CMS 8
1040  is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'])
1041  && !empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'])
1042  )
1043  );
1044  }
1045 
1052  protected function fetchTableRelationFields($tableName) {
1053  if (!isset($GLOBALS['TCA'][$tableName])) {
1054  return '';
1055  }
1056 
1057  $fields = array();
1058 
1059  foreach ($GLOBALS['TCA'][$tableName]['columns'] as $field => $fieldDefinition) {
1060  if (is_array($fieldDefinition['config'])) {
1061  // Check for flex field
1062  if (isset($fieldDefinition['config']['type']) && $fieldDefinition['config']['type'] === 'flex') {
1063  // Fetch all fields if the is a field of type flex in the table definition because the complete row is passed to
1064  // BackendUtility::getFlexFormDS in the end and might be needed in ds_pointerField or $hookObj->getFlexFormDS_postProcessDS
1065  return '*';
1066  }
1067  // Only fetch this field if it can contain a reference
1068  if ($this->isReferenceField($fieldDefinition['config'])) {
1069  $fields[] = $field;
1070  }
1071  }
1072  }
1073 
1074  return implode(',', $fields);
1075  }
1076 
1084  public function destPathFromUploadFolder($folder) {
1085  if (!$folder) {
1086  return substr(PATH_site, 0, -1);
1087  }
1088  return PATH_site . $folder;
1089  }
1090 
1098  public function error($msg) {
1099  $this->errorLog[] = $msg;
1100  }
1101 
1109  public function updateIndex($testOnly, $cli_echo = FALSE) {
1110  $errors = array();
1111  $tableNames = array();
1112  $recCount = 0;
1113  $tableCount = 0;
1114  $headerContent = $testOnly ? 'Reference Index being TESTED (nothing written, use "--refindex update" to update)' : 'Reference Index being Updated';
1115  if ($cli_echo) {
1116  echo '*******************************************' . LF . $headerContent . LF . '*******************************************' . LF;
1117  }
1118  // Traverse all tables:
1119  foreach ($GLOBALS['TCA'] as $tableName => $cfg) {
1120  if (isset(static::$nonRelationTables[$tableName])) {
1121  continue;
1122  }
1123  // Traverse all records in tables, including deleted records:
1124  $fieldNames = (BackendUtility::isTableWorkspaceEnabled($tableName) ? 'uid,t3ver_wsid' : 'uid');
1125  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fieldNames, $tableName, '1=1');
1126  if ($GLOBALS['TYPO3_DB']->sql_error()) {
1127  // Table exists in $TCA but does not exist in the database
1128  GeneralUtility::sysLog(sprintf('Table "%s" exists in $TCA but does not exist in the database. You should run the Database Analyzer in the Install Tool to fix this.', $tableName), 'core', GeneralUtility::SYSLOG_SEVERITY_ERROR);
1129  continue;
1130  }
1131  $tableNames[] = $tableName;
1132  $tableCount++;
1133  $uidList = array(0);
1134  while ($recdat = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
1136  $refIndexObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Database\\ReferenceIndex');
1137  if (isset($recdat['t3ver_wsid'])) {
1138  $refIndexObj->setWorkspaceId($recdat['t3ver_wsid']);
1139  }
1140  $result = $refIndexObj->updateRefIndexTable($tableName, $recdat['uid'], $testOnly);
1141  $uidList[] = $recdat['uid'];
1142  $recCount++;
1143  if ($result['addedNodes'] || $result['deletedNodes']) {
1144  $Err = 'Record ' . $tableName . ':' . $recdat['uid'] . ' had ' . $result['addedNodes'] . ' added indexes and ' . $result['deletedNodes'] . ' deleted indexes';
1145  $errors[] = $Err;
1146  if ($cli_echo) {
1147  echo $Err . LF;
1148  }
1149  }
1150  }
1151  $GLOBALS['TYPO3_DB']->sql_free_result($res);
1152 
1153  // Searching lost indexes for this table:
1154  $where = 'tablename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($tableName, 'sys_refindex') . ' AND recuid NOT IN (' . implode(',', $uidList) . ')';
1155  $lostIndexes = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('hash', 'sys_refindex', $where);
1156  if (count($lostIndexes)) {
1157  $Err = 'Table ' . $tableName . ' has ' . count($lostIndexes) . ' lost indexes which are now deleted';
1158  $errors[] = $Err;
1159  if ($cli_echo) {
1160  echo $Err . LF;
1161  }
1162  if (!$testOnly) {
1163  $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_refindex', $where);
1164  }
1165  }
1166  }
1167  // Searching lost indexes for non-existing tables:
1168  $where = 'tablename NOT IN (' . implode(',', $GLOBALS['TYPO3_DB']->fullQuoteArray($tableNames, 'sys_refindex')) . ')';
1169  $lostTables = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('hash', 'sys_refindex', $where);
1170  if (count($lostTables)) {
1171  $Err = 'Index table hosted ' . count($lostTables) . ' indexes for non-existing tables, now removed';
1172  $errors[] = $Err;
1173  if ($cli_echo) {
1174  echo $Err . LF;
1175  }
1176  if (!$testOnly) {
1177  $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_refindex', $where);
1178  }
1179  }
1180  $testedHowMuch = $recCount . ' records from ' . $tableCount . ' tables were checked/updated.' . LF;
1181  $bodyContent = $testedHowMuch . (count($errors) ? implode(LF, $errors) : 'Index Integrity was perfect!');
1182  if ($cli_echo) {
1183  echo $testedHowMuch . (count($errors) ? 'Updates: ' . count($errors) : 'Index Integrity was perfect!') . LF;
1184  }
1185  if (!$testOnly) {
1186  $registry = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Registry');
1187  $registry->set('core', 'sys_refindex_lastUpdate', $GLOBALS['EXEC_TIME']);
1188  }
1189  return array($headerContent, $bodyContent, count($errors));
1190  }
1191 
1195  protected function getRelationHandler() {
1196  return GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Database\\RelationHandler');
1197  }
1198 
1199 }
getRelations($table, $row, $onlyField='')
static isFirstPartOfStr($str, $partStr)
$TCA['tx_irretutorial_1ncsv_hotel']
$uid
Definition: server.php:36
if($list_of_literals) if(!empty($literals)) if(!empty($literals)) $result
Analyse literals to prepend the N char to them if their contents aren&#39;t numeric.
getRelations_procDB($value, $conf, $uid, $table='', $field='')
createEntryData_fileRels($table, $uid, $fieldname, $flexpointer, $deleted, $items)
static getRecordRaw($table, $where='', $fields=' *')
createEntryData_softreferences($table, $uid, $fieldname, $flexpointer, $deleted, $keys)
getRelations_flexFormCallBack($dsArr, $dataValue, $PA, $structurePath, $pObj)
createEntryData_dbRels($table, $uid, $fieldname, $flexpointer, $deleted, $items)
createEntryData($table, $uid, $field, $flexpointer, $deleted, $ref_table, $ref_uid, $ref_string='', $sort=-1, $softref_key='', $softref_id='')
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
static xml2array($string, $NSprefix='', $reportDocTag=FALSE)
updateRefIndexTable($tableName, $uid, $testOnly=FALSE)