[FOLLOWUP][BUGFIX] Fix evaluation of rootLevel configuration in NewRecordController
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / NewRecordController.php
1 <?php
2 namespace TYPO3\CMS\Backend\Controller;
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 Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Module\AbstractModule;
20 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
21 use TYPO3\CMS\Backend\Tree\View\NewRecordPageTreeView;
22 use TYPO3\CMS\Backend\Tree\View\PagePositionMap;
23 use TYPO3\CMS\Backend\Utility\BackendUtility;
24 use TYPO3\CMS\Core\Database\DatabaseConnection;
25 use TYPO3\CMS\Core\Imaging\Icon;
26 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28 use TYPO3\CMS\Core\Utility\HttpUtility;
29 use TYPO3\CMS\Frontend\Page\PageRepository;
30
31 /**
32 * Script class for 'db_new'
33 */
34 class NewRecordController extends AbstractModule
35 {
36 /**
37 * @var array
38 */
39 public $pageinfo;
40
41 /**
42 * @var array
43 */
44 public $pidInfo;
45
46 /**
47 * @var array
48 */
49 protected $newRecordSortList;
50
51 /**
52 * @var int
53 */
54 public $newPagesInto;
55
56 /**
57 * @var int
58 */
59 public $newContentInto;
60
61 /**
62 * @var int
63 */
64 public $newPagesAfter;
65
66 /**
67 * Determines, whether "Select Position" for new page should be shown
68 *
69 * @var bool
70 */
71 protected $newPagesSelectPosition = true;
72
73 /**
74 * @var array
75 */
76 public $web_list_modTSconfig;
77
78 /**
79 * @var array
80 */
81 public $allowedNewTables;
82
83 /**
84 * @var array
85 */
86 public $deniedNewTables;
87
88 /**
89 * @var array
90 */
91 public $web_list_modTSconfig_pid;
92
93 /**
94 * @var array
95 */
96 public $allowedNewTables_pid;
97
98 /**
99 * @var array
100 */
101 public $deniedNewTables_pid;
102
103 /**
104 * @var string
105 */
106 public $code;
107
108 /**
109 * @var string
110 */
111 public $R_URI;
112
113 /**
114 * @var int
115 */
116 public $id;
117
118 /**
119 * @var string
120 */
121 public $returnUrl;
122
123 /**
124 * pagesOnly flag.
125 *
126 * @var int
127 */
128 public $pagesOnly;
129
130 /**
131 * @var string
132 */
133 public $perms_clause;
134
135 /**
136 * Accumulated HTML output
137 *
138 * @var string
139 */
140 public $content;
141
142 /**
143 * @var array
144 */
145 public $tRows;
146
147 /**
148 * Constructor
149 */
150 public function __construct()
151 {
152 parent::__construct();
153 $GLOBALS['SOBE'] = $this;
154 $this->getLanguageService()->includeLLFile('EXT:lang/locallang_misc.xlf');
155 $this->init();
156 }
157
158 /**
159 * Constructor function for the class
160 *
161 * @return void
162 */
163 protected function init()
164 {
165 $beUser = $this->getBackendUserAuthentication();
166 // Page-selection permission clause (reading)
167 $this->perms_clause = $beUser->getPagePermsClause(1);
168 // This will hide records from display - it has nothing to do with user rights!!
169 if ($pidList = $beUser->getTSConfigVal('options.hideRecords.pages')) {
170 if ($pidList = $this->getDatabaseConnection()->cleanIntList($pidList)) {
171 $this->perms_clause .= ' AND pages.uid NOT IN (' . $pidList . ')';
172 }
173 }
174 // Setting GPvars:
175 // The page id to operate from
176 $this->id = (int)GeneralUtility::_GP('id');
177 $this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
178 $this->pagesOnly = GeneralUtility::_GP('pagesOnly');
179 // Setting up the context sensitive menu:
180 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
181 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Tooltip');
182 // Creating content
183 $this->content = '';
184 $this->content .= '<h1>'
185 . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:db_new.php.pagetitle')
186 . '</h1>';
187 // Id a positive id is supplied, ask for the page record with permission information contained:
188 if ($this->id > 0) {
189 $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
190 }
191 // If a page-record was returned, the user had read-access to the page.
192 if ($this->pageinfo['uid']) {
193 // Get record of parent page
194 $this->pidInfo = BackendUtility::getRecord('pages', $this->pageinfo['pid']);
195 // Checking the permissions for the user with regard to the parent page: Can he create new pages, new
196 // content record, new page after?
197 if ($beUser->doesUserHaveAccess($this->pageinfo, 8)) {
198 $this->newPagesInto = 1;
199 }
200 if ($beUser->doesUserHaveAccess($this->pageinfo, 16)) {
201 $this->newContentInto = 1;
202 }
203 if (($beUser->isAdmin() || is_array($this->pidInfo)) && $beUser->doesUserHaveAccess($this->pidInfo, 8)) {
204 $this->newPagesAfter = 1;
205 }
206 } elseif ($beUser->isAdmin()) {
207 // Admins can do it all
208 $this->newPagesInto = 1;
209 $this->newContentInto = 1;
210 $this->newPagesAfter = 0;
211 } else {
212 // People with no permission can do nothing
213 $this->newPagesInto = 0;
214 $this->newContentInto = 0;
215 $this->newPagesAfter = 0;
216 }
217 }
218
219 /**
220 * Injects the request object for the current request or subrequest
221 * As this controller goes only through the main() method, it is rather simple for now
222 *
223 * @param ServerRequestInterface $request the current request
224 * @param ResponseInterface $response
225 * @return ResponseInterface the response with the content
226 */
227 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
228 {
229 $this->main();
230
231 $response->getBody()->write($this->moduleTemplate->renderContent());
232 return $response;
233 }
234
235 /**
236 * Main processing, creating the list of new record tables to select from
237 *
238 * @return void
239 */
240 public function main()
241 {
242 // If there was a page - or if the user is admin (admins has access to the root) we proceed:
243 if (!empty($this->pageinfo['uid']) || $this->getBackendUserAuthentication()->isAdmin()) {
244 if (empty($this->pageinfo)) {
245 // Explicitly pass an empty array to the docHeader
246 $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation([]);
247 } else {
248 $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($this->pageinfo);
249 }
250 // Acquiring TSconfig for this module/current page:
251 $this->web_list_modTSconfig = BackendUtility::getModTSconfig($this->pageinfo['uid'], 'mod.web_list');
252 $this->allowedNewTables = GeneralUtility::trimExplode(
253 ',',
254 $this->web_list_modTSconfig['properties']['allowedNewTables'],
255 true
256 );
257 $this->deniedNewTables = GeneralUtility::trimExplode(
258 ',',
259 $this->web_list_modTSconfig['properties']['deniedNewTables'],
260 true
261 );
262 // Acquiring TSconfig for this module/parent page:
263 $this->web_list_modTSconfig_pid = BackendUtility::getModTSconfig($this->pageinfo['pid'], 'mod.web_list');
264 $this->allowedNewTables_pid = GeneralUtility::trimExplode(
265 ',',
266 $this->web_list_modTSconfig_pid['properties']['allowedNewTables'],
267 true
268 );
269 $this->deniedNewTables_pid = GeneralUtility::trimExplode(
270 ',',
271 $this->web_list_modTSconfig_pid['properties']['deniedNewTables'],
272 true
273 );
274 // More init:
275 if (!$this->showNewRecLink('pages')) {
276 $this->newPagesInto = 0;
277 }
278 if (!$this->showNewRecLink('pages', $this->allowedNewTables_pid, $this->deniedNewTables_pid)) {
279 $this->newPagesAfter = 0;
280 }
281 // Set header-HTML and return_url
282 if (is_array($this->pageinfo) && $this->pageinfo['uid']) {
283 $title = strip_tags($this->pageinfo[$GLOBALS['TCA']['pages']['ctrl']['label']]);
284 } else {
285 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
286 }
287 $this->moduleTemplate->setTitle($title);
288 // GENERATE the HTML-output depending on mode (pagesOnly is the page wizard)
289 // Regular new element:
290 if (!$this->pagesOnly) {
291 $this->regularNew();
292 } elseif ($this->showNewRecLink('pages')) {
293 // Pages only wizard
294 $this->pagesOnly();
295 }
296 // Add all the content to an output section
297 $this->content .= '<div>' . $this->code . '</div>';
298 // Setting up the buttons and markers for docheader
299 $this->getButtons();
300 // Build the <body> for the module
301 $this->moduleTemplate->setContent($this->content);
302 }
303 }
304
305 /**
306 * Create the panel of buttons for submitting the form or otherwise perform operations.
307 */
308 protected function getButtons()
309 {
310 $lang = $this->getLanguageService();
311 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
312 // Regular new element:
313 if (!$this->pagesOnly) {
314 // New page
315 if ($this->showNewRecLink('pages')) {
316 $newPageButton = $buttonBar->makeLinkButton()
317 ->setHref(GeneralUtility::linkThisScript(['pagesOnly' => '1']))
318 ->setTitle($lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:newPage'))
319 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-page-new', Icon::SIZE_SMALL));
320 $buttonBar->addButton($newPageButton, ButtonBar::BUTTON_POSITION_LEFT, 20);
321 }
322 // CSH
323 $cshButton = $buttonBar->makeHelpButton()->setModuleName('xMOD_csh_corebe')->setFieldName('new_regular');
324 $buttonBar->addButton($cshButton);
325 } elseif ($this->showNewRecLink('pages')) {
326 // Pages only wizard
327 // CSH
328 $buttons['csh'] = BackendUtility::cshItem('xMOD_csh_corebe', 'new_pages');
329 $cshButton = $buttonBar->makeHelpButton()->setModuleName('xMOD_csh_corebe')->setFieldName('new_pages');
330 $buttonBar->addButton($cshButton);
331 }
332 // Back
333 if ($this->returnUrl) {
334 $returnButton = $buttonBar->makeLinkButton()
335 ->setHref($this->returnUrl)
336 ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.goBack'))
337 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
338 $buttonBar->addButton($returnButton, ButtonBar::BUTTON_POSITION_LEFT, 10);
339 }
340
341 if (is_array($this->pageinfo) && $this->pageinfo['uid']) {
342 // View
343 $pagesTSconfig = BackendUtility::getPagesTSconfig($this->pageinfo['uid']);
344 if (isset($pagesTSconfig['TCEMAIN.']['preview.']['disableButtonForDokType'])) {
345 $excludeDokTypes = GeneralUtility::intExplode(
346 ',',
347 $pagesTSconfig['TCEMAIN.']['preview.']['disableButtonForDokType'],
348 true
349 );
350 } else {
351 // exclude sysfolders and recycler by default
352 $excludeDokTypes = [
353 PageRepository::DOKTYPE_RECYCLER,
354 PageRepository::DOKTYPE_SYSFOLDER,
355 PageRepository::DOKTYPE_SPACER
356 ];
357 }
358 if (!in_array((int)$this->pageinfo['doktype'], $excludeDokTypes, true)) {
359 $viewButton = $buttonBar->makeLinkButton()
360 ->setHref('#')
361 ->setOnClick(BackendUtility::viewOnClick(
362 $this->pageinfo['uid'],
363 '',
364 BackendUtility::BEgetRootLine($this->pageinfo['uid'])
365 ))
366 ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage'))
367 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
368 'actions-document-view',
369 Icon::SIZE_SMALL
370 ));
371 $buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, 30);
372 }
373 }
374 }
375
376 /**
377 * Creates the position map for pages wizard
378 *
379 * @return void
380 */
381 public function pagesOnly()
382 {
383 $numberOfPages = $this->getDatabaseConnection()->exec_SELECTcountRows(
384 '*',
385 'pages',
386 '1=1' . BackendUtility::deleteClause('pages')
387 );
388 if ($numberOfPages > 0) {
389 $this->code .= '
390 <h3>' . htmlspecialchars($this->getLanguageService()->getLL('selectPosition')) . ':</h3>
391 ';
392 $positionMap = GeneralUtility::makeInstance(PagePositionMap::class, NewRecordPageTreeView::class);
393 /** @var $positionMap \TYPO3\CMS\Backend\Tree\View\PagePositionMap */
394 $this->code .= $positionMap->positionTree(
395 $this->id,
396 $this->pageinfo,
397 $this->perms_clause,
398 $this->returnUrl
399 );
400 } else {
401 // No pages yet, no need to prompt for position, redirect to page creation.
402 $urlParameters = [
403 'edit' => [
404 'pages' => [
405 0 => 'new'
406 ]
407 ],
408 'returnNewPageId' => 1,
409 'returnUrl' => BackendUtility::getModuleUrl('db_new', ['id' => $this->id, 'pagesOnly' => '1'])
410 ];
411 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
412 @ob_end_clean();
413 HttpUtility::redirect($url);
414 }
415 }
416
417 /**
418 * Create a regular new element (pages and records)
419 *
420 * @return void
421 */
422 public function regularNew()
423 {
424 $lang = $this->getLanguageService();
425 // Initialize array for accumulating table rows:
426 $this->tRows = [];
427 // Get TSconfig for current page
428 $pageTS = BackendUtility::getPagesTSconfig($this->id);
429 // Finish initializing new pages options with TSconfig
430 // Each new page option may be hidden by TSconfig
431 // Enabled option for the position of a new page
432 $this->newPagesSelectPosition = !empty(
433 $pageTS['mod.']['wizards.']['newRecord.']['pages.']['show.']['pageSelectPosition']
434 );
435 // Pseudo-boolean (0/1) for backward compatibility
436 $displayNewPagesIntoLink = $this->newPagesInto && !empty($pageTS['mod.']['wizards.']['newRecord.']['pages.']['show.']['pageInside']) ? 1 : 0;
437 $displayNewPagesAfterLink = $this->newPagesAfter && !empty($pageTS['mod.']['wizards.']['newRecord.']['pages.']['show.']['pageAfter']) ? 1 : 0;
438 // Slight spacer from header:
439 $this->code .= '';
440 // New Page
441 $table = 'pages';
442 $v = $GLOBALS['TCA'][$table];
443 $pageIcon = $this->moduleTemplate->getIconFactory()->getIconForRecord(
444 $table,
445 [],
446 Icon::SIZE_SMALL
447 )->render();
448 $newPageIcon = $this->moduleTemplate->getIconFactory()->getIcon('actions-page-new', Icon::SIZE_SMALL)->render();
449 $rowContent = '';
450 // New pages INSIDE this pages
451 $newPageLinks = [];
452 if ($displayNewPagesIntoLink && $this->isTableAllowedForThisPage($this->pageinfo, 'pages') && $this->getBackendUserAuthentication()->check('tables_modify', 'pages') && $this->getBackendUserAuthentication()->workspaceCreateNewRecord(($this->pageinfo['_ORIG_uid'] ?: $this->id), 'pages')) {
453 // Create link to new page inside:
454 $newPageLinks[] = $this->linkWrap($this->moduleTemplate->getIconFactory()->getIconForRecord($table, [], Icon::SIZE_SMALL)->render() . $lang->sL($v['ctrl']['title'], true) . ' (' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:db_new.php.inside', true) . ')', $table, $this->id);
455 }
456 // New pages AFTER this pages
457 if ($displayNewPagesAfterLink && $this->isTableAllowedForThisPage($this->pidInfo, 'pages') && $this->getBackendUserAuthentication()->check('tables_modify', 'pages') && $this->getBackendUserAuthentication()->workspaceCreateNewRecord($this->pidInfo['uid'], 'pages')) {
458 $newPageLinks[] = $this->linkWrap($pageIcon . $lang->sL($v['ctrl']['title'], true) . ' (' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:db_new.php.after', true) . ')', 'pages', -$this->id);
459 }
460 // New pages at selection position
461 if ($this->newPagesSelectPosition && $this->showNewRecLink('pages')) {
462 // Link to page-wizard:
463 $newPageLinks[] = '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(['pagesOnly' => 1])) . '">' . $pageIcon . htmlspecialchars($lang->getLL('pageSelectPosition')) . '</a>';
464 }
465 // Assemble all new page links
466 $numPageLinks = count($newPageLinks);
467 for ($i = 0; $i < $numPageLinks; $i++) {
468 $rowContent .= '<li>' . $newPageLinks[$i] . '</li>';
469 }
470 if ($this->showNewRecLink('pages')) {
471 $rowContent = '<ul class="list-tree"><li>' . $newPageIcon . '<strong>' .
472 $lang->getLL('createNewPage') . '</strong><ul>' . $rowContent . '</ul></li>';
473 } else {
474 $rowContent = '<ul class="list-tree"><li><ul>' . $rowContent . '</li></ul>';
475 }
476 // Compile table row
477 $startRows = [$rowContent];
478 $iconFile = [];
479 // New tables (but not pages) INSIDE this pages
480 $isAdmin = $this->getBackendUserAuthentication()->isAdmin();
481 $newContentIcon = $this->moduleTemplate->getIconFactory()->getIcon('actions-document-new', Icon::SIZE_SMALL)->render();
482 if ($this->newContentInto) {
483 if (is_array($GLOBALS['TCA'])) {
484 $groupName = '';
485 foreach ($GLOBALS['TCA'] as $table => $v) {
486 $rootLevelConfiguration = isset($v['ctrl']['rootLevel']) ? (int)$v['ctrl']['rootLevel'] : 0;
487 if ($table != 'pages'
488 && $this->showNewRecLink($table)
489 && $this->isTableAllowedForThisPage($this->pageinfo, $table)
490 && $this->getBackendUserAuthentication()->check('tables_modify', $table)
491 && ($rootLevelConfiguration === -1 || ($this->id xor $rootLevelConfiguration))
492 && $this->getBackendUserAuthentication()->workspaceCreateNewRecord(($this->pageinfo['_ORIG_uid'] ? $this->pageinfo['_ORIG_uid'] : $this->id), $table)
493 ) {
494 $newRecordIcon = $this->moduleTemplate->getIconFactory()->getIconForRecord($table, [], Icon::SIZE_SMALL)->render();
495 $rowContent = '';
496 $thisTitle = '';
497 // Create new link for record:
498 $newLink = $this->linkWrap($newRecordIcon . $lang->sL($v['ctrl']['title'], true), $table, $this->id);
499 // If the table is 'tt_content', create link to wizard
500 if ($table == 'tt_content') {
501 $groupName = $lang->getLL('createNewContent');
502 $rowContent = $newContentIcon . '<strong>' . $lang->getLL('createNewContent') . '</strong><ul>';
503 // If mod.newContentElementWizard.override is set, use that extension's wizard instead:
504 $tsConfig = BackendUtility::getModTSconfig($this->id, 'mod');
505 $moduleName = isset($tsConfig['properties']['newContentElementWizard.']['override'])
506 ? $tsConfig['properties']['newContentElementWizard.']['override']
507 : 'new_content_element';
508 $url = BackendUtility::getModuleUrl($moduleName, ['id' => $this->id, 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')]);
509 $rowContent .= '<li>' . $newLink . ' ' . BackendUtility::wrapInHelp($table, '') . '</li><li><a href="' . htmlspecialchars($url) . '">' . $newContentIcon . htmlspecialchars($lang->getLL('clickForWizard')) . '</a></li></ul>';
510 } else {
511 // Get the title
512 if ($v['ctrl']['readOnly'] || $v['ctrl']['hideTable'] || $v['ctrl']['is_static']) {
513 continue;
514 }
515 if ($v['ctrl']['adminOnly'] && !$isAdmin) {
516 continue;
517 }
518 $nameParts = explode('_', $table);
519 $thisTitle = '';
520 $_EXTKEY = '';
521 if ($nameParts[0] == 'tx' || $nameParts[0] == 'tt') {
522 // Try to extract extension name
523 if (substr($v['ctrl']['title'], 0, 8) == 'LLL:EXT:') {
524 $_EXTKEY = substr($v['ctrl']['title'], 8);
525 $_EXTKEY = substr($_EXTKEY, 0, strpos($_EXTKEY, '/'));
526 if ($_EXTKEY != '') {
527 // First try to get localisation of extension title
528 $temp = explode(':', substr($v['ctrl']['title'], 9 + strlen($_EXTKEY)));
529 $langFile = $temp[0];
530 $thisTitle = $lang->sL('LLL:EXT:' . $_EXTKEY . '/' . $langFile . ':extension.title');
531 // If no localisation available, read title from ext_emconf.php
532 $extEmConfFile = ExtensionManagementUtility::extPath($_EXTKEY) . 'ext_emconf.php';
533 if (!$thisTitle && is_file($extEmConfFile)) {
534 $EM_CONF = [];
535 include $extEmConfFile;
536 $thisTitle = $EM_CONF[$_EXTKEY]['title'];
537 }
538 $iconFile[$_EXTKEY] = '<img ' . 'src="' . ExtensionManagementUtility::extRelPath($_EXTKEY) . $GLOBALS['TYPO3_LOADED_EXT'][$_EXTKEY]['ext_icon'] . '" ' . 'width="16" height="16" ' . 'alt="' . $thisTitle . '" />';
539 }
540 }
541 if (empty($thisTitle)) {
542 $_EXTKEY = $nameParts[1];
543 $thisTitle = $nameParts[1];
544 $iconFile[$_EXTKEY] = '';
545 }
546 } else {
547 if ($table === 'pages_language_overlay' && !$this->checkIfLanguagesExist()) {
548 continue;
549 }
550 $_EXTKEY = 'system';
551 $thisTitle = $lang->getLL('system_records');
552 $iconFile['system'] = $this->moduleTemplate->getIconFactory()->getIcon('apps-pagetree-root', Icon::SIZE_SMALL)->render();
553 }
554 if ($groupName == '' || $groupName != $_EXTKEY) {
555 $groupName = empty($v['ctrl']['groupName']) ? $_EXTKEY : $v['ctrl']['groupName'];
556 }
557 $rowContent .= $newLink;
558 }
559 // Compile table row:
560 if ($table == 'tt_content') {
561 $startRows[] = '<li>' . $rowContent . '</li>';
562 } else {
563 $this->tRows[$groupName]['title'] = $thisTitle;
564 $this->tRows[$groupName]['html'][] = $rowContent;
565 $this->tRows[$groupName]['table'][] = $table;
566 }
567 }
568 }
569 }
570 }
571 // User sort
572 if (isset($pageTS['mod.']['wizards.']['newRecord.']['order'])) {
573 $this->newRecordSortList = GeneralUtility::trimExplode(',', $pageTS['mod.']['wizards.']['newRecord.']['order'], true);
574 }
575 uksort($this->tRows, [$this, 'sortNewRecordsByConfig']);
576 // Compile table row:
577 $finalRows = [];
578 $finalRows[] = implode('', $startRows);
579 foreach ($this->tRows as $key => $value) {
580 $row = '<li>' . $iconFile[$key] . ' <strong>' . $value['title'] . '</strong><ul>';
581 foreach ($value['html'] as $recordKey => $record) {
582 $row .= '<li>' . $record . ' ' . BackendUtility::wrapInHelp($value['table'][$recordKey], '') . '</li>';
583 }
584 $row .= '</ul></li>';
585 $finalRows[] = $row;
586 }
587
588 $finalRows[] = '</ul>';
589 // Make table:
590 $this->code .= implode('', $finalRows);
591 }
592
593 /**
594 * User array sort function used by regularNew
595 *
596 * @param string $a First array element for compare
597 * @param string $b First array element for compare
598 * @return int -1 for lower, 0 for equal, 1 for greater
599 */
600 public function sortNewRecordsByConfig($a, $b)
601 {
602 if (!empty($this->newRecordSortList)) {
603 if (in_array($a, $this->newRecordSortList) && in_array($b, $this->newRecordSortList)) {
604 // Both are in the list, return relative to position in array
605 $sub = array_search($a, $this->newRecordSortList) - array_search($b, $this->newRecordSortList);
606 $ret = ($sub < 0 ? -1 : $sub == 0) ? 0 : 1;
607 } elseif (in_array($a, $this->newRecordSortList)) {
608 // First element is in array, put to top
609 $ret = -1;
610 } elseif (in_array($b, $this->newRecordSortList)) {
611 // Second element is in array, put first to bottom
612 $ret = 1;
613 } else {
614 // No element is in array, return alphabetic order
615 $ret = strnatcasecmp($this->tRows[$a]['title'], $this->tRows[$b]['title']);
616 }
617 return $ret;
618 } else {
619 // Return alphabetic order
620 return strnatcasecmp($this->tRows[$a]['title'], $this->tRows[$b]['title']);
621 }
622 }
623
624 /**
625 * Ending page output and echo'ing content to browser.
626 *
627 * @return void
628 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use mainAction() instead
629 */
630 public function printContent()
631 {
632 GeneralUtility::logDeprecatedFunction();
633 echo $this->content;
634 }
635
636 /**
637 * Links the string $code to a create-new form for a record in $table created on page $pid
638 *
639 * @param string $linkText Link text
640 * @param string $table Table name (in which to create new record)
641 * @param int $pid PID value for the "&edit['.$table.']['.$pid.']=new" command (positive/negative)
642 * @param bool $addContentTable If $addContentTable is set, then a new tt_content record is created together with pages
643 * @return string The link.
644 */
645 public function linkWrap($linkText, $table, $pid, $addContentTable = false)
646 {
647 $urlParameters = [
648 'edit' => [
649 $table => [
650 $pid => 'new'
651 ]
652 ],
653 'returnUrl' => $this->returnUrl
654 ];
655 if ($table == 'pages' && $addContentTable) {
656 $urlParameters['tt_content']['prev'] = 'new';
657 $urlParameters['returnNewPageId'] = 1;
658 } elseif ($table == 'pages_language_overlay') {
659 $urlParameters['overrideVals']['pages_language_overlay']['doktype'] = (int)$this->pageinfo['doktype'];
660 }
661 $url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
662 return '<a href="' . htmlspecialchars($url) . '">' . $linkText . '</a>';
663 }
664
665 /**
666 * Returns TRUE if the tablename $checkTable is allowed to be created on the page with record $pid_row
667 *
668 * @param array $pid_row Record for parent page.
669 * @param string $checkTable Table name to check
670 * @return bool Returns TRUE if the tablename $checkTable is allowed to be created on the page with record $pid_row
671 */
672 public function isTableAllowedForThisPage($pid_row, $checkTable)
673 {
674 if (!is_array($pid_row)) {
675 return $this->getBackendUserAuthentication()->isAdmin();
676 }
677 // be_users and be_groups may not be created anywhere but in the root.
678 if ($checkTable == 'be_users' || $checkTable == 'be_groups') {
679 return false;
680 }
681 // Checking doktype:
682 $doktype = (int)$pid_row['doktype'];
683 if (!($allowedTableList = $GLOBALS['PAGES_TYPES'][$doktype]['allowedTables'])) {
684 $allowedTableList = $GLOBALS['PAGES_TYPES']['default']['allowedTables'];
685 }
686 // If all tables or the table is listed as an allowed type, return TRUE
687 if (strstr($allowedTableList, '*') || GeneralUtility::inList($allowedTableList, $checkTable)) {
688 return true;
689 }
690
691 return false;
692 }
693
694 /**
695 * Returns TRUE if:
696 * - $allowedNewTables and $deniedNewTables are empty
697 * - the table is not found in $deniedNewTables and $allowedNewTables is not set or the $table tablename is found in
698 * $allowedNewTables
699 *
700 * If $table tablename is found in $allowedNewTables and $deniedNewTables, $deniedNewTables
701 * has priority over $allowedNewTables.
702 *
703 * @param string $table Table name to test if in allowedTables
704 * @param array $allowedNewTables Array of new tables that are allowed.
705 * @param array $deniedNewTables Array of new tables that are not allowed.
706 *
707 * @return bool Returns TRUE if a link for creating new records should be displayed for $table
708 */
709 public function showNewRecLink($table, array $allowedNewTables = [], array $deniedNewTables = [])
710 {
711 if (!$this->getBackendUserAuthentication()->check('tables_modify', $table)) {
712 return false;
713 }
714
715 $allowedNewTables = $allowedNewTables ?: $this->allowedNewTables;
716 $deniedNewTables = $deniedNewTables ?: $this->deniedNewTables;
717 // No deny/allow tables are set:
718 if (empty($allowedNewTables) && empty($deniedNewTables)) {
719 return true;
720 }
721
722 return !in_array($table, $deniedNewTables) && (empty($allowedNewTables) || in_array($table, $allowedNewTables));
723 }
724
725 /**
726 * Checks if sys_language records are present
727 *
728 * @return bool
729 */
730 protected function checkIfLanguagesExist()
731 {
732 $languageCount = $this->getDatabaseConnection()->exec_SELECTcountRows('uid', 'sys_language', '1=1');
733 if ($languageCount) {
734 $languageCount = true;
735 }
736 return $languageCount;
737 }
738
739 /**
740 * Return language service instance
741 *
742 * @return \TYPO3\CMS\Lang\LanguageService
743 */
744 protected function getLanguageService()
745 {
746 return $GLOBALS['LANG'];
747 }
748
749 /**
750 * Returns the global BackendUserAuthentication object.
751 *
752 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
753 */
754 protected function getBackendUserAuthentication()
755 {
756 return $GLOBALS['BE_USER'];
757 }
758
759 /**
760 * Returns the database connection
761 *
762 * @return DatabaseConnection
763 */
764 protected function getDatabaseConnection()
765 {
766 return $GLOBALS['TYPO3_DB'];
767 }
768 }