6a2d0555d1a58917d2babb3acea726c14219a5aa
[Packages/TYPO3.CMS.git] / typo3 / sysext / compatibility7 / Classes / Hooks / PageLayoutActionHook.php
1 <?php
2 namespace TYPO3\CMS\Compatibility7\Hooks;
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
17 use TYPO3\CMS\Backend\Controller\PageLayoutController;
18 use TYPO3\CMS\Backend\Form\FormDataCompiler;
19 use TYPO3\CMS\Backend\Form\FormDataGroup\TcaDatabaseRecord;
20 use TYPO3\CMS\Backend\Form\FormResultCompiler;
21 use TYPO3\CMS\Backend\Form\NodeFactory;
22 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
23 use TYPO3\CMS\Backend\Tree\View\ContentLayoutPagePositionMap;
24 use TYPO3\CMS\Backend\Utility\BackendUtility;
25 use TYPO3\CMS\Core\Database\Connection;
26 use TYPO3\CMS\Core\Database\ConnectionPool;
27 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
28 use TYPO3\CMS\Core\Imaging\Icon;
29 use TYPO3\CMS\Core\Messaging\FlashMessage;
30 use TYPO3\CMS\Core\Messaging\FlashMessageService;
31 use TYPO3\CMS\Core\Utility\GeneralUtility;
32 use TYPO3\CMS\Core\Utility\MathUtility;
33 use TYPO3\CMS\Core\Versioning\VersionState;
34
35 /**
36 * Adds the action `QuickEdit to the module `Web > Layout`
37 */
38 class PageLayoutActionHook
39 {
40
41 /**
42 * @var bool
43 */
44 protected $undoButton;
45
46 /**
47 * @var array
48 */
49 protected $undoButtonR;
50
51 /**
52 * @var bool
53 */
54 protected $deleteButton;
55
56 /**
57 * @var string
58 */
59 protected $closeUrl;
60
61 /**
62 * @var array
63 */
64 protected $eRParts = [];
65
66 /**
67 * The name of the module
68 *
69 * @var string
70 */
71 protected $moduleName = 'web_layout';
72
73 /**
74 * @var string
75 */
76 protected $R_URI;
77
78 /**
79 * @var PageLayoutController
80 */
81 protected $controller;
82
83 /**
84 * Initializes the action
85 *
86 * @param array $parameters the hook parameters
87 * @param PageLayoutController $controller the page layout controller
88 * @return void
89 */
90 public function initAction(array $parameters, PageLayoutController $controller)
91 {
92 $this->controller = $controller;
93 // Add function to MOD_MENU
94 $this->controller->MOD_MENU['function'] = array_slice($this->controller->MOD_MENU['function'], 0, 1, true)
95 + ['0' => $this->getLanguageService()->getLL('m_function_0')] + $this->controller->MOD_MENU['function'];
96 // Remove QuickEdit as option if page type is not...
97 if (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['FE']['content_doktypes'] . ',6', $this->controller->pageinfo['doktype'])) {
98 array_unshift($parameters['actions'], $this->getLanguageService()->getLL('m_function_0'));
99 }
100 // TSconfig settings and blinding of menu-items
101 if ($this->controller->modTSconfig['properties']['QEisDefault']) {
102 ksort($parameters['actions']);
103 }
104 }
105
106 /**
107 * Renders the content of the action
108 *
109 * @param array $parameters the hook parameters
110 * @param PageLayoutController $controller the page layout controller
111 * @return string the module content
112 */
113 public function renderAction(array $parameters, PageLayoutController $controller)
114 {
115 $this->controller = $controller;
116
117 $content = $this->renderContent();
118 $this->makeButtons();
119
120 return $content;
121 }
122
123 /**
124 * Makes the action buttons
125 *
126 * @return void
127 */
128 protected function makeButtons()
129 {
130 $buttonBar = $this->controller->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
131 $iconFactory = $this->controller->getModuleTemplate()->getIconFactory();
132 $lang = $this->getLanguageService();
133 // Add CSH (Context Sensitive Help) icon to tool bar
134 $contextSensitiveHelpButton = $buttonBar->makeHelpButton()
135 ->setModuleName($this->controller->descrTable)
136 ->setFieldName('quickEdit');
137 $buttonBar->addButton($contextSensitiveHelpButton);
138
139 if (!$this->controller->modTSconfig['properties']['disableIconToolbar']) {
140 // Move record
141 if (MathUtility::canBeInterpretedAsInteger($this->eRParts[1])) {
142 $urlParameters = [
143 'table' => $this->eRParts[0],
144 'uid' => $this->eRParts[1],
145 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
146 ];
147 $moveButton = $buttonBar->makeLinkButton()
148 ->setHref(BackendUtility::getModuleUrl('move_element', $urlParameters))
149 ->setTitle($lang->getLL('move_' . ($this->eRParts[0] == 'tt_content' ? 'record' : 'page')))
150 ->setIcon($iconFactory->getIcon('actions-' . ($this->eRParts[0] == 'tt_content' ? 'document' : 'page') . '-move', Icon::SIZE_SMALL));
151 $buttonBar->addButton($moveButton, ButtonBar::BUTTON_POSITION_LEFT, 2);
152 }
153 }
154
155 // Close Record
156 $closeButton = $buttonBar->makeLinkButton()
157 ->setHref('#')
158 ->setOnClick('jumpToUrl(' . GeneralUtility::quoteJSvalue($this->closeUrl) . '); return false;')
159 ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:rm.closeDoc'))
160 ->setIcon($iconFactory->getIcon('actions-document-close', Icon::SIZE_SMALL));
161 $buttonBar->addButton($closeButton, ButtonBar::BUTTON_POSITION_LEFT, 0);
162
163 // Save Record
164 $saveButtonDropdown = $buttonBar->makeSplitButton();
165 $saveButton = $buttonBar->makeInputButton()
166 ->setName('_savedok')
167 ->setValue('1')
168 ->setForm('PageLayoutController')
169 ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:rm.saveDoc'))
170 ->setIcon($iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL));
171 $saveButtonDropdown->addItem($saveButton);
172 $saveAndCloseButton = $buttonBar->makeInputButton()
173 ->setName('_saveandclosedok')
174 ->setValue('1')
175 ->setForm('PageLayoutController')
176 ->setOnClick('document.editform.redirect.value=\'' . $this->closeUrl . '\';')
177 ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:rm.saveCloseDoc'))
178 ->setIcon($iconFactory->getIcon('actions-document-save-close', Icon::SIZE_SMALL));
179 $saveButtonDropdown->addItem($saveAndCloseButton);
180 $saveAndShowPageButton = $buttonBar->makeInputButton()
181 ->setName('_savedokview')
182 ->setValue('1')
183 ->setForm('PageLayoutController')
184 ->setOnClick('document.editform.redirect.value+=\'&popView=1\';')
185 ->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:rm.saveDocShow'))
186 ->setIcon($iconFactory->getIcon('actions-document-save-view', Icon::SIZE_SMALL));
187 $saveButtonDropdown->addItem($saveAndShowPageButton);
188 $buttonBar->addButton($saveButtonDropdown, ButtonBar::BUTTON_POSITION_LEFT, 1);
189
190 // Delete record
191 if ($this->deleteButton) {
192 $dataAttributes = [];
193 $dataAttributes['table'] = $this->eRParts[0];
194 $dataAttributes['uid'] = $this->eRParts[1];
195 $dataAttributes['return-url'] = BackendUtility::getModuleUrl($this->moduleName) . '&id=' . $this->controller->id;
196 $deleteButton = $buttonBar->makeLinkButton()
197 ->setHref('#')
198 ->setClasses('t3js-editform-delete-record')
199 ->setDataAttributes($dataAttributes)
200 ->setTitle($lang->getLL('deleteItem'))
201 ->setIcon($iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL));
202 $buttonBar->addButton($deleteButton, ButtonBar::BUTTON_POSITION_LEFT, 4);
203 }
204
205 // History
206 if ($this->undoButton) {
207 $undoButton = $buttonBar->makeLinkButton()
208 ->setHref('#')
209 ->setOnClick('window.location.href=' .
210 GeneralUtility::quoteJSvalue(
211 BackendUtility::getModuleUrl(
212 'record_history',
213 [
214 'element' => $this->eRParts[0] . ':' . $this->eRParts[1],
215 'revert' => 'ALL_FIELDS',
216 'returnUrl' => $this->R_URI,
217 ]
218 )
219 ) . '; return false;')
220 ->setTitle(sprintf($lang->getLL('undoLastChange'), BackendUtility::calcAge($GLOBALS['EXEC_TIME'] - $this->undoButtonR['tstamp'], $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.minutesHoursDaysYears'))))
221 ->setIcon($iconFactory->getIcon('actions-edit-undo', Icon::SIZE_SMALL));
222 $buttonBar->addButton($undoButton, ButtonBar::BUTTON_POSITION_LEFT, 5);
223 $historyButton = $buttonBar->makeLinkButton()
224 ->setHref('#')
225 ->setOnClick('jumpToUrl(' .
226 GeneralUtility::quoteJSvalue(
227 BackendUtility::getModuleUrl(
228 'record_history',
229 [
230 'element' => $this->eRParts[0] . ':' . $this->eRParts[1],
231 'returnUrl' => $this->R_URI,
232 ]
233 ) . '#latest'
234 ) . ');return false;')
235 ->setTitle($lang->getLL('recordHistory'))
236 ->setIcon($iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL));
237 $buttonBar->addButton($historyButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
238 }
239 }
240
241 /**
242 * Makes the action menu
243 *
244 * @param array $edit_record the record to make the menu for
245 *
246 * @return array
247 */
248 protected function makeMenu($edit_record)
249 {
250 $lang = $this->getLanguageService();
251 $beUser = $this->getBackendUser();
252
253 $quickEditMenu = $this->controller->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
254 $quickEditMenu->setIdentifier('quickEditMenu');
255 $quickEditMenu->setLabel('');
256
257 // Setting close url/return url for exiting this script:
258 // Goes to 'Columns' view if close is pressed (default)
259 $this->closeUrl = $this->controller->local_linkThisScript(['SET' => ['function' => 1]]);
260 if ($this->returnUrl) {
261 $this->closeUrl = $this->returnUrl;
262 }
263 $retUrlStr = $this->returnUrl ? '&returnUrl=' . rawurlencode($this->returnUrl) : '';
264
265 // Creating the selector box, allowing the user to select which element to edit:
266 $isSelected = 0;
267 $languageOverlayRecord = '';
268 if ($this->current_sys_language) {
269 list($languageOverlayRecord) = BackendUtility::getRecordsByField(
270 'pages_language_overlay',
271 'pid',
272 $this->id,
273 'AND sys_language_uid=' . (int)$this->current_sys_language
274 );
275 }
276 if (is_array($languageOverlayRecord)) {
277 $inValue = 'pages_language_overlay:' . $languageOverlayRecord['uid'];
278 $isSelected += (int)$edit_record == $inValue;
279 $menuItem = $quickEditMenu->makeMenuItem()
280 ->setTitle('[ ' . $lang->getLL('editLanguageHeader') . ' ]')
281 ->setHref(BackendUtility::getModuleUrl($this->moduleName) . '&id=' . $this->id . '&edit_record=' . $inValue . $retUrlStr)
282 ->setActive($edit_record == $inValue);
283 $quickEditMenu->addMenuItem($menuItem);
284 } else {
285 $inValue = 'pages:' . $this->id;
286 $isSelected += (int)$edit_record == $inValue;
287 $menuItem = $quickEditMenu->makeMenuItem()
288 ->setTitle('[ ' . $lang->getLL('editPageProperties') . ' ]')
289 ->setHref(BackendUtility::getModuleUrl($this->moduleName) . '&id=' . $this->id . '&edit_record=' . $inValue . $retUrlStr)
290 ->setActive($edit_record == $inValue);
291 $quickEditMenu->addMenuItem($menuItem);
292 }
293
294 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
295 if ($this->controller->MOD_SETTINGS['tt_content_showHidden']) {
296 $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
297 }
298 $queryBuilder->select('*')
299 ->from('tt_content')
300 ->where(
301 $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->controller->id, \PDO::PARAM_INT)),
302 $queryBuilder->expr()->eq(
303 'sys_language_uid',
304 $queryBuilder->createNamedParameter($this->controller->current_sys_language, \PDO::PARAM_INT)
305 ),
306 $queryBuilder->expr()->in(
307 'colPos',
308 $queryBuilder->createNamedParameter(
309 GeneralUtility::intExplode(',', $this->controller->colPosList, true),
310 Connection::PARAM_INT_ARRAY
311 )
312 ),
313 $queryBuilder->expr()->orX(
314 $queryBuilder->expr()->gte(
315 't3ver_state',
316 $queryBuilder->createNamedParameter(
317 (string)new VersionState(VersionState::DEFAULT_STATE),
318 \PDO::PARAM_INT
319 )
320 ),
321 $queryBuilder->expr()->eq(
322 't3ver_wsid',
323 $queryBuilder->createNamedParameter(
324 (string)new VersionState(VersionState::DEFAULT_STATE),
325 \PDO::PARAM_INT
326 )
327 )
328 )
329 )
330 ->orderBy('colPos')
331 ->addOrderBy('sorting');
332 if (!$beUser->user['admin']) {
333 $queryBuilder->andWhere(
334 $queryBuilder->expr()->eq(
335 'editlock',
336 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
337 )
338 );
339 }
340 $statement = $queryBuilder->execute();
341 $colPos = null;
342 $first = 1;
343 // Page is the pid if no record to put this after.
344 $prev = $this->controller->id;
345 while ($cRow = $statement->fetch()) {
346 BackendUtility::workspaceOL('tt_content', $cRow);
347 if (is_array($cRow)) {
348 if ($first) {
349 if (!$edit_record) {
350 $edit_record = 'tt_content:' . $cRow['uid'];
351 }
352 $first = 0;
353 }
354 if (!isset($colPos) || $cRow['colPos'] !== $colPos) {
355 $colPos = $cRow['colPos'];
356 $menuItem = $quickEditMenu->makeMenuItem()
357 ->setTitle(' ')
358 ->setHref('#');
359 $quickEditMenu->addMenuItem($menuItem);
360 $menuItem = $quickEditMenu->makeMenuItem()
361 ->setTitle('__' . $lang->sL(BackendUtility::getLabelFromItemlist('tt_content', 'colPos', $colPos)) . ':__')
362 ->setHref(BackendUtility::getModuleUrl($this->moduleName) . '&id=' . $this->controller->id . '&edit_record=_EDIT_COL:' . $colPos . $retUrlStr);
363 $quickEditMenu->addMenuItem($menuItem);
364 }
365 $inValue = 'tt_content:' . $cRow['uid'];
366 $isSelected += (int)$edit_record == $inValue;
367 $menuItem = $quickEditMenu->makeMenuItem()
368 ->setTitle(GeneralUtility::fixed_lgd_cs(($cRow['header'] ? $cRow['header'] : '[' . $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.no_title') . '] ' . strip_tags($cRow['bodytext'])), $beUser->uc['titleLen']))
369 ->setHref(BackendUtility::getModuleUrl($this->moduleName) . '&id=' . $this->controller->id . '&edit_record=' . $inValue . $retUrlStr)
370 ->setActive($edit_record == $inValue);
371 $quickEditMenu->addMenuItem($menuItem);
372 $prev = -$cRow['uid'];
373 }
374 }
375 // If edit_record is not set (meaning, no content elements was found for this language) we simply set it to create a new element:
376 if (!$edit_record) {
377 $edit_record = 'tt_content:new/' . $prev . '/' . $colPos;
378 $inValue = 'tt_content:new/' . $prev . '/' . $colPos;
379 $isSelected += (int)$edit_record == $inValue;
380 $menuItem = $quickEditMenu->makeMenuItem()
381 ->setTitle('[ ' . $lang->getLL('newLabel') . ' ]')
382 ->setHref(BackendUtility::getModuleUrl($this->moduleName) . '&id=' . $this->controller->id . '&edit_record=' . $inValue . $retUrlStr)
383 ->setActive($edit_record == $inValue);
384 $quickEditMenu->addMenuItem($menuItem);
385 }
386 // If none is yet selected...
387 if (!$isSelected) {
388 $menuItem = $quickEditMenu->makeMenuItem()
389 ->setTitle('__________')
390 ->setHref('#');
391 $quickEditMenu->addMenuItem($menuItem);
392 $menuItem = $quickEditMenu->makeMenuItem()
393 ->setTitle('[ ' . $lang->getLL('newLabel') . ' ]')
394 ->setHref(BackendUtility::getModuleUrl($this->moduleName) . '&id=' . $this->controller->id . '&edit_record=' . $edit_record . $retUrlStr)
395 ->setActive($edit_record == $inValue);
396 $quickEditMenu->addMenuItem($menuItem);
397 }
398 $this->controller->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->addMenu($quickEditMenu);
399 return $edit_record;
400 }
401
402 /**
403 * Renders the action content
404 *
405 * @return string the content
406 */
407 protected function renderContent()
408 {
409 $beUser = $this->getBackendUser();
410 $lang = $this->getLanguageService();
411 // Set the edit_record value for internal use in this function:
412 $edit_record = $this->controller->edit_record;
413 // If a command to edit all records in a column is issue, then select all those elements, and redirect to FormEngine
414 if (substr($edit_record, 0, 9) == '_EDIT_COL') {
415 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
416 if ($this->controller->MOD_SETTINGS['tt_content_showHidden']) {
417 $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
418 }
419 $statement = $queryBuilder->select('*')
420 ->from('tt_content')
421 ->orderBy('sorting')
422 ->where(
423 $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->controller->id, \PDO::PARAM_INT)),
424 $queryBuilder->expr()->eq(
425 'colPos',
426 $queryBuilder->createNamedParameter(substr($edit_record, 10), \PDO::PARAM_INT)
427 ),
428 $queryBuilder->expr()->eq(
429 'sys_language_uid',
430 $queryBuilder->createNamedParameter($this->controller->current_sys_language, \PDO::PARAM_INT)
431 ),
432 $queryBuilder->expr()->orX(
433 $queryBuilder->expr()->gte(
434 't3ver_state',
435 $queryBuilder->createNamedParameter(
436 (string)new VersionState(VersionState::DEFAULT_STATE),
437 \PDO::PARAM_INT
438 )
439 ),
440 $queryBuilder->expr()->eq(
441 't3ver_wsid',
442 $queryBuilder->createNamedParameter($beUser->workspace, \PDO::PARAM_INT)
443 )
444 )
445 )
446 ->execute();
447 $idListA = [];
448 while ($cRow = $statement->fetch()) {
449 $idListA[] = $cRow['uid'];
450 }
451 $url = BackendUtility::getModuleUrl('record_edit', [
452 'edit[tt_content][' . implode(',', $idListA) . ']' => 'edit',
453 'returnUrl' => $this->controller->local_linkThisScript(['edit_record' => ''])
454 ]);
455 HttpUtility::redirect($url);
456 }
457 // If the former record edited was the creation of a NEW record, this will look up the created records uid:
458 if ($this->controller->new_unique_uid) {
459 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_log');
460 $queryBuilder->getRestrictions()->removeAll();
461 $sys_log_row = $queryBuilder->select('tablename', 'recuid')
462 ->from('sys_log')
463 ->where(
464 $queryBuilder->expr()->eq(
465 'userid',
466 $queryBuilder->createNamedParameter($beUser->user['uid'], \PDO::PARAM_INT)
467 ),
468 $queryBuilder->expr()->eq(
469 'NEWid',
470 $queryBuilder->createNamedParameter($this->controller->new_unique_uid, \PDO::PARAM_INT)
471 )
472 )
473 ->execute()
474 ->fetch();
475 if (is_array($sys_log_row)) {
476 $edit_record = $sys_log_row['tablename'] . ':' . $sys_log_row['recuid'];
477 }
478 }
479 $edit_record = $this->makeMenu($edit_record);
480 // Splitting the edit-record cmd value into table/uid:
481 $this->eRParts = explode(':', $edit_record);
482 $tableName = $this->eRParts[0];
483 // Delete-button flag?
484 $this->deleteButton = MathUtility::canBeInterpretedAsInteger($this->eRParts[1]) && $edit_record && ($tableName !== 'pages' && $this->controller->EDIT_CONTENT || $tableName === 'pages' && $this->controller->CALC_PERMS & Permission::PAGE_DELETE);
485 // If undo-button should be rendered (depends on available items in sys_history)
486 $this->undoButton = false;
487
488 // if there is no content on a page
489 // the parameter $this->eRParts[1] will be set to e.g. /new/1
490 // which is not an integer value and it will throw an exception here on certain dbms
491 // thus let's check that before as there cannot be a history for a new record
492 $this->undoButtonR = false;
493 if (MathUtility::canBeInterpretedAsInteger($this->eRParts[1])) {
494 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_history');
495 $queryBuilder->getRestrictions()->removeAll();
496 $this->undoButtonR = $queryBuilder->select('tstamp')
497 ->from('sys_history')
498 ->where(
499 $queryBuilder->expr()->eq(
500 'tablename',
501 $queryBuilder->createNamedParameter($tableName, \PDO::PARAM_STR)
502 ),
503 $queryBuilder->expr()->eq(
504 'recuid',
505 $queryBuilder->createNamedParameter($this->eRParts[1], \PDO::PARAM_INT)
506 )
507 )
508 ->orderBy('tstamp', 'DESC')
509 ->setMaxResults(1)
510 ->execute()
511 ->fetch();
512 }
513 if ($this->undoButtonR) {
514 $this->undoButton = true;
515 }
516 // Setting up the Return URL for coming back to THIS script (if links take the user to another script)
517 $R_URL_parts = parse_url(GeneralUtility::getIndpEnv('REQUEST_URI'));
518 $R_URL_getvars = GeneralUtility::_GET();
519 unset($R_URL_getvars['popView']);
520 unset($R_URL_getvars['new_unique_uid']);
521 $R_URL_getvars['edit_record'] = $edit_record;
522 $this->R_URI = $R_URL_parts['path'] . '?' . GeneralUtility::implodeArrayForUrl('', $R_URL_getvars);
523
524 // Creating editing form:
525 if ($edit_record) {
526 // Splitting uid parts for special features, if new:
527 list($uidVal, $neighborRecordUid, $ex_colPos) = explode('/', $this->eRParts[1]);
528
529 if ($uidVal === 'new') {
530 $command = 'new';
531 // Page id of this new record
532 $theUid = $this->controller->id;
533 if ($neighborRecordUid) {
534 $theUid = $neighborRecordUid;
535 }
536 } else {
537 $command = 'edit';
538 $theUid = $uidVal;
539 // Convert $uidVal to workspace version if any:
540 $draftRecord = BackendUtility::getWorkspaceVersionOfRecord($beUser->workspace, $tableName, $theUid, 'uid');
541 if ($draftRecord) {
542 $theUid = $draftRecord['uid'];
543 }
544 }
545
546 // @todo: Hack because DatabaseInitializeNewRow reads from _GP directly
547 $GLOBALS['_GET']['defVals'][$tableName] = [
548 'colPos' => (int)$ex_colPos,
549 'sys_language_uid' => (int)$this->controller->current_sys_language
550 ];
551
552 /** @var TcaDatabaseRecord $formDataGroup */
553 $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
554 /** @var FormDataCompiler $formDataCompiler */
555 $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
556 /** @var NodeFactory $nodeFactory */
557 $nodeFactory = GeneralUtility::makeInstance(NodeFactory::class);
558
559 try {
560 $formDataCompilerInput = [
561 'tableName' => $tableName,
562 'vanillaUid' => (int)$theUid,
563 'command' => $command,
564 ];
565 $formData = $formDataCompiler->compile($formDataCompilerInput);
566
567 if ($command !== 'new') {
568 BackendUtility::lockRecords($tableName, $formData['databaseRow']['uid'], $tableName === 'tt_content' ? $formData['databaseRow']['pid'] : 0);
569 }
570
571 $formData['renderType'] = 'outerWrapContainer';
572 $formResult = $nodeFactory->create($formData)->render();
573
574 $panel = $formResult['html'];
575 $formResult['html'] = '';
576
577 /** @var FormResultCompiler $formResultCompiler */
578 $formResultCompiler = GeneralUtility::makeInstance(FormResultCompiler::class);
579 $formResultCompiler->mergeResult($formResult);
580
581 $row = $formData['databaseRow'];
582 $new_unique_uid = '';
583 if ($command === 'new') {
584 $new_unique_uid = $row['uid'];
585 }
586
587 // Add hidden fields:
588 if ($uidVal == 'new') {
589 $panel .= '<input type="hidden" name="data[' . $tableName . '][' . $row['uid'] . '][pid]" value="' . $row['pid'] . '" />';
590 }
591 $redirect = ($uidVal == 'new' ? BackendUtility::getModuleUrl(
592 $this->moduleName,
593 ['id' => $this->controller->id, 'new_unique_uid' => $new_unique_uid, 'returnUrl' => $this->returnUrl]
594 ) : $this->R_URI);
595 $panel .= '
596 <input type="hidden" name="_serialNumber" value="' . md5(microtime()) . '" />
597 <input type="hidden" name="edit_record" value="' . $edit_record . '" />
598 <input type="hidden" name="redirect" value="' . htmlspecialchars($redirect) . '" />
599 ';
600 // Add JavaScript as needed around the form:
601 $content = $formResultCompiler->addCssFiles() . $panel . $formResultCompiler->printNeededJSFunctions();
602
603 // Display "is-locked" message:
604 if ($command === 'edit') {
605 $lockInfo = BackendUtility::isRecordLocked($tableName, $formData['databaseRow']['uid']);
606 if ($lockInfo) {
607 /** @var \TYPO3\CMS\Core\Messaging\FlashMessage $flashMessage */
608 $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $lockInfo['msg'], '', FlashMessage::WARNING);
609 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
610 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
611 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
612 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
613 $defaultFlashMessageQueue->enqueue($flashMessage);
614 }
615 }
616 } catch (AccessDeniedException $e) {
617 // If no edit access, print error message:
618 $content = '<h2>' . htmlspecialchars($lang->getLL('noAccess')) . '</h2>';
619 $content .= '<div>' . $lang->getLL('noAccess_msg') . '<br /><br />' . ($beUser->errorMsg ? 'Reason: ' . $beUser->errorMsg . '<br /><br />' : '') . '</div>';
620 }
621 } else {
622 // If no edit access, print error message:
623 $content = '<h2>' . $lang->getLL('noAccess') . '</h2>';
624 $content .= '<div>' . $lang->getLL('noAccess_msg') . '</div>';
625 }
626
627 // Element selection matrix:
628 if ($tableName === 'tt_content' && MathUtility::canBeInterpretedAsInteger($this->eRParts[1])) {
629 $content .= '<h2>' . $lang->getLL('CEonThisPage') . '</h2>';
630 // PositionMap
631 $posMap = GeneralUtility::makeInstance(ContentLayoutPagePositionMap::class);
632 $posMap->cur_sys_language = $this->controller->current_sys_language;
633 $content .= $posMap->printContentElementColumns(
634 $this->controller->id,
635 $this->eRParts[1],
636 $this->controller->colPosList,
637 $this->controller->MOD_SETTINGS['tt_content_showHidden'],
638 $this->R_URI
639 );
640 // Toggle hidden ContentElements
641 $numberOfHiddenElements = $this->controller->getNumberOfHiddenElements();
642 if ($numberOfHiddenElements) {
643 $content .= '<div class="checkbox">';
644 $content .= '<label for="checkTt_content_showHidden">';
645 $content .= BackendUtility::getFuncCheck($this->controller->id, 'SET[tt_content_showHidden]', $this->controller->MOD_SETTINGS['tt_content_showHidden'], '', '', 'id="checkTt_content_showHidden"');
646 $content .= (!$numberOfHiddenElements ? ('<span class="text-muted">' . htmlspecialchars($lang->getLL('hiddenCE')) . '</span>') : htmlspecialchars($lang->getLL('hiddenCE')) . ' (' . $numberOfHiddenElements . ')');
647 $content .= '</label>';
648 $content .= '</div>';
649 }
650 // CSH
651 $content .= BackendUtility::cshItem($this->descrTable, 'quickEdit_selElement', null, '<span class="btn btn-default btn-sm">|</span>');
652 }
653
654 $content = '<form action="' .
655 htmlspecialchars(BackendUtility::getModuleUrl('tce_db', ['prErr' => 1, 'uPT' => 1])) .
656 '" method="post" enctype="multipart/form-data" name="editform" id="PageLayoutController" onsubmit="return TBE_EDITOR.checkSubmit(1);">' .
657 $content .
658 '</form>';
659
660 return $content;
661 }
662
663 /**
664 * Returns LanguageService
665 *
666 * @return \TYPO3\CMS\Lang\LanguageService
667 */
668 protected function getLanguageService()
669 {
670 return $GLOBALS['LANG'];
671 }
672
673 /**
674 * Returns the current BE user.
675 *
676 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
677 */
678 protected function getBackendUser()
679 {
680 return $GLOBALS['BE_USER'];
681 }
682 }