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