TYPO3 CMS  TYPO3_8-7
FrontendEditingController.php
Go to the documentation of this file.
1 <?php
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 
25 
30 {
37  public $TSFE_EDIT;
38 
42  protected $tce;
43 
47  public function initConfigOptions()
48  {
49  $this->TSFE_EDIT = GeneralUtility::_GP('TSFE_EDIT');
50  // Include classes for editing IF editing module in Admin Panel is open
51  if ($GLOBALS['BE_USER']->isFrontendEditingActive()) {
52  if ($this->isEditAction()) {
53  $this->editAction();
54  }
55  }
56  }
57 
69  public function displayEditPanel($content, array $conf, $currentRecord, array $dataArray)
70  {
71  if ($conf['newRecordFromTable']) {
72  $currentRecord = $conf['newRecordFromTable'] . ':NEW';
73  $conf['allow'] = 'new';
74  $checkEditAccessInternals = false;
75  } else {
76  $checkEditAccessInternals = true;
77  }
78  list($table, $uid) = explode(':', $currentRecord);
79  // Page ID for new records, 0 if not specified
80  $newRecordPid = (int)$conf['newRecordInPid'];
81  $newUid = null;
82  if (!$conf['onlyCurrentPid'] || $dataArray['pid'] == $GLOBALS['TSFE']->id) {
83  if ($table === 'pages') {
84  $newUid = $uid;
85  } else {
86  if ($conf['newRecordFromTable']) {
87  $newUid = $GLOBALS['TSFE']->id;
88  if ($newRecordPid) {
89  $newUid = $newRecordPid;
90  }
91  } else {
92  $newUid = -1 * $uid;
93  }
94  }
95  }
96  if ($GLOBALS['TSFE']->displayEditIcons && $table && $this->allowedToEdit($table, $dataArray, $conf, $checkEditAccessInternals) && $this->allowedToEditLanguage($table, $dataArray)) {
97  $editClass = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/classes/class.frontendedit.php']['edit'];
98  if ($editClass) {
99  $edit = GeneralUtility::getUserObj($editClass);
100  if (is_object($edit)) {
101  $allowedActions = $this->getAllowedEditActions($table, $conf, $dataArray['pid']);
102  $content = $edit->editPanel($content, $conf, $currentRecord, $dataArray, $table, $allowedActions, $newUid, $this->getHiddenFields($dataArray));
103  }
104  }
105  }
106  return $content;
107  }
108 
121  public function displayEditIcons($content, $params, array $conf = [], $currentRecord = '', array $dataArray = [], $addUrlParamStr = '')
122  {
123  // Check incoming params:
124  list($currentRecordTable, $currentRecordUID) = explode(':', $currentRecord);
125  list($fieldList, $table) = array_reverse(GeneralUtility::trimExplode(':', $params, true));
126  // Reverse the array because table is optional
127  if (!$table) {
128  $table = $currentRecordTable;
129  } elseif ($table != $currentRecordTable) {
130  // If the table is set as the first parameter, and does not match the table of the current record, then just return.
131  return $content;
132  }
133  $editUid = $dataArray['_LOCALIZED_UID'] ?: $currentRecordUID;
134  // Edit icons imply that the editing action is generally allowed, assuming page and content element permissions permit it.
135  if (!array_key_exists('allow', $conf)) {
136  $conf['allow'] = 'edit';
137  }
138  if ($GLOBALS['TSFE']->displayFieldEditIcons && $table && $this->allowedToEdit($table, $dataArray, $conf) && $fieldList && $this->allowedToEditLanguage($table, $dataArray)) {
139  $editClass = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/classes/class.frontendedit.php']['edit'];
140  if ($editClass) {
141  $edit = GeneralUtility::getUserObj($editClass);
142  if (is_object($edit)) {
143  $content = $edit->editIcons($content, $params, $conf, $currentRecord, $dataArray, $addUrlParamStr, $table, $editUid, $fieldList);
144  }
145  }
146  }
147  return $content;
148  }
149 
150  /*****************************************************
151  *
152  * Frontend Editing
153  *
154  ****************************************************/
161  public function isEditAction()
162  {
163  if (is_array($this->TSFE_EDIT)) {
164  if ($this->TSFE_EDIT['cancel']) {
165  unset($this->TSFE_EDIT['cmd']);
166  } else {
167  $cmd = (string)$this->TSFE_EDIT['cmd'];
168  if (($cmd !== 'edit' || is_array($this->TSFE_EDIT['data']) && ($this->TSFE_EDIT['doSave'] || $this->TSFE_EDIT['update'] || $this->TSFE_EDIT['update_close'])) && $cmd !== 'new') {
169  // $cmd can be a command like "hide" or "move". If $cmd is "edit" or "new" it's an indication to show the formfields. But if data is sent with update-flag then $cmd = edit is accepted because edit may be sent because of .keepGoing flag.
170  return true;
171  }
172  }
173  }
174  return false;
175  }
176 
184  public function isEditFormShown()
185  {
186  if (is_array($this->TSFE_EDIT)) {
187  $cmd = (string)$this->TSFE_EDIT['cmd'];
188  if ($cmd === 'edit' || $cmd === 'new') {
189  return true;
190  }
191  }
192  }
193 
201  public function editAction()
202  {
203  // Commands
204  list($table, $uid) = explode(':', $this->TSFE_EDIT['record']);
205  $uid = (int)$uid;
206  $cmd = $this->TSFE_EDIT['cmd'];
207  // Look for some TSFE_EDIT data that indicates we should save.
208  if (($this->TSFE_EDIT['doSave'] || $this->TSFE_EDIT['update'] || $this->TSFE_EDIT['update_close']) && is_array($this->TSFE_EDIT['data'])) {
209  $cmd = 'save';
210  }
211  if ($cmd === 'save' || $cmd && $table && $uid && isset($GLOBALS['TCA'][$table])) {
212  // Hook for defining custom editing actions. Naming is incorrect, but preserves compatibility.
213  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['extEditAction'])) {
214  $_params = [];
215  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['extEditAction'] as $_funcRef) {
216  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
217  }
218  }
219  // Perform the requested editing command.
220  $cmdAction = 'do' . ucwords($cmd);
221  if (is_callable([$this, $cmdAction])) {
222  $this->{$cmdAction}($table, $uid);
223  } else {
224  throw new \UnexpectedValueException('The specified frontend edit command (' . $cmd . ') is not valid.', 1225818120);
225  }
226  }
227  }
228 
235  public function doHide($table, $uid)
236  {
237  $hideField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
238  if ($hideField) {
239  $recData = [];
240  $recData[$table][$uid][$hideField] = 1;
241  $this->initializeTceMain();
242  $this->tce->start($recData, []);
243  $this->tce->process_datamap();
244  }
245  }
246 
253  public function doUnhide($table, $uid)
254  {
255  $hideField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
256  if ($hideField) {
257  $recData = [];
258  $recData[$table][$uid][$hideField] = 0;
259  $this->initializeTceMain();
260  $this->tce->start($recData, []);
261  $this->tce->process_datamap();
262  }
263  }
264 
271  public function doUp($table, $uid)
272  {
273  $this->move($table, $uid, 'up');
274  }
275 
282  public function doDown($table, $uid)
283  {
284  $this->move($table, $uid, 'down');
285  }
286 
293  public function doMoveAfter($table, $uid)
294  {
295  $afterUID = $GLOBALS['BE_USER']->frontendEdit->TSFE_EDIT['moveAfter'];
296  $this->move($table, $uid, '', $afterUID);
297  }
298 
307  protected function move($table, $uid, $direction = '', $afterUID = 0)
308  {
309  $dataHandlerCommands = [];
310  $sortField = $GLOBALS['TCA'][$table]['ctrl']['sortby'];
311  if ($sortField) {
312  // Get the current record
313  // Only fetch uid, pid and the fields that are necessary to detect the sorting factors
314  if (isset($GLOBALS['TCA'][$table]['ctrl']['copyAfterDuplFields'])) {
315  $copyAfterDuplicateFields = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['copyAfterDuplFields'], true);
316  } else {
317  $copyAfterDuplicateFields = [];
318  }
319 
320  $fields = $copyAfterDuplicateFields;
321  $fields[] = 'uid';
322  $fields[] = 'pid';
323  $fields[] = $sortField;
324  $fields = array_unique($fields);
325 
326  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
327  ->getQueryBuilderForTable($table);
328  $queryBuilder->getRestrictions()->removeAll();
329 
330  $currentRecord = $queryBuilder
331  ->select(...$fields)
332  ->from($table)
333  ->where($queryBuilder->expr()->eq(
334  'uid',
335  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
336  ))
337  ->execute()
338  ->fetch();
339 
340  if (is_array($currentRecord)) {
341  // Fetch the record before or after the current one
342  // to define the data handler commands
343  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
344  ->getQueryBuilderForTable($table);
345 
346  $queryBuilder
347  ->select('uid', 'pid')
348  ->from($table)
349  ->where($queryBuilder->expr()->eq(
350  'pid',
351  $queryBuilder->createNamedParameter($currentRecord['pid'], \PDO::PARAM_INT)
352  ))
353  ->setMaxResults(2);
354 
355  // Disable the default restrictions (but not all) if the admin panel is in preview mode
356  if ($GLOBALS['BE_USER']->adminPanel instanceof AdminPanelView && $GLOBALS['BE_USER']->adminPanel->extGetFeAdminValue('preview')) {
357  $queryBuilder->getRestrictions()
358  ->removeByType(StartTimeRestriction::class)
359  ->removeByType(EndTimeRestriction::class)
360  ->removeByType(HiddenRestriction::class)
361  ->removeByType(FrontendGroupRestriction::class);
362  }
363 
364  if (!empty($copyAfterDuplicateFields)) {
365  foreach ($copyAfterDuplicateFields as $fieldName) {
366  $queryBuilder->andWhere($queryBuilder->expr()->eq(
367  $fieldName,
368  $queryBuilder->createNamedParameter($currentRecord[$fieldName], \PDO::PARAM_STR)
369  ));
370  }
371  }
372  if (!empty($direction)) {
373  if ($direction === 'up') {
374  $queryBuilder->andWhere(
375  $queryBuilder->expr()->lt(
376  $sortField,
377  $queryBuilder->createNamedParameter($currentRecord[$sortField], \PDO::PARAM_INT)
378  )
379  );
380  $queryBuilder->orderBy($sortField, 'DESC');
381  } else {
382  $queryBuilder->andWhere(
383  $queryBuilder->expr()->gt(
384  $sortField,
385  $queryBuilder->createNamedParameter($currentRecord[$sortField], \PDO::PARAM_INT)
386  )
387  );
388  $queryBuilder->orderBy($sortField, 'ASC');
389  }
390  }
391 
392  $result = $queryBuilder->execute();
393  if ($recordBefore = $result->fetch()) {
394  if ($afterUID) {
395  $dataHandlerCommands[$table][$uid]['move'] = -$afterUID;
396  } elseif ($direction === 'down') {
397  $dataHandlerCommands[$table][$uid]['move'] = -$recordBefore['uid'];
398  } elseif ($recordAfter = $result->fetch()) {
399  // Must take the second record above...
400  $dataHandlerCommands[$table][$uid]['move'] = -$recordAfter['uid'];
401  } else {
402  // ... and if that does not exist, use pid
403  $dataHandlerCommands[$table][$uid]['move'] = $currentRecord['pid'];
404  }
405  } elseif ($direction === 'up') {
406  $dataHandlerCommands[$table][$uid]['move'] = $currentRecord['pid'];
407  }
408  }
409 
410  // If any data handler commands were set, execute the data handler command
411  if (!empty($dataHandlerCommands)) {
412  $this->initializeTceMain();
413  $this->tce->start([], $dataHandlerCommands);
414  $this->tce->process_cmdmap();
415  }
416  }
417  }
418 
425  public function doDelete($table, $uid)
426  {
427  $cmdData[$table][$uid]['delete'] = 1;
428  if (!empty($cmdData)) {
429  $this->initializeTceMain();
430  $this->tce->start([], $cmdData);
431  $this->tce->process_cmdmap();
432  }
433  }
434 
441  public function doSave($table, $uid)
442  {
443  $data = $this->TSFE_EDIT['data'];
444  if (!empty($data)) {
445  $this->initializeTceMain();
446  $this->tce->start($data, []);
447  $this->tce->process_uploads($_FILES);
448  $this->tce->process_datamap();
449  // Save the new UID back into TSFE_EDIT
450  $newUID = $this->tce->substNEWwithIDs['NEW'];
451  if ($newUID) {
452  $GLOBALS['BE_USER']->frontendEdit->TSFE_EDIT['newUID'] = $newUID;
453  }
454  }
455  }
456 
464  public function doSaveAndClose($table, $uid)
465  {
466  $this->doSave($table, $uid);
467  }
468 
476  public function doClose($table, $uid)
477  {
478  }
479 
488  protected function allowedToEditLanguage($table, array $currentRecord)
489  {
490  // If no access right to record languages, return immediately
491  if ($table === 'pages') {
492  $lang = $GLOBALS['TSFE']->sys_language_uid;
493  } elseif ($table === 'tt_content') {
494  $lang = $GLOBALS['TSFE']->sys_language_content;
495  } elseif ($GLOBALS['TCA'][$table]['ctrl']['languageField']) {
496  $lang = $currentRecord[$GLOBALS['TCA'][$table]['ctrl']['languageField']];
497  } else {
498  $lang = -1;
499  }
500  if ($GLOBALS['BE_USER']->checkLanguageAccess($lang)) {
501  $languageAccess = true;
502  } else {
503  $languageAccess = false;
504  }
505  return $languageAccess;
506  }
507 
517  protected function allowedToEdit($table, array $dataArray, array $conf, $checkEditAccessInternals = true)
518  {
519  // Unless permissions specifically allow it, editing is not allowed.
520  $mayEdit = false;
521  if ($checkEditAccessInternals) {
522  $editAccessInternals = $GLOBALS['BE_USER']->recordEditAccessInternals($table, $dataArray, false, false);
523  } else {
524  $editAccessInternals = true;
525  }
526  if ($editAccessInternals) {
527  if ($table === 'pages') {
528  // 2 = permission to edit the page
529  if ($GLOBALS['BE_USER']->isAdmin() || $GLOBALS['BE_USER']->doesUserHaveAccess($dataArray, 2)) {
530  $mayEdit = true;
531  }
532  } else {
533  // 16 = permission to edit content on the page
534  if ($GLOBALS['BE_USER']->isAdmin() || $GLOBALS['BE_USER']->doesUserHaveAccess(\TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('pages', $dataArray['pid']), 16)) {
535  $mayEdit = true;
536  }
537  }
538  if (!$conf['onlyCurrentPid'] || $dataArray['pid'] == $GLOBALS['TSFE']->id) {
539  // Permissions:
540  $types = GeneralUtility::trimExplode(',', strtolower($conf['allow']), true);
541  $allow = array_flip($types);
542  $perms = $GLOBALS['BE_USER']->calcPerms($GLOBALS['TSFE']->page);
543  if ($table === 'pages') {
544  $allow = $this->getAllowedEditActions($table, $conf, $dataArray['pid'], $allow);
545  // Can only display editbox if there are options in the menu
546  if (!empty($allow)) {
547  $mayEdit = true;
548  }
549  } else {
550  $mayEdit = !empty($allow) && $perms & Permission::CONTENT_EDIT;
551  }
552  }
553  }
554  return $mayEdit;
555  }
556 
566  protected function getAllowedEditActions($table, array $conf, $pid, $allow = '')
567  {
568  if (!$allow) {
569  $types = GeneralUtility::trimExplode(',', strtolower($conf['allow']), true);
570  $allow = array_flip($types);
571  }
572  if (!$conf['onlyCurrentPid'] || $pid == $GLOBALS['TSFE']->id) {
573  // Permissions
574  $types = GeneralUtility::trimExplode(',', strtolower($conf['allow']), true);
575  $allow = array_flip($types);
576  $perms = $GLOBALS['BE_USER']->calcPerms($GLOBALS['TSFE']->page);
577  if ($table === 'pages') {
578  // Rootpage
579  if (count($GLOBALS['TSFE']->config['rootLine']) === 1) {
580  unset($allow['move']);
581  unset($allow['hide']);
582  unset($allow['delete']);
583  }
584  if (!($perms & Permission::PAGE_EDIT) || !$GLOBALS['BE_USER']->checkLanguageAccess(0)) {
585  unset($allow['edit']);
586  unset($allow['move']);
587  unset($allow['hide']);
588  }
589  if (!($perms & Permission::PAGE_DELETE)) {
590  unset($allow['delete']);
591  }
592  if (!($perms & Permission::PAGE_NEW)) {
593  unset($allow['new']);
594  }
595  }
596  }
597  return $allow;
598  }
599 
605  public function getJavascriptIncludes()
606  {
607  // No extra JS includes needed
608  return '';
609  }
610 
618  public function getHiddenFields(array $dataArray)
619  {
620  // No special hidden fields needed.
621  return [];
622  }
623 
627  protected function initializeTceMain()
628  {
629  if (!isset($this->tce)) {
630  $this->tce = GeneralUtility::makeInstance(\TYPO3\CMS\Core\DataHandling\DataHandler::class);
631  }
632  }
633 }
displayEditIcons($content, $params, array $conf=[], $currentRecord='', array $dataArray=[], $addUrlParamStr='')
displayEditPanel($content, array $conf, $currentRecord, array $dataArray)
static callUserFunction($funcName, &$params, &$ref, $_='', $errorMode=0)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
allowedToEdit($table, array $dataArray, array $conf, $checkEditAccessInternals=true)
static makeInstance($className,... $constructorArguments)
$fields
Definition: pages.php:4
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']