TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
RemoteServer.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Workspaces\Controller\Remote;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
36 
41 {
45  protected $gridDataService;
46 
50  protected $stagesService;
51 
55  protected $differenceHandler;
56 
63  public function checkIntegrity(\stdClass $parameters)
64  {
65  $integrity = $this->createIntegrityService($this->getAffectedElements($parameters));
66  $integrity->check();
67  $response = [
68  'result' => $integrity->getStatusRepresentation()
69  ];
70  return $response;
71  }
72 
79  public function getWorkspaceInfos($parameter)
80  {
81  // To avoid too much work we use -1 to indicate that every page is relevant
82  $pageId = $parameter->id > 0 ? $parameter->id : -1;
83  if (!isset($parameter->language) || !MathUtility::canBeInterpretedAsInteger($parameter->language)) {
84  $parameter->language = null;
85  }
86  $versions = $this->getWorkspaceService()->selectVersionsInWorkspace($this->getCurrentWorkspace(), 0, -99, $pageId, $parameter->depth, 'tables_select', $parameter->language);
87  $data = $this->getGridDataService()->generateGridListFromVersions($versions, $parameter, $this->getCurrentWorkspace());
88  return $data;
89  }
90 
97  public function getStageActions(\stdClass $parameter)
98  {
99  $currentWorkspace = $this->getCurrentWorkspace();
100  $stages = [];
101  if ($currentWorkspace != WorkspaceService::SELECT_ALL_WORKSPACES) {
102  $stages = $this->getStagesService()->getStagesForWSUser();
103  }
104  $data = [
105  'total' => count($stages),
106  'data' => $stages
107  ];
108  return $data;
109  }
110 
117  public function getRowDetails($parameter)
118  {
119  $diffReturnArray = [];
120  $liveReturnArray = [];
121  $diffUtility = $this->getDifferenceHandler();
123  $parseObj = GeneralUtility::makeInstance(RteHtmlParser::class);
124  $liveRecord = BackendUtility::getRecord($parameter->table, $parameter->t3ver_oid);
125  $versionRecord = BackendUtility::getRecord($parameter->table, $parameter->uid);
126  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
127  $icon_Live = $iconFactory->getIconForRecord($parameter->table, $liveRecord, Icon::SIZE_SMALL)->render();
128  $icon_Workspace = $iconFactory->getIconForRecord($parameter->table, $versionRecord, Icon::SIZE_SMALL)->render();
129  $stagesService = $this->getStagesService();
130  $stagePosition = $stagesService->getPositionOfCurrentStage($parameter->stage);
131  $fieldsOfRecords = array_keys($liveRecord);
132  if ($GLOBALS['TCA'][$parameter->table]) {
133  if ($GLOBALS['TCA'][$parameter->table]['interface']['showRecordFieldList']) {
134  $fieldsOfRecords = $GLOBALS['TCA'][$parameter->table]['interface']['showRecordFieldList'];
135  $fieldsOfRecords = GeneralUtility::trimExplode(',', $fieldsOfRecords, true);
136  }
137  }
138  foreach ($fieldsOfRecords as $fieldName) {
139  if (empty($GLOBALS['TCA'][$parameter->table]['columns'][$fieldName]['config'])) {
140  continue;
141  }
142  // Get the field's label. If not available, use the field name
143  $fieldTitle = $this->getLanguageService()->sL(BackendUtility::getItemLabel($parameter->table, $fieldName));
144  if (empty($fieldTitle)) {
145  $fieldTitle = $fieldName;
146  }
147  // Gets the TCA configuration for the current field
148  $configuration = $GLOBALS['TCA'][$parameter->table]['columns'][$fieldName]['config'];
149  // check for exclude fields
150  if ($this->getBackendUser()->isAdmin() || $GLOBALS['TCA'][$parameter->table]['columns'][$fieldName]['exclude'] == 0 || GeneralUtility::inList($this->getBackendUser()->groupData['non_exclude_fields'], $parameter->table . ':' . $fieldName)) {
151  // call diff class only if there is a difference
152  if ($configuration['type'] === 'inline' && $configuration['foreign_table'] === 'sys_file_reference') {
153  $useThumbnails = false;
154  if (!empty($configuration['foreign_selector_fieldTcaOverride']['config']['appearance']['elementBrowserAllowed']) && !empty($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'])) {
155  $fileExtensions = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], true);
156  $allowedExtensions = GeneralUtility::trimExplode(',', $configuration['foreign_selector_fieldTcaOverride']['config']['appearance']['elementBrowserAllowed'], true);
157  $differentExtensions = array_diff($allowedExtensions, $fileExtensions);
158  $useThumbnails = empty($differentExtensions);
159  }
160 
161  $liveFileReferences = BackendUtility::resolveFileReferences(
162  $parameter->table,
163  $fieldName,
164  $liveRecord,
165  0
166  );
167  $versionFileReferences = BackendUtility::resolveFileReferences(
168  $parameter->table,
169  $fieldName,
170  $versionRecord,
171  $this->getCurrentWorkspace()
172  );
173  $fileReferenceDifferences = $this->prepareFileReferenceDifferences(
174  $liveFileReferences,
175  $versionFileReferences,
176  $useThumbnails
177  );
178 
179  if ($fileReferenceDifferences === null) {
180  continue;
181  }
182 
183  $diffReturnArray[] = [
184  'field' => $fieldName,
185  'label' => $fieldTitle,
186  'content' => $fileReferenceDifferences['differences']
187  ];
188  $liveReturnArray[] = [
189  'field' => $fieldName,
190  'label' => $fieldTitle,
191  'content' => $fileReferenceDifferences['live']
192  ];
193  } elseif ((string)$liveRecord[$fieldName] !== (string)$versionRecord[$fieldName]) {
194  // Select the human readable values before diff
195  $liveRecord[$fieldName] = BackendUtility::getProcessedValue(
196  $parameter->table,
197  $fieldName,
198  $liveRecord[$fieldName],
199  0,
200  1,
201  false,
202  $liveRecord['uid']
203  );
204  $versionRecord[$fieldName] = BackendUtility::getProcessedValue(
205  $parameter->table,
206  $fieldName,
207  $versionRecord[$fieldName],
208  0,
209  1,
210  false,
211  $versionRecord['uid']
212  );
213 
214  if ($configuration['type'] == 'group' && $configuration['internal_type'] == 'file') {
215  $versionThumb = BackendUtility::thumbCode($versionRecord, $parameter->table, $fieldName, '');
216  $liveThumb = BackendUtility::thumbCode($liveRecord, $parameter->table, $fieldName, '');
217  $diffReturnArray[] = [
218  'field' => $fieldName,
219  'label' => $fieldTitle,
220  'content' => $versionThumb
221  ];
222  $liveReturnArray[] = [
223  'field' => $fieldName,
224  'label' => $fieldTitle,
225  'content' => $liveThumb
226  ];
227  } else {
228  $diffReturnArray[] = [
229  'field' => $fieldName,
230  'label' => $fieldTitle,
231  'content' => $diffUtility->makeDiffDisplay($liveRecord[$fieldName], $versionRecord[$fieldName])
232  ];
233  $liveReturnArray[] = [
234  'field' => $fieldName,
235  'label' => $fieldTitle,
236  'content' => $parseObj->TS_images_rte($liveRecord[$fieldName])
237  ];
238  }
239  }
240  }
241  }
242  // Hook for modifying the difference and live arrays
243  // (this may be used by custom or dynamically-defined fields)
244  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['workspaces']['modifyDifferenceArray'])) {
245  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['workspaces']['modifyDifferenceArray'] as $className) {
246  $hookObject = GeneralUtility::getUserObj($className);
247  if (method_exists($hookObject, 'modifyDifferenceArray')) {
248  $hookObject->modifyDifferenceArray($parameter, $diffReturnArray, $liveReturnArray, $diffUtility);
249  }
250  }
251  }
252  $commentsForRecord = $this->getCommentsForRecord($parameter->uid, $parameter->table);
253 
255  $historyService = GeneralUtility::makeInstance(HistoryService::class);
256  $history = $historyService->getHistory($parameter->table, $parameter->t3ver_oid);
257 
258  $prevStage = $stagesService->getPrevStage($parameter->stage);
259  $nextStage = $stagesService->getNextStage($parameter->stage);
260 
261  if (isset($prevStage[0])) {
262  $prevStage = current($prevStage);
263  }
264 
265  if (isset($nextStage[0])) {
266  $nextStage = current($nextStage);
267  }
268 
269  return [
270  'total' => 1,
271  'data' => [
272  [
273  // these parts contain HTML (don't escape)
274  'diff' => $diffReturnArray,
275  'live_record' => $liveReturnArray,
276  'icon_Live' => $icon_Live,
277  'icon_Workspace' => $icon_Workspace,
278  // this part is already escaped in getCommentsForRecord()
279  'comments' => $commentsForRecord,
280  // escape/sanitize the others
281  'path_Live' => htmlspecialchars(BackendUtility::getRecordPath($liveRecord['pid'], '', 999)),
282  'label_Stage' => htmlspecialchars($stagesService->getStageTitle($parameter->stage)),
283  'label_PrevStage' => $prevStage,
284  'label_NextStage' => $nextStage,
285  'stage_position' => (int)$stagePosition['position'],
286  'stage_count' => (int)$stagePosition['count'],
287  'parent' => [
288  'table' => htmlspecialchars($parameter->table),
289  'uid' => (int)$parameter->uid
290  ],
291  'history' => [
292  'data' => $history,
293  'total' => count($history)
294  ]
295  ]
296  ]
297  ];
298  }
299 
308  protected function prepareFileReferenceDifferences(array $liveFileReferences, array $versionFileReferences, $useThumbnails = false)
309  {
310  $randomValue = uniqid('file');
311 
312  $liveValues = [];
313  $versionValues = [];
314  $candidates = [];
315  $substitutes = [];
316 
317  // Process live references
318  foreach ($liveFileReferences as $identifier => $liveFileReference) {
319  $identifierWithRandomValue = $randomValue . '__' . $liveFileReference->getUid() . '__' . $randomValue;
320  $candidates[$identifierWithRandomValue] = $liveFileReference;
321  $liveValues[] = $identifierWithRandomValue;
322  }
323 
324  // Process version references
325  foreach ($versionFileReferences as $identifier => $versionFileReference) {
326  $identifierWithRandomValue = $randomValue . '__' . $versionFileReference->getUid() . '__' . $randomValue;
327  $candidates[$identifierWithRandomValue] = $versionFileReference;
328  $versionValues[] = $identifierWithRandomValue;
329  }
330 
331  // Combine values and surround by spaces
332  // (to reduce the chunks Diff will find)
333  $liveInformation = ' ' . implode(' ', $liveValues) . ' ';
334  $versionInformation = ' ' . implode(' ', $versionValues) . ' ';
335 
336  // Return if information has not changed
337  if ($liveInformation === $versionInformation) {
338  return null;
339  }
340 
345  foreach ($candidates as $identifierWithRandomValue => $fileReference) {
346  if ($useThumbnails) {
347  $thumbnailFile = $fileReference->getOriginalFile()->process(
349  ['width' => 40, 'height' => 40]
350  );
351  $thumbnailMarkup = '<img src="' . $thumbnailFile->getPublicUrl(true) . '" />';
352  $substitutes[$identifierWithRandomValue] = $thumbnailMarkup;
353  } else {
354  $substitutes[$identifierWithRandomValue] = $fileReference->getPublicUrl();
355  }
356  }
357 
358  $differences = $this->getDifferenceHandler()->makeDiffDisplay($liveInformation, $versionInformation);
359  $liveInformation = str_replace(array_keys($substitutes), array_values($substitutes), trim($liveInformation));
360  $differences = str_replace(array_keys($substitutes), array_values($substitutes), trim($differences));
361 
362  return [
363  'live' => $liveInformation,
364  'differences' => $differences
365  ];
366  }
367 
375  public function getCommentsForRecord($uid, $table)
376  {
377  $sysLogReturnArray = [];
378  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_log');
379 
380  $result = $queryBuilder
381  ->select('log_data', 'tstamp', 'userid')
382  ->from('sys_log')
383  ->where(
384  $queryBuilder->expr()->eq(
385  'action',
386  $queryBuilder->createNamedParameter(6, \PDO::PARAM_INT)
387  ),
388  $queryBuilder->expr()->eq(
389  'details_nr',
390  $queryBuilder->createNamedParameter(30, \PDO::PARAM_INT)
391  ),
392  $queryBuilder->expr()->eq(
393  'tablename',
394  $queryBuilder->createNamedParameter($table, \PDO::PARAM_STR)
395  ),
396  $queryBuilder->expr()->eq(
397  'recuid',
398  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
399  )
400  )
401  ->orderBy('tstamp', 'DESC')
402  ->execute();
403 
405  $avatar = GeneralUtility::makeInstance(Avatar::class);
406 
407  while ($sysLogRow = $result->fetch()) {
408  $sysLogEntry = [];
409  $data = unserialize($sysLogRow['log_data']);
410  $beUserRecord = BackendUtility::getRecord('be_users', $sysLogRow['userid']);
411  $sysLogEntry['stage_title'] = htmlspecialchars($this->getStagesService()->getStageTitle($data['stage']));
412  $sysLogEntry['user_uid'] = (int)$sysLogRow['userid'];
413  $sysLogEntry['user_username'] = is_array($beUserRecord) ? htmlspecialchars($beUserRecord['username']) : '';
414  $sysLogEntry['tstamp'] = htmlspecialchars(BackendUtility::datetime($sysLogRow['tstamp']));
415  $sysLogEntry['user_comment'] = nl2br(htmlspecialchars($data['comment']));
416  $sysLogEntry['user_avatar'] = $avatar->render($beUserRecord);
417  $sysLogReturnArray[] = $sysLogEntry;
418  }
419  return $sysLogReturnArray;
420  }
421 
427  public function getSystemLanguages()
428  {
429  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
430  $systemLanguages = [
431  [
432  'uid' => 'all',
433  'title' => LocalizationUtility::translate('language.allLanguages', 'workspaces'),
434  'icon' => $iconFactory->getIcon('empty-empty', Icon::SIZE_SMALL)->render()
435  ]
436  ];
437  foreach ($this->getGridDataService()->getSystemLanguages() as $id => $systemLanguage) {
438  if ($id < 0) {
439  continue;
440  }
441  $systemLanguages[] = [
442  'uid' => $id,
443  'title' => htmlspecialchars($systemLanguage['title']),
444  'icon' => $iconFactory->getIcon($systemLanguage['flagIcon'], Icon::SIZE_SMALL)->render()
445  ];
446  }
447  $result = [
448  'total' => count($systemLanguages),
449  'data' => $systemLanguages
450  ];
451  return $result;
452  }
453 
457  protected function getBackendUser()
458  {
459  return $GLOBALS['BE_USER'];
460  }
461 
465  protected function getLanguageService()
466  {
467  return $GLOBALS['LANG'];
468  }
469 
475  protected function getGridDataService()
476  {
477  if (!isset($this->gridDataService)) {
478  $this->gridDataService = GeneralUtility::makeInstance(GridDataService::class);
479  }
480  return $this->gridDataService;
481  }
482 
488  protected function getStagesService()
489  {
490  if (!isset($this->stagesService)) {
491  $this->stagesService = GeneralUtility::makeInstance(StagesService::class);
492  }
493  return $this->stagesService;
494  }
495 
501  protected function getDifferenceHandler()
502  {
503  if (!isset($this->differenceHandler)) {
504  $this->differenceHandler = GeneralUtility::makeInstance(DiffUtility::class);
505  }
507  }
508 
512  protected function getObjectManager()
513  {
514  return GeneralUtility::makeInstance(ObjectManager::class);
515  }
516 }
static getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit=0)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static getRecord($table, $uid, $fields= '*', $where= '', $useDeleteClause=true)
static translate($key, $extensionName, $arguments=null)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)