NewRecordController.php 26.5 KB
Newer Older
1
2
3
<?php
namespace TYPO3\CMS\Backend\Controller;

4
/*
5
 * This file is part of the TYPO3 CMS project.
6
 *
7
8
9
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
10
 *
11
12
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
13
 *
14
15
 * The TYPO3 project - inspiring people to share!
 */
16

17
18
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
Nicole Cordes's avatar
Nicole Cordes committed
19
use TYPO3\CMS\Backend\Utility\BackendUtility;
20
use TYPO3\CMS\Core\Database\DatabaseConnection;
21
22
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
Nicole Cordes's avatar
Nicole Cordes committed
23
24
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
25
26
27
28
use TYPO3\CMS\Backend\Template\DocumentTemplate;
use TYPO3\CMS\Backend\Tree\View\PagePositionMap;
use TYPO3\CMS\Backend\Tree\View\NewRecordPageTreeView;
use TYPO3\CMS\Core\Utility\HttpUtility;
29
30
use TYPO3\CMS\Frontend\Page\PageRepository;

Nicole Cordes's avatar
Nicole Cordes committed
31

32
33
34
/**
 * Script class for 'db_new'
 */
35
class NewRecordController {
36
37

	/**
38
	 * @var array
39
40
41
42
	 */
	public $pageinfo;

	/**
43
	 * @var array
44
45
46
	 */
	public $pidInfo;

47
48
49
50
51
	/**
	 * @var array
	 */
	protected $newRecordSortList;

52
	/**
53
	 * @var int
54
55
56
57
	 */
	public $newPagesInto;

	/**
58
	 * @var int
59
60
61
62
	 */
	public $newContentInto;

	/**
63
	 * @var int
64
65
66
67
68
69
	 */
	public $newPagesAfter;

	/**
	 * Determines, whether "Select Position" for new page should be shown
	 *
70
	 * @var bool
71
72
73
74
	 */
	protected $newPagesSelectPosition = TRUE;

	/**
75
	 * @var array
76
77
78
79
	 */
	public $web_list_modTSconfig;

	/**
80
	 * @var array
81
82
83
84
	 */
	public $allowedNewTables;

	/**
85
	 * @var array
86
87
88
89
	 */
	public $deniedNewTables;

	/**
90
	 * @var array
91
92
93
94
	 */
	public $web_list_modTSconfig_pid;

	/**
95
	 * @var array
96
97
98
99
	 */
	public $allowedNewTables_pid;

	/**
100
	 * @var array
101
102
103
104
	 */
	public $deniedNewTables_pid;

	/**
105
	 * @var string
106
107
108
109
	 */
	public $code;

	/**
110
	 * @var string
111
112
113
114
	 */
	public $R_URI;

	/**
115
	 * @var int
116
117
118
119
	 */
	public $id;

	/**
120
	 * @var string
121
122
123
124
	 */
	public $returnUrl;

	/**
125
126
	 * pagesOnly flag.
	 *
127
	 * @var int
128
129
130
131
	 */
	public $pagesOnly;

	/**
132
	 * @var string
133
134
135
136
137
138
	 */
	public $perms_clause;

	/**
	 * Document template object
	 *
139
	 * @var \TYPO3\CMS\Backend\Template\DocumentTemplate
140
141
142
143
	 */
	public $doc;

	/**
144
145
	 * Accumulated HTML output
	 *
146
	 * @var string
147
148
149
150
	 */
	public $content;

	/**
151
	 * @var array
152
153
154
	 */
	public $tRows;

155
156
157
158
159
	/**
	 * @var IconFactory
	 */
	protected $iconFactory;

160
161
162
163
	/**
	 * Constructor
	 */
	public function __construct() {
164
		$this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
165
		$GLOBALS['SOBE'] = $this;
166
		$this->getLanguageService()->includeLLFile('EXT:lang/locallang_misc.xlf');
167
168
169
		$this->init();
	}

170
171
172
173
174
	/**
	 * Constructor function for the class
	 *
	 * @return void
	 */
175
	protected function init() {
176
		$beUser = $this->getBackendUserAuthentication();
177
		// Page-selection permission clause (reading)
178
		$this->perms_clause = $beUser->getPagePermsClause(1);
179
		// This will hide records from display - it has nothing to do with user rights!!
180
181
		if ($pidList = $beUser->getTSConfigVal('options.hideRecords.pages')) {
			if ($pidList = $this->getDatabaseConnection()->cleanIntList($pidList)) {
182
				$this->perms_clause .= ' AND pages.uid NOT IN (' . $pidList . ')';
183
184
185
186
			}
		}
		// Setting GPvars:
		// The page id to operate from
187
		$this->id = (int)GeneralUtility::_GP('id');
Nicole Cordes's avatar
Nicole Cordes committed
188
189
		$this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
		$this->pagesOnly = GeneralUtility::_GP('pagesOnly');
190
		// Create instance of template class for output
191
		$this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
192
		$this->doc->setModuleTemplate('EXT:backend/Resources/Private/Templates/db_new.html');
193
194
195
196
197
		$this->doc->JScode = '';
		// Setting up the context sensitive menu:
		$this->doc->getContextMenuCode();
		// Creating content
		$this->content = '';
198
		$this->content .= $this->doc->header($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:db_new.php.pagetitle'));
199
200
		// Id a positive id is supplied, ask for the page record with permission information contained:
		if ($this->id > 0) {
Nicole Cordes's avatar
Nicole Cordes committed
201
			$this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
202
203
204
205
		}
		// If a page-record was returned, the user had read-access to the page.
		if ($this->pageinfo['uid']) {
			// Get record of parent page
Nicole Cordes's avatar
Nicole Cordes committed
206
			$this->pidInfo = BackendUtility::getRecord('pages', $this->pageinfo['pid']);
207
			// Checking the permissions for the user with regard to the parent page: Can he create new pages, new content record, new page after?
208
			if ($beUser->doesUserHaveAccess($this->pageinfo, 8)) {
209
210
				$this->newPagesInto = 1;
			}
211
			if ($beUser->doesUserHaveAccess($this->pageinfo, 16)) {
212
213
				$this->newContentInto = 1;
			}
214
			if (($beUser->isAdmin() || is_array($this->pidInfo)) && $beUser->doesUserHaveAccess($this->pidInfo, 8)) {
215
216
				$this->newPagesAfter = 1;
			}
217
		} elseif ($beUser->isAdmin()) {
218
219
220
221
222
223
224
225
226
227
228
229
			// Admins can do it all
			$this->newPagesInto = 1;
			$this->newContentInto = 1;
			$this->newPagesAfter = 0;
		} else {
			// People with no permission can do nothing
			$this->newPagesInto = 0;
			$this->newContentInto = 0;
			$this->newPagesAfter = 0;
		}
	}

230
231
232
233
	/**
	 * Injects the request object for the current request or subrequest
	 * As this controller goes only through the main() method, it is rather simple for now
	 *
234
235
236
	 * @param ServerRequestInterface $request the current request
	 * @param ResponseInterface $response
	 * @return ResponseInterface the response with the content
237
	 */
238
	public function mainAction(ServerRequestInterface $request, ResponseInterface $response) {
239
240
241
242
243
244
		$this->main();

		$response->getBody()->write($this->content);
		return $response;
	}

245
246
247
248
249
250
251
	/**
	 * Main processing, creating the list of new record tables to select from
	 *
	 * @return void
	 */
	public function main() {
		// If there was a page - or if the user is admin (admins has access to the root) we proceed:
252
		if ($this->pageinfo['uid'] || $this->getBackendUserAuthentication()->isAdmin()) {
253
			// Acquiring TSconfig for this module/current page:
Nicole Cordes's avatar
Nicole Cordes committed
254
			$this->web_list_modTSconfig = BackendUtility::getModTSconfig($this->pageinfo['uid'], 'mod.web_list');
255
256
			$this->allowedNewTables = GeneralUtility::trimExplode(',', $this->web_list_modTSconfig['properties']['allowedNewTables'], TRUE);
			$this->deniedNewTables = GeneralUtility::trimExplode(',', $this->web_list_modTSconfig['properties']['deniedNewTables'], TRUE);
257
			// Acquiring TSconfig for this module/parent page:
Nicole Cordes's avatar
Nicole Cordes committed
258
			$this->web_list_modTSconfig_pid = BackendUtility::getModTSconfig($this->pageinfo['pid'], 'mod.web_list');
259
260
			$this->allowedNewTables_pid = GeneralUtility::trimExplode(',', $this->web_list_modTSconfig_pid['properties']['allowedNewTables'], TRUE);
			$this->deniedNewTables_pid = GeneralUtility::trimExplode(',', $this->web_list_modTSconfig_pid['properties']['deniedNewTables'], TRUE);
261
262
263
264
265
266
267
268
269
			// More init:
			if (!$this->showNewRecLink('pages')) {
				$this->newPagesInto = 0;
			}
			if (!$this->showNewRecLink('pages', $this->allowedNewTables_pid, $this->deniedNewTables_pid)) {
				$this->newPagesAfter = 0;
			}
			// Set header-HTML and return_url
			if (is_array($this->pageinfo) && $this->pageinfo['uid']) {
270
				$iconImgTag = '<span title="' . htmlspecialchars($this->pageinfo['_thePath']) . '">' . $this->iconFactory->getIconForRecord('pages', $this->pageinfo, Icon::SIZE_SMALL)->render() . '</span>';
271
272
				$title = strip_tags($this->pageinfo[$GLOBALS['TCA']['pages']['ctrl']['label']]);
			} else {
273
				$iconImgTag = '<span title="' . htmlspecialchars($this->pageinfo['_thePath']) . '">' . $this->iconFactory->getIcon('apps-pagetree-root', Icon::SIZE_SMALL)->render() . '</span>';
274
275
				$title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
			}
Nicole Cordes's avatar
Nicole Cordes committed
276
			$this->code = '<span class="typo3-moduleHeader">' . $this->doc->wrapClickMenuOnIcon($iconImgTag, 'pages', $this->pageinfo['uid']) . htmlspecialchars(GeneralUtility::fixed_lgd_cs($title, 45)) . '</span><br />';
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
			$this->R_URI = $this->returnUrl;
			// GENERATE the HTML-output depending on mode (pagesOnly is the page wizard)
			// Regular new element:
			if (!$this->pagesOnly) {
				$this->regularNew();
			} elseif ($this->showNewRecLink('pages')) {
				// Pages only wizard
				$this->pagesOnly();
			}
			// Add all the content to an output section
			$this->content .= $this->doc->section('', $this->code);
			// Setting up the buttons and markers for docheader
			$docHeaderButtons = $this->getButtons();
			$markers['CSH'] = $docHeaderButtons['csh'];
			$markers['CONTENT'] = $this->content;
			// Build the <body> for the module
293
			$this->content = $this->doc->startPage($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:db_new.php.pagetitle'));
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
			$this->content .= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
			$this->content .= $this->doc->endPage();
			$this->content = $this->doc->insertStylesAndJS($this->content);
		}
	}

	/**
	 * Create the panel of buttons for submitting the form or otherwise perform operations.
	 *
	 * @return array All available buttons as an assoc. array
	 */
	protected function getButtons() {
		$buttons = array(
			'csh' => '',
			'back' => '',
			'view' => '',
			'new_page' => ''
		);
		// Regular new element:
		if (!$this->pagesOnly) {
			// New page
			if ($this->showNewRecLink('pages')) {
316
				$buttons['new_page'] = '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('pagesOnly' => '1'))) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:newPage', TRUE) . '">'
317
					. $this->iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL)->render()
318
					. '</a>';
319
320
			}
			// CSH
Benni Mack's avatar
Benni Mack committed
321
			$buttons['csh'] = BackendUtility::cshItem('xMOD_csh_corebe', 'new_regular');
322
323
324
		} elseif ($this->showNewRecLink('pages')) {
			// Pages only wizard
			// CSH
Benni Mack's avatar
Benni Mack committed
325
			$buttons['csh'] = BackendUtility::cshItem('xMOD_csh_corebe', 'new_pages');
326
327
328
		}
		// Back
		if ($this->R_URI) {
329
			$buttons['back'] = '<a href="' . htmlspecialchars($this->R_URI) . '" class="typo3-goBack" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.goBack', TRUE) . '">' . $this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL)->render() . '</a>';
330
331
332
		}
		if (is_array($this->pageinfo) && $this->pageinfo['uid']) {
			// View
333
334
335
336
337
338
339
340
			$pagesTSconfig = BackendUtility::getPagesTSconfig($this->pageinfo['uid']);
			if (isset($pagesTSconfig['TCEMAIN.']['preview.']['disableButtonForDokType'])) {
				$excludeDokTypes = GeneralUtility::intExplode(',', $pagesTSconfig['TCEMAIN.']['preview.']['disableButtonForDokType'], TRUE);
			} else {
				// exclude sysfolders and recycler by default
				$excludeDokTypes = array(PageRepository::DOKTYPE_RECYCLER, PageRepository::DOKTYPE_SYSFOLDER, PageRepository::DOKTYPE_SPACER);
			}
			if (!in_array((int)$this->pageinfo['doktype'], $excludeDokTypes, TRUE)) {
341
				$buttons['view'] = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($this->pageinfo['uid'], '', BackendUtility::BEgetRootLine($this->pageinfo['uid']))) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">' . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render() . '</a>';
342
			}
343
344
345
346
347
348
349
350
351
352
		}
		return $buttons;
	}

	/**
	 * Creates the position map for pages wizard
	 *
	 * @return void
	 */
	public function pagesOnly() {
353
		$numberOfPages = $this->getDatabaseConnection()->exec_SELECTcountRows('*', 'pages', '1=1' . BackendUtility::deleteClause('pages'));
354
		if ($numberOfPages > 0) {
355
			$this->code .= '
356
				<h3>' . htmlspecialchars($this->getLanguageService()->getLL('selectPosition')) . ':</h3>
357
			';
358
			$positionMap = GeneralUtility::makeInstance(PagePositionMap::class, NewRecordPageTreeView::class);
Nicole Cordes's avatar
Nicole Cordes committed
359
			/** @var $positionMap \TYPO3\CMS\Backend\Tree\View\PagePositionMap */
360
361
362
			$this->code .= $positionMap->positionTree($this->id, $this->pageinfo, $this->perms_clause, $this->R_URI);
		} else {
			// No pages yet, no need to prompt for position, redirect to page creation.
363
364
365
366
367
368
369
370
371
372
			$urlParameters = [
				'edit' => [
					'pages' => [
						0 => 'new'
					]
				],
				'returnNewPageId' => 1,
				'returnUrl' => BackendUtility::getModuleUrl('db_new', array('id' => $this->id, 'pagesOnly' => '1'))
			];
			$url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
373
			@ob_end_clean();
374
			HttpUtility::redirect($url);
375
376
377
378
379
380
381
382
383
		}
	}

	/**
	 * Create a regular new element (pages and records)
	 *
	 * @return void
	 */
	public function regularNew() {
384

385
386
		/** @var IconFactory $iconFactory */
		$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
387
		$lang = $this->getLanguageService();
388
389
390
		// Initialize array for accumulating table rows:
		$this->tRows = array();
		// Get TSconfig for current page
Nicole Cordes's avatar
Nicole Cordes committed
391
		$pageTS = BackendUtility::getPagesTSconfig($this->id);
392
393
394
395
396
		// Finish initializing new pages options with TSconfig
		// Each new page option may be hidden by TSconfig
		// Enabled option for the position of a new page
		$this->newPagesSelectPosition = !empty($pageTS['mod.']['wizards.']['newRecord.']['pages.']['show.']['pageSelectPosition']);
		// Pseudo-boolean (0/1) for backward compatibility
397
398
		$displayNewPagesIntoLink = $this->newPagesInto && !empty($pageTS['mod.']['wizards.']['newRecord.']['pages.']['show.']['pageInside']) ? 1 : 0;
		$displayNewPagesAfterLink = $this->newPagesAfter && !empty($pageTS['mod.']['wizards.']['newRecord.']['pages.']['show.']['pageAfter']) ? 1 : 0;
399
		// Slight spacer from header:
400
		$this->code .= '';
401
402
403
		// New Page
		$table = 'pages';
		$v = $GLOBALS['TCA'][$table];
404
		$pageIcon = $this->iconFactory->getIconForRecord($table, array(), Icon::SIZE_SMALL)->render();
405
		$newPageIcon = $this->iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL)->render();
406
407
408
		$rowContent = '';
		// New pages INSIDE this pages
		$newPageLinks = array();
409
		if ($displayNewPagesIntoLink && $this->isTableAllowedForThisPage($this->pageinfo, 'pages') && $this->getBackendUserAuthentication()->check('tables_modify', 'pages') && $this->getBackendUserAuthentication()->workspaceCreateNewRecord(($this->pageinfo['_ORIG_uid'] ?: $this->id), 'pages')) {
410
			// Create link to new page inside:
411
			$newPageLinks[] = $this->linkWrap($this->iconFactory->getIconForRecord($table, array(), 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);
412
413
		}
		// New pages AFTER this pages
414
		if ($displayNewPagesAfterLink && $this->isTableAllowedForThisPage($this->pidInfo, 'pages') && $this->getBackendUserAuthentication()->check('tables_modify', 'pages') && $this->getBackendUserAuthentication()->workspaceCreateNewRecord($this->pidInfo['uid'], 'pages')) {
415
			$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);
416
417
		}
		// New pages at selection position
418
		if ($this->newPagesSelectPosition && $this->showNewRecLink('pages')) {
419
			// Link to page-wizard:
420
			$newPageLinks[] = '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('pagesOnly' => 1))) . '">' . $pageIcon . htmlspecialchars($lang->getLL('pageSelectPosition')) . '</a>';
421
422
423
424
		}
		// Assemble all new page links
		$numPageLinks = count($newPageLinks);
		for ($i = 0; $i < $numPageLinks; $i++) {
425
			$rowContent .= '<li>' . $newPageLinks[$i] . '</li>';
426
		}
427
		if ($this->showNewRecLink('pages')) {
428
			$rowContent = '<ul class="list-tree"><li>' .$newPageIcon . '<strong>' .
429
				$lang->getLL('createNewPage') . '</strong><ul>' . $rowContent . '</ul></li>';
430
431
		} else {
			$rowContent = '<ul class="list-tree"><li><ul>' . $rowContent . '</li></ul>';
432
		}
433
434
		// Compile table row
		$startRows = array($rowContent);
435
		$iconFile = array();
436
		// New tables (but not pages) INSIDE this pages
437
		$isAdmin = $this->getBackendUserAuthentication()->isAdmin();
438
		$newContentIcon = $iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render();
439
440
441
442
		if ($this->newContentInto) {
			if (is_array($GLOBALS['TCA'])) {
				$groupName = '';
				foreach ($GLOBALS['TCA'] as $table => $v) {
443
444
445
					if ($table != 'pages'
						&& $this->showNewRecLink($table)
						&& $this->isTableAllowedForThisPage($this->pageinfo, $table)
446
						&& $this->getBackendUserAuthentication()->check('tables_modify', $table)
447
						&& (($v['ctrl']['rootLevel'] xor $this->id) || $v['ctrl']['rootLevel'] == -1)
448
						&& $this->getBackendUserAuthentication()->workspaceCreateNewRecord(($this->pageinfo['_ORIG_uid'] ? $this->pageinfo['_ORIG_uid'] : $this->id), $table)
449
					) {
450
						$newRecordIcon = $this->iconFactory->getIconForRecord($table, array(), Icon::SIZE_SMALL)->render();
451
						$rowContent = '';
452
						$thisTitle = '';
453
						// Create new link for record:
454
						$newLink = $this->linkWrap($newRecordIcon . $lang->sL($v['ctrl']['title'], TRUE), $table, $this->id);
Wouter Wolters's avatar
Wouter Wolters committed
455
						// If the table is 'tt_content', create link to wizard
456
						if ($table == 'tt_content') {
457
458
							$groupName = $lang->getLL('createNewContent');
							$rowContent = $newContentIcon . '<strong>' . $lang->getLL('createNewContent') . '</strong><ul>';
459
460
							// If mod.web_list.newContentWiz.overrideWithExtension is set, use that extension's wizard instead:
							$overrideExt = $this->web_list_modTSconfig['properties']['newContentWiz.']['overrideWithExtension'];
461
462
							$pathToWizard = ExtensionManagementUtility::isLoaded($overrideExt) ? ExtensionManagementUtility::extRelPath($overrideExt) . 'mod1/db_new_content_el.php?' : BackendUtility::getModuleUrl('new_content_element') . '&';
							$href = $pathToWizard . 'id=' . $this->id . '&returnUrl=' . rawurlencode(GeneralUtility::getIndpEnv('REQUEST_URI'));
463
							$rowContent .= '<li>' . $newLink . ' ' . BackendUtility::wrapInHelp($table, '') . '</li><li><a href="' . htmlspecialchars($href) . '">' . $newContentIcon . htmlspecialchars($lang->getLL('clickForWizard')) . '</a></li></ul>';
464
465
						} else {
							// Get the title
466
							if ($v['ctrl']['readOnly'] || $v['ctrl']['hideTable'] || $v['ctrl']['is_static']) {
467
468
469
470
471
472
473
								continue;
							}
							if ($v['ctrl']['adminOnly'] && !$isAdmin) {
								continue;
							}
							$nameParts = explode('_', $table);
							$thisTitle = '';
474
							$_EXTKEY = '';
475
476
477
478
479
480
481
482
483
							if ($nameParts[0] == 'tx' || $nameParts[0] == 'tt') {
								// Try to extract extension name
								if (substr($v['ctrl']['title'], 0, 8) == 'LLL:EXT:') {
									$_EXTKEY = substr($v['ctrl']['title'], 8);
									$_EXTKEY = substr($_EXTKEY, 0, strpos($_EXTKEY, '/'));
									if ($_EXTKEY != '') {
										// First try to get localisation of extension title
										$temp = explode(':', substr($v['ctrl']['title'], 9 + strlen($_EXTKEY)));
										$langFile = $temp[0];
484
										$thisTitle = $lang->sL('LLL:EXT:' . $_EXTKEY . '/' . $langFile . ':extension.title');
485
										// If no localisation available, read title from ext_emconf.php
486
487
488
489
										$extEmConfFile = ExtensionManagementUtility::extPath($_EXTKEY) . 'ext_emconf.php';
										if (!$thisTitle && is_file($extEmConfFile)) {
											$EM_CONF = array();
											include $extEmConfFile;
490
491
											$thisTitle = $EM_CONF[$_EXTKEY]['title'];
										}
Nicole Cordes's avatar
Nicole Cordes committed
492
										$iconFile[$_EXTKEY] = '<img ' . 'src="' . ExtensionManagementUtility::extRelPath($_EXTKEY) . $GLOBALS['TYPO3_LOADED_EXT'][$_EXTKEY]['ext_icon'] . '" ' . 'width="16" height="16" ' . 'alt="' . $thisTitle . '" />';
493
									}
494
495
496
								}
								if (empty($thisTitle)) {
									$_EXTKEY = $nameParts[1];
497
498
499
500
									$thisTitle = $nameParts[1];
									$iconFile[$_EXTKEY] = '';
								}
							} else {
501
502
503
								if ($table === 'pages_language_overlay' && !$this->checkIfLanguagesExist()) {
									continue;
								}
504
								$_EXTKEY = 'system';
505
								$thisTitle = $lang->getLL('system_records');
506
								$iconFile['system'] = $this->iconFactory->getIcon('apps-pagetree-root', Icon::SIZE_SMALL)->render();
507
508
509
510
511
512
513
514
							}
							if ($groupName == '' || $groupName != $_EXTKEY) {
								$groupName = empty($v['ctrl']['groupName']) ? $_EXTKEY : $v['ctrl']['groupName'];
							}
							$rowContent .= $newLink;
						}
						// Compile table row:
						if ($table == 'tt_content') {
515
							$startRows[] = '<li>' . $rowContent . '</li>';
516
517
518
519
520
521
522
523
524
525
526
						} else {
							$this->tRows[$groupName]['title'] = $thisTitle;
							$this->tRows[$groupName]['html'][] = $rowContent;
							$this->tRows[$groupName]['table'][] = $table;
						}
					}
				}
			}
		}
		// User sort
		if (isset($pageTS['mod.']['wizards.']['newRecord.']['order'])) {
Nicole Cordes's avatar
Nicole Cordes committed
527
			$this->newRecordSortList = GeneralUtility::trimExplode(',', $pageTS['mod.']['wizards.']['newRecord.']['order'], TRUE);
528
529
530
531
532
533
		}
		uksort($this->tRows, array($this, 'sortNewRecordsByConfig'));
		// Compile table row:
		$finalRows = array();
		$finalRows[] = implode('', $startRows);
		foreach ($this->tRows as $key => $value) {
534
			$row = '<li>' . $iconFile[$key] . ' <strong>' . $value['title'] . '</strong><ul>';
535
			foreach ($value['html'] as $recordKey => $record) {
536
				$row .= '<li>' . $record . ' ' . BackendUtility::wrapInHelp($value['table'][$recordKey], '') . '</li>';
537
			}
538
			$row .= '</ul></li>';
539
540
541
			$finalRows[] = $row;
		}
		// Make table:
542
		$this->code .= implode('', $finalRows);
543
544
545
546
547
548
549
	}

	/**
	 * User array sort function used by regularNew
	 *
	 * @param string $a First array element for compare
	 * @param string $b First array element for compare
550
	 * @return int -1 for lower, 0 for equal, 1 for greater
551
552
	 */
	public function sortNewRecordsByConfig($a, $b) {
553
		if (!empty($this->newRecordSortList)) {
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
			if (in_array($a, $this->newRecordSortList) && in_array($b, $this->newRecordSortList)) {
				// Both are in the list, return relative to position in array
				$sub = array_search($a, $this->newRecordSortList) - array_search($b, $this->newRecordSortList);
				$ret = ($sub < 0 ? -1 : $sub == 0) ? 0 : 1;
			} elseif (in_array($a, $this->newRecordSortList)) {
				// First element is in array, put to top
				$ret = -1;
			} elseif (in_array($b, $this->newRecordSortList)) {
				// Second element is in array, put first to bottom
				$ret = 1;
			} else {
				// No element is in array, return alphabetic order
				$ret = strnatcasecmp($this->tRows[$a]['title'], $this->tRows[$b]['title']);
			}
			return $ret;
		} else {
			// Return alphabetic order
			return strnatcasecmp($this->tRows[$a]['title'], $this->tRows[$b]['title']);
		}
	}

	/**
	 * Ending page output and echo'ing content to browser.
	 *
	 * @return void
579
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use mainAction() instead
580
581
	 */
	public function printContent() {
582
		GeneralUtility::logDeprecatedFunction();
583
584
585
586
587
588
589
590
		echo $this->content;
	}

	/**
	 * Links the string $code to a create-new form for a record in $table created on page $pid
	 *
	 * @param string $linkText Link text
	 * @param string $table Table name (in which to create new record)
591
	 * @param int $pid PID value for the "&edit['.$table.']['.$pid.']=new" command (positive/negative)
592
	 * @param bool $addContentTable If $addContentTable is set, then a new tt_content record is created together with pages
593
594
595
	 * @return string The link.
	 */
	public function linkWrap($linkText, $table, $pid, $addContentTable = FALSE) {
596
597
598
599
600
601
602
603
		$urlParameters = [
			'edit' => [
				$table => [
					$pid => 'new'
				]
			],
			'returnUrl' => $this->returnUrl
		];
604
		if ($table == 'pages' && $addContentTable) {
605
606
			$urlParameters['tt_content']['prev'] = 'new';
			$urlParameters['returnNewPageId'] = 1;
607
		} elseif ($table == 'pages_language_overlay') {
608
			$urlParameters['overrideVals']['pages_language_overlay']['doktype'] = (int)$this->pageinfo['doktype'];
609
		}
610
611
		$url = BackendUtility::getModuleUrl('record_edit', $urlParameters);
		return '<a href="' . htmlspecialchars($url) . '">' . $linkText . '</a>';
612
613
614
615
616
617
618
	}

	/**
	 * Returns TRUE if the tablename $checkTable is allowed to be created on the page with record $pid_row
	 *
	 * @param array $pid_row Record for parent page.
	 * @param string $checkTable Table name to check
619
	 * @return bool Returns TRUE if the tablename $checkTable is allowed to be created on the page with record $pid_row
620
621
622
	 */
	public function isTableAllowedForThisPage($pid_row, $checkTable) {
		if (!is_array($pid_row)) {
623
			return $this->getBackendUserAuthentication()->isAdmin();
624
625
626
627
628
629
		}
		// be_users and be_groups may not be created anywhere but in the root.
		if ($checkTable == 'be_users' || $checkTable == 'be_groups') {
			return FALSE;
		}
		// Checking doktype:
630
		$doktype = (int)$pid_row['doktype'];
631
632
633
		if (!($allowedTableList = $GLOBALS['PAGES_TYPES'][$doktype]['allowedTables'])) {
			$allowedTableList = $GLOBALS['PAGES_TYPES']['default']['allowedTables'];
		}
634
		// If all tables or the table is listed as an allowed type, return TRUE
Nicole Cordes's avatar
Nicole Cordes committed
635
		if (strstr($allowedTableList, '*') || GeneralUtility::inList($allowedTableList, $checkTable)) {
636
637
			return TRUE;
		}
638
639

		return FALSE;
640
641
642
643
644
645
646
647
648
649
650
651
652
	}

	/**
	 * Returns TRUE if:
	 * - $allowedNewTables and $deniedNewTables are empty
	 * - the table is not found in $deniedNewTables and $allowedNewTables is not set or the $table tablename is found in $allowedNewTables
	 *
	 * If $table tablename is found in $allowedNewTables and $deniedNewTables, $deniedNewTables
	 * has priority over $allowedNewTables.
	 *
	 * @param string $table Table name to test if in allowedTables
	 * @param array $allowedNewTables Array of new tables that are allowed.
	 * @param array $deniedNewTables Array of new tables that are not allowed.
653
	 * @return bool Returns TRUE if a link for creating new records should be displayed for $table
654
655
	 */
	public function showNewRecLink($table, array $allowedNewTables = array(), array $deniedNewTables = array()) {
656
657
658
659
660

		if (!$this->getBackendUserAuthentication()->check('tables_modify', $table)) {
			return FALSE;
		}

661
662
		$allowedNewTables = $allowedNewTables ?: $this->allowedNewTables;
		$deniedNewTables = $deniedNewTables ?: $this->deniedNewTables;
663
		// No deny/allow tables are set:
664
		if (empty($allowedNewTables) && empty($deniedNewTables)) {
665
666
			return TRUE;
		}
667
668

		return !in_array($table, $deniedNewTables) && (empty($allowedNewTables) || in_array($table, $allowedNewTables));
669
670
	}

671
672
673
674
675
676
677
678
679
680
681
682
683
	/**
	 * Checks if sys_language records are present
	 *
	 * @return bool
	 */
	protected function checkIfLanguagesExist() {
		$languageCount = $this->getDatabaseConnection()->exec_SELECTcountRows('uid', 'sys_language', '1=1');
		if ($languageCount) {
			$languageCount = TRUE;
		}
		return $languageCount;
	}

684
685
686
687
688
689
690
691
692
	/**
	 * Return language service instance
	 *
	 * @return \TYPO3\CMS\Lang\LanguageService
	 */
	protected function getLanguageService() {
		return $GLOBALS['LANG'];
	}

693
694
695
696
697
698
699
700
	/**
	 * Returns the global BackendUserAuthentication object.
	 *
	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
	 */
	protected function getBackendUserAuthentication() {
		return $GLOBALS['BE_USER'];
	}
701

702
703
704
705
706
707
708
709
710
	/**
	 * Returns the database connection
	 *
	 * @return DatabaseConnection
	 */
	protected function getDatabaseConnection() {
		return $GLOBALS['TYPO3_DB'];
	}

711
}