[TASK] Move language and chsimages in setup
[Packages/TYPO3.CMS.git] / typo3 / sysext / setup / Classes / Controller / SetupModuleController.php
1 <?php
2 namespace TYPO3\CMS\Setup\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 TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
19 use TYPO3\CMS\Core\Database\DatabaseConnection;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Core\Messaging\FlashMessage;
22
23 /**
24 * Script class for the Setup module
25 */
26 class SetupModuleController {
27
28 const PASSWORD_NOT_UPDATED = 0;
29 const PASSWORD_UPDATED = 1;
30 const PASSWORD_NOT_THE_SAME = 2;
31 const PASSWORD_OLD_WRONG = 3;
32
33 /**
34 * @var array
35 */
36 public $MOD_MENU = array();
37
38 /**
39 * @var array
40 */
41 public $MOD_SETTINGS = array();
42
43 /**
44 * @var \TYPO3\CMS\Backend\Template\DocumentTemplate
45 */
46 public $doc;
47
48 /**
49 * @var string
50 */
51 public $content;
52
53 /**
54 * @var array
55 */
56 public $overrideConf;
57
58 /**
59 * backend user object, set during simulate-user operation
60 *
61 * @var \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
62 */
63 public $OLD_BE_USER;
64
65 /**
66 * @var bool
67 */
68 public $languageUpdate;
69
70 /**
71 * @var bool
72 */
73 protected $pagetreeNeedsRefresh = FALSE;
74
75 /**
76 * @var bool
77 */
78 protected $isAdmin;
79
80 /**
81 * @var array
82 */
83 protected $tsFieldConf;
84
85 /**
86 * @var bool
87 */
88 protected $saveData = FALSE;
89
90 /**
91 * @var int
92 */
93 protected $passwordIsUpdated = self::PASSWORD_NOT_UPDATED;
94
95 /**
96 * @var bool
97 */
98 protected $passwordIsSubmitted = FALSE;
99
100 /**
101 * @var bool
102 */
103 protected $setupIsUpdated = FALSE;
104
105 /**
106 * @var bool
107 */
108 protected $tempDataIsCleared = FALSE;
109
110 /**
111 * @var bool
112 */
113 protected $settingsAreResetToDefault = FALSE;
114
115 /**
116 * Form protection instance
117 *
118 * @var \TYPO3\CMS\Core\FormProtection\BackendFormProtection
119 */
120 protected $formProtection;
121
122 /**
123 * @var string
124 */
125 protected $simulateSelector = '';
126
127 /**
128 * @var string
129 */
130 protected $simUser = '';
131
132 /**
133 * The name of the module
134 *
135 * @var string
136 */
137 protected $moduleName = 'user_setup';
138
139 /**
140 * Instantiate the form protection before a simulated user is initialized.
141 */
142 public function __construct() {
143 $this->formProtection = \TYPO3\CMS\Core\FormProtection\FormProtectionFactory::get();
144 }
145
146 /**
147 * Getter for the form protection instance.
148 *
149 * @return \TYPO3\CMS\Core\FormProtection\BackendFormProtection
150 */
151 public function getFormProtection() {
152 return $this->formProtection;
153 }
154
155 /**
156 * If settings are submitted to _POST[DATA], store them
157 * NOTICE: This method is called before the \TYPO3\CMS\Backend\Template\DocumentTemplate
158 * is included. See bottom of document.
159 *
160 * @see \TYPO3\CMS\Backend\Template\DocumentTemplate
161 */
162 public function storeIncomingData() {
163 // First check if something is submitted in the data-array from POST vars
164 $d = GeneralUtility::_POST('data');
165 $columns = $GLOBALS['TYPO3_USER_SETTINGS']['columns'];
166 $beUser = $this->getBackendUser();
167 $beUserId = $beUser->user['uid'];
168 $storeRec = array();
169 $fieldList = $this->getFieldsFromShowItem();
170 if (is_array($d) && $this->formProtection->validateToken((string)GeneralUtility::_POST('formToken'), 'BE user setup', 'edit')) {
171 // UC hashed before applying changes
172 $save_before = md5(serialize($beUser->uc));
173 // PUT SETTINGS into the ->uc array:
174 // Reload left frame when switching BE language
175 if (isset($d['lang']) && $d['lang'] != $beUser->uc['lang']) {
176 $this->languageUpdate = TRUE;
177 }
178 // Reload pagetree if the title length is changed
179 if (isset($d['titleLen']) && $d['titleLen'] !== $beUser->uc['titleLen']) {
180 $this->pagetreeNeedsRefresh = TRUE;
181 }
182 if ($d['setValuesToDefault']) {
183 // If every value should be default
184 $beUser->resetUC();
185 $this->settingsAreResetToDefault = TRUE;
186 } elseif ($d['clearSessionVars']) {
187 foreach ($beUser->uc as $key => $value) {
188 if (!isset($columns[$key])) {
189 unset($beUser->uc[$key]);
190 }
191 }
192 $this->tempDataIsCleared = TRUE;
193 } elseif ($d['save']) {
194 // Save all submitted values if they are no array (arrays are with table=be_users) and exists in $GLOBALS['TYPO3_USER_SETTINGS'][columns]
195 foreach ($columns as $field => $config) {
196 if (!in_array($field, $fieldList)) {
197 continue;
198 }
199 if ($config['table']) {
200 if ($config['table'] === 'be_users' && !in_array($field, array('password', 'password2', 'passwordCurrent', 'email', 'realName', 'admin'))) {
201 if (!isset($config['access']) || $this->checkAccess($config) && $beUser->user[$field] !== $d['be_users'][$field]) {
202 if ($config['type'] === 'check') {
203 $fieldValue = isset($d['be_users'][$field]) ? 1 : 0;
204 } else {
205 $fieldValue = $d['be_users'][$field];
206 }
207 $storeRec['be_users'][$beUserId][$field] = $fieldValue;
208 $beUser->user[$field] = $fieldValue;
209 }
210 }
211 }
212 if ($config['type'] === 'check') {
213 $beUser->uc[$field] = isset($d[$field]) ? 1 : 0;
214 } else {
215 $beUser->uc[$field] = htmlspecialchars($d[$field]);
216 }
217 }
218 // Personal data for the users be_user-record (email, name, password...)
219 // If email and name is changed, set it in the users record:
220 $be_user_data = $d['be_users'];
221 // Possibility to modify the transmitted values. Useful to do transformations, like RSA password decryption
222 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/setup/mod/index.php']['modifyUserDataBeforeSave'])) {
223 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/setup/mod/index.php']['modifyUserDataBeforeSave'] as $function) {
224 $params = array('be_user_data' => &$be_user_data);
225 GeneralUtility::callUserFunction($function, $params, $this);
226 }
227 }
228 $this->passwordIsSubmitted = (string)$be_user_data['password'] !== '';
229 $passwordIsConfirmed = $this->passwordIsSubmitted && $be_user_data['password'] === $be_user_data['password2'];
230 // Update the real name:
231 if ($be_user_data['realName'] !== $beUser->user['realName']) {
232 $beUser->user['realName'] = ($storeRec['be_users'][$beUserId]['realName'] = substr($be_user_data['realName'], 0, 80));
233 }
234 // Update the email address:
235 if ($be_user_data['email'] !== $beUser->user['email']) {
236 $beUser->user['email'] = ($storeRec['be_users'][$beUserId]['email'] = substr($be_user_data['email'], 0, 80));
237 }
238 // Update the password:
239 if ($passwordIsConfirmed) {
240 $currentPasswordHashed = $GLOBALS['BE_USER']->user['password'];
241 $saltFactory = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($currentPasswordHashed);
242 if ($saltFactory->checkPassword($be_user_data['passwordCurrent'], $currentPasswordHashed)) {
243 $this->passwordIsUpdated = self::PASSWORD_UPDATED;
244 $storeRec['be_users'][$beUserId]['password'] = $be_user_data['password'];
245 } else {
246 $this->passwordIsUpdated = self::PASSWORD_OLD_WRONG;
247 }
248 } else {
249 $this->passwordIsUpdated = self::PASSWORD_NOT_THE_SAME;
250 }
251 $this->saveData = TRUE;
252 }
253 // Inserts the overriding values.
254 $beUser->overrideUC();
255 $save_after = md5(serialize($beUser->uc));
256 // If something in the uc-array of the user has changed, we save the array...
257 if ($save_before != $save_after) {
258 $beUser->writeUC($beUser->uc);
259 $beUser->writelog(254, 1, 0, 1, 'Personal settings changed', array());
260 $this->setupIsUpdated = TRUE;
261 }
262 // If the temporary data has been cleared, lets make a log note about it
263 if ($this->tempDataIsCleared) {
264 $beUser->writelog(254, 1, 0, 1, $this->getLanguageService()->getLL('tempDataClearedLog'), array());
265 }
266 // Persist data if something has changed:
267 if (count($storeRec) && $this->saveData) {
268 // Make instance of TCE for storing the changes.
269 $tce = GeneralUtility::makeInstance(\TYPO3\CMS\Core\DataHandling\DataHandler::class);
270 $tce->stripslashes_values = 0;
271 // This is so the user can actually update his user record.
272 $isAdmin = $beUser->user['admin'];
273 $beUser->user['admin'] = 1;
274 $tce->start($storeRec, array(), $beUser);
275 // This is to make sure that the users record can be updated even if in another workspace. This is tolerated.
276 $tce->bypassWorkspaceRestrictions = TRUE;
277 $tce->process_datamap();
278 unset($tce);
279 if ($this->passwordIsUpdated === self::PASSWORD_NOT_UPDATED || count($storeRec['be_users'][$beUserId]) > 1) {
280 $this->setupIsUpdated = TRUE;
281 }
282 // Restore admin status after processing
283 $beUser->user['admin'] = $isAdmin;
284 }
285 }
286 }
287
288 /******************************
289 *
290 * Rendering module
291 *
292 ******************************/
293 /**
294 * Initializes the module for display of the settings form.
295 *
296 * @return void
297 */
298 public function init() {
299 $this->getLanguageService()->includeLLFile('EXT:setup/Resources/Private/Language/locallang.xlf');
300
301 // Returns the script user - that is the REAL logged in user! ($GLOBALS[BE_USER] might be another user due to simulation!)
302 $scriptUser = $this->getRealScriptUserObj();
303
304 $this->isAdmin = $scriptUser->isAdmin();
305 // Getting the 'override' values as set might be set in User TSconfig
306 $this->overrideConf = $this->getBackendUser()->getTSConfigProp('setup.override');
307 // Getting the disabled fields might be set in User TSconfig (eg setup.fields.password.disabled=1)
308 $this->tsFieldConf = $this->getBackendUser()->getTSConfigProp('setup.fields');
309 // id password is disabled, disable repeat of password too (password2)
310 if (isset($this->tsFieldConf['password.']) && $this->tsFieldConf['password.']['disabled']) {
311 $this->tsFieldConf['password2.']['disabled'] = 1;
312 $this->tsFieldConf['passwordCurrent.']['disabled'] = 1;
313 }
314 // Create instance of object for output of data
315 $this->doc = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Template\DocumentTemplate::class);
316 $this->doc->backPath = $GLOBALS['BACK_PATH'];
317 $this->doc->setModuleTemplate('EXT:setup/Resources/Private/Templates/setup.html');
318 $this->doc->form = '<form action="' . BackendUtility::getModuleUrl('user_setup') . '" method="post" name="usersetup" enctype="application/x-www-form-urlencoded">';
319 $this->doc->addStyleSheet('module', 'sysext/setup/Resources/Public/Css/styles.css');
320 $this->doc->JScode .= $this->getJavaScript();
321 }
322
323 /**
324 * Generate necessary JavaScript
325 *
326 * @return string
327 */
328 protected function getJavaScript() {
329 $javaScript = '';
330 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/setup/mod/index.php']['setupScriptHook'])) {
331 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/setup/mod/index.php']['setupScriptHook'] as $function) {
332 $params = array();
333 $javaScript .= GeneralUtility::callUserFunction($function, $params, $this);
334 }
335 }
336 return $javaScript;
337 }
338
339 /**
340 * Generate the main settings form:
341 *
342 * @return void
343 */
344 public function main() {
345 if ($this->languageUpdate) {
346 $this->doc->JScodeArray['languageUpdate'] .= '
347 if (top.refreshMenu) {
348 top.refreshMenu();
349 } else {
350 top.TYPO3ModuleMenu.refreshMenu();
351 }
352 ';
353 }
354 if ($this->pagetreeNeedsRefresh) {
355 BackendUtility::setUpdateSignal('updatePageTree');
356 }
357 // Start page:
358 $this->doc->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/md5.js');
359 // Use a wrapper div
360 $this->content .= '<div id="user-setup-wrapper">';
361 // Load available backend modules
362 $this->loadModules = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Module\ModuleLoader::class);
363 $this->loadModules->observeWorkspaces = TRUE;
364 $this->loadModules->load($GLOBALS['TBE_MODULES']);
365 $this->content .= $this->doc->header($this->getLanguageService()->getLL('UserSettings'));
366 // Show if setup was saved
367 if ($this->setupIsUpdated && !$this->tempDataIsCleared && !$this->settingsAreResetToDefault) {
368 $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('setupWasUpdated'), $this->getLanguageService()->getLL('UserSettings'));
369 $this->content .= $flashMessage->render();
370 }
371 // Show if temporary data was cleared
372 if ($this->tempDataIsCleared) {
373 $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('tempDataClearedFlashMessage'), $this->getLanguageService()->getLL('tempDataCleared'));
374 $this->content .= $flashMessage->render();
375 }
376 // Show if temporary data was cleared
377 if ($this->settingsAreResetToDefault) {
378 $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('settingsAreReset'), $this->getLanguageService()->getLL('resetConfiguration'));
379 $this->content .= $flashMessage->render();
380 }
381 // Notice
382 if ($this->setupIsUpdated || $this->settingsAreResetToDefault) {
383 $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('activateChanges'), '', FlashMessage::INFO);
384 $this->content .= $flashMessage->render();
385 }
386 // If password is updated, output whether it failed or was OK.
387 if ($this->passwordIsSubmitted) {
388 $flashMessage = NULL;
389 switch ($this->passwordIsUpdated) {
390 case self::PASSWORD_OLD_WRONG:
391 $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('oldPassword_failed'), $this->getLanguageService()->getLL('newPassword'), FlashMessage::ERROR);
392 break;
393 case self::PASSWORD_NOT_THE_SAME:
394 $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('newPassword_failed'), $this->getLanguageService()->getLL('newPassword'), FlashMessage::ERROR);
395 break;
396 case self::PASSWORD_UPDATED:
397 $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('newPassword_ok'), $this->getLanguageService()->getLL('newPassword'));
398 break;
399 }
400 if ($flashMessage) {
401 $this->content .= $flashMessage->render();
402 }
403 }
404
405 // Render user switch
406 $this->content .= $this->renderSimulateUserSelectAndLabel();
407
408 // Render the menu items
409 $menuItems = $this->renderUserSetup();
410 $this->content .= $this->doc->getDynamicTabMenu($menuItems, 'user-setup', 1, FALSE, FALSE);
411 $formToken = $this->formProtection->generateToken('BE user setup', 'edit');
412 $this->content .= $this->doc->section('', '<input type="hidden" name="simUser" value="' . $this->simUser . '" />
413 <input type="hidden" name="formToken" value="' . $formToken . '" />
414 <input type="hidden" value="1" name="data[save]" />
415 <input type="hidden" name="data[setValuesToDefault]" value="0" id="setValuesToDefault" />
416 <input type="hidden" name="data[clearSessionVars]" value="0" id="clearSessionVars" />');
417 // End of wrapper div
418 $this->content .= '</div>';
419 // Setting up the buttons and markers for docheader
420 $docHeaderButtons = $this->getButtons();
421 $markers['CSH'] = $docHeaderButtons['csh'];
422 $markers['CONTENT'] = $this->content;
423 // Build the <body> for the module
424 $this->content = $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
425 // Renders the module page
426 $this->content = $this->doc->render($this->getLanguageService()->getLL('UserSettings'), $this->content);
427 }
428
429 /**
430 * Prints the content / ends page
431 *
432 * @return void
433 */
434 public function printContent() {
435 echo $this->content;
436 }
437
438 /**
439 * Create the panel of buttons for submitting the form or otherwise perform operations.
440 *
441 * @return array All available buttons as an assoc. array
442 */
443 protected function getButtons() {
444 $buttons = array(
445 'csh' => '',
446 'save' => '',
447 'shortcut' => ''
448 );
449 $buttons['csh'] = BackendUtility::cshItem('_MOD_user_setup', '');
450 $buttons['save'] = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-save', array('html' => '<input type="image" name="data[save]" class="c-inputButton" src="clear.gif" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', TRUE) . '" />'));
451 if ($this->getBackendUser()->mayMakeShortcut()) {
452 $buttons['shortcut'] = $this->doc->makeShortcutIcon('', '', $this->moduleName);
453 }
454 return $buttons;
455 }
456
457 /******************************
458 *
459 * Render module
460 *
461 ******************************/
462
463 /**
464 * renders the data for all tabs in the user setup and returns
465 * everything that is needed with tabs and dyntab menu
466 *
467 * @return array Ready to use for the dyntabmenu itemarray
468 */
469 protected function renderUserSetup() {
470 $result = array();
471 $firstTabLabel = '';
472 $code = array();
473 $i = 0;
474 $fieldArray = $this->getFieldsFromShowItem();
475 $tabLabel = '';
476 foreach ($fieldArray as $fieldName) {
477 $more = '';
478 if (substr($fieldName, 0, 8) === '--div--;') {
479 if ($firstTabLabel === '') {
480 // First tab
481 $tabLabel = $this->getLabel(substr($fieldName, 8), '', FALSE);
482 $firstTabLabel = $tabLabel;
483 } else {
484 $result[] = array(
485 'label' => $tabLabel,
486 'content' => count($code) ? implode(LF, $code) : ''
487 );
488 $tabLabel = $this->getLabel(substr($fieldName, 8), '', FALSE);
489 $i = 0;
490 $code = array();
491 }
492 continue;
493 }
494 $config = $GLOBALS['TYPO3_USER_SETTINGS']['columns'][$fieldName];
495
496 // Field my be disabled in setup.fields
497 if (isset($this->tsFieldConf[$fieldName . '.']['disabled']) && $this->tsFieldConf[$fieldName . '.']['disabled'] == 1) {
498 continue;
499 }
500 if (isset($config['access']) && !$this->checkAccess($config)) {
501 continue;
502 }
503 $label = $this->getLabel($config['label'], $fieldName);
504 $label = $this->getCSH($config['csh'] ?: $fieldName, $label);
505 $type = $config['type'];
506 $class = $config['class'];
507
508 if ($type !== 'check') {
509 $class .= ' form-control';
510 }
511
512 $style = $config['style'];
513 if ($class) {
514 $more .= ' class="' . $class . '"';
515 }
516 if ($style) {
517 $more .= ' style="' . $style . '"';
518 }
519 if (isset($this->overrideConf[$fieldName])) {
520 $more .= ' disabled="disabled"';
521 }
522 $value = $config['table'] === 'be_users' ? $this->getBackendUser()->user[$fieldName] : $this->getBackendUser()->uc[$fieldName];
523 if (!$value && isset($config['default'])) {
524 $value = $config['default'];
525 }
526 $dataAdd = '';
527 if ($config['table'] === 'be_users') {
528 $dataAdd = '[be_users]';
529 }
530
531 switch ($type) {
532 case 'text':
533 case 'email':
534 case 'password':
535 $noAutocomplete = '';
536 if ($type === 'password') {
537 $value = '';
538 $noAutocomplete = 'autocomplete="off" ';
539 $more .= ' data-rsa-encryption=""';
540 }
541 $html = '<input id="field_' . $fieldName . '"
542 type="' . $type . '"
543 name="data' . $dataAdd . '[' . $fieldName . ']" ' .
544 $noAutocomplete .
545 'value="' . htmlspecialchars($value) . '" ' .
546 $more .
547 ' />';
548 break;
549 case 'check':
550 $html = $label . '<div class="checkbox"><label><input id="field_' . $fieldName . '"
551 type="checkbox"
552 name="data' . $dataAdd . '[' . $fieldName . ']"' .
553 ($value ? ' checked="checked"' : '') .
554 $more .
555 ' /></label></div>';
556 $label = '';
557 break;
558 case 'select':
559 if ($config['itemsProcFunc']) {
560 $html = GeneralUtility::callUserFunction($config['itemsProcFunc'], $config, $this, '');
561 } else {
562 $html = '<select id="field_' . $fieldName . '"
563 name="data' . $dataAdd . '[' . $fieldName . ']"' .
564 $more . '>' . LF;
565 foreach ($config['items'] as $key => $optionLabel) {
566 $html .= '<option value="' . $key . '"' . ($value == $key ? ' selected="selected"' : '') . '>' . $this->getLabel($optionLabel, '', FALSE) . '</option>' . LF;
567 }
568 $html .= '</select>';
569 }
570 break;
571 case 'user':
572 $html = GeneralUtility::callUserFunction($config['userFunc'], $config, $this, '');
573 break;
574 case 'button':
575 if ($config['onClick']) {
576 $onClick = $config['onClick'];
577 if ($config['onClickLabels']) {
578 foreach ($config['onClickLabels'] as $key => $labelclick) {
579 $config['onClickLabels'][$key] = $this->getLabel($labelclick, '', FALSE);
580 }
581 $onClick = vsprintf($onClick, $config['onClickLabels']);
582 }
583 $html = '<br><input class="btn btn-default" type="button"
584 value="' . $this->getLabel($config['buttonlabel'], '', FALSE) . '"
585 onclick="' . $onClick . '" />';
586 }
587 break;
588 default:
589 $html = '';
590 }
591
592 $code[] = '<div class="form-section"><div class="form-group">' .
593 $label .
594 $html .
595 '</div></div>';
596 }
597
598 $result[] = array(
599 'label' => $tabLabel,
600 'content' => count($code) ? implode(LF, $code) : ''
601 );
602 return $result;
603 }
604
605 /******************************
606 *
607 * Helper functions
608 *
609 ******************************/
610 /**
611 * Returns the backend user object, either the global OR the $this->OLD_BE_USER which is set during simulate-user operation.
612 * Anyway: The REAL user is returned - the one logged in.
613 *
614 * @return BackendUserAuthentication The REAL user is returned - the one logged in.
615 */
616 protected function getRealScriptUserObj() {
617 return is_object($this->OLD_BE_USER) ? $this->OLD_BE_USER : $this->getBackendUser();
618 }
619
620 /**
621 * Return a select with available languages
622 *
623 * @return string Complete select as HTML string or warning box if something went wrong.
624 */
625 public function renderLanguageSelect($params, $pObj) {
626 $languageOptions = array();
627 // Compile the languages dropdown
628 $langDefault = $this->getLanguageService()->getLL('lang_default', TRUE);
629 $languageOptions[$langDefault] = '<option value=""' . ($this->getBackendUser()->uc['lang'] === '' ? ' selected="selected"' : '') . '>' . $langDefault . '</option>';
630 // Traverse the number of languages
631 /** @var $locales \TYPO3\CMS\Core\Localization\Locales */
632 $locales = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Localization\Locales::class);
633 $languages = $locales->getLanguages();
634 foreach ($languages as $locale => $name) {
635 if ($locale !== 'default') {
636 $defaultName = isset($GLOBALS['LOCAL_LANG']['default']['lang_' . $locale]) ? $GLOBALS['LOCAL_LANG']['default']['lang_' . $locale][0]['source'] : $name;
637 $localizedName = $this->getLanguageService()->getLL('lang_' . $locale, TRUE);
638 if ($localizedName === '') {
639 $localizedName = htmlspecialchars($name);
640 }
641 $localLabel = ' - [' . htmlspecialchars($defaultName) . ']';
642 $available = is_dir(PATH_typo3conf . 'l10n/' . $locale);
643 if ($available) {
644 $languageOptions[$defaultName] = '<option value="' . $locale . '"' . ($this->getBackendUser()->uc['lang'] === $locale ? ' selected="selected"' : '') . '>' . $localizedName . $localLabel . '</option>';
645 }
646 }
647 }
648 ksort($languageOptions);
649 $languageCode = '
650 <select id="field_lang" name="data[lang]" class="form-control">' . implode('', $languageOptions) . '
651 </select>';
652 if ($this->getBackendUser()->uc['lang'] && !@is_dir((PATH_typo3conf . 'l10n/' . $this->getBackendUser()->uc['lang']))) {
653 $languageUnavailableWarning = 'The selected language "' . $this->getLanguageService()->getLL(('lang_' . $this->getBackendUser()->uc['lang']), TRUE) . '" is not available before the language files are installed.<br />' . ($this->getBackendUser()->isAdmin() ? 'You can use the Language module to easily download new language files.' : 'Please ask your system administrator to do this.');
654 $languageUnavailableMessage = GeneralUtility::makeInstance(FlashMessage::class, $languageUnavailableWarning, '', FlashMessage::WARNING);
655 $languageCode = $languageUnavailableMessage->render() . $languageCode;
656 }
657 return $languageCode;
658 }
659
660 /**
661 * Returns a select with all modules for startup
662 *
663 * @return string Complete select as HTML string
664 */
665 public function renderStartModuleSelect($params, $pObj) {
666 $startModuleSelect = '<option value="">' . $this->getLanguageService()->getLL('startModule.firstInMenu', TRUE) . '</option>';
667 foreach ($pObj->loadModules->modules as $mainMod => $modData) {
668 if (!empty($modData['sub']) && is_array($modData['sub'])) {
669 $modules = '';
670 foreach ($modData['sub'] as $subData) {
671 $modName = $subData['name'];
672 $modules .= '<option value="' . htmlspecialchars($modName) . '"';
673 $modules .= $this->getBackendUser()->uc['startModule'] === $modName ? ' selected="selected"' : '';
674 $modules .= '>' . $this->getLanguageService()->moduleLabels['tabs'][$modName . '_tab'] . '</option>';
675 }
676 $groupLabel = $this->getLanguageService()->moduleLabels['tabs'][$mainMod . '_tab'];
677 $startModuleSelect .= '<optgroup label="' . htmlspecialchars($groupLabel) . '">' . $modules . '</optgroup>';
678 }
679 }
680 return '<select id="field_startModule" name="data[startModule]" class="form-control">' . $startModuleSelect . '</select>';
681 }
682
683 /**
684 * Will make the simulate-user selector if the logged in user is administrator.
685 * It will also set the GLOBAL(!) BE_USER to the simulated user selected if any (and set $this->OLD_BE_USER to logged in user)
686 *
687 * @return void
688 */
689 public function simulateUser() {
690 // If admin, allow simulation of another user
691 $this->simUser = 0;
692 $this->simulateSelector = '';
693 unset($this->OLD_BE_USER);
694 if ($this->getBackendUser()->isAdmin()) {
695 $this->simUser = (int)GeneralUtility::_GP('simUser');
696 // Make user-selector:
697 $db = $this->getDatabaseConnection();
698 $where = 'AND username NOT LIKE ' . $db->fullQuoteStr($db->escapeStrForLike('_cli_', 'be_users') . '%', 'be_users');
699 $where .= ' AND uid <> ' . (int)$this->getBackendUser()->user['uid'] . BackendUtility::BEenableFields('be_users');
700 $users = BackendUtility::getUserNames('username,usergroup,usergroup_cached_list,uid,realName', $where);
701 $opt = array();
702 foreach ($users as $rr) {
703 $label = htmlspecialchars(($rr['username'] . ($rr['realName'] ? ' (' . $rr['realName'] . ')' : '')));
704 $opt[] = '<option value="' . $rr['uid'] . '"' . ($this->simUser == $rr['uid'] ? ' selected="selected"' : '') . '>' . $label . '</option>';
705 }
706 if (!empty($opt)) {
707 $this->simulateSelector = '<select id="field_simulate" name="simulateUser" onchange="window.location.href=' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('user_setup') . '&simUser=') . '+this.options[this.selectedIndex].value;"><option></option>' . implode('', $opt) . '</select>';
708 }
709 }
710 // This can only be set if the previous code was executed.
711 if ($this->simUser > 0) {
712 // Save old user...
713 $this->OLD_BE_USER = $this->getBackendUser();
714 unset($GLOBALS['BE_USER']);
715 // Unset current
716 // New backend user object
717 $BE_USER = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class);
718 $BE_USER->setBeUserByUid($this->simUser);
719 $BE_USER->fetchGroupData();
720 $BE_USER->backendSetUC();
721 // Must do this, because unsetting $BE_USER before apparently unsets the reference to the global variable by this name!
722 $GLOBALS['BE_USER'] = $BE_USER;
723 }
724 }
725
726 /**
727 * Render simulate user select and label
728 *
729 * @return string
730 */
731 protected function renderSimulateUserSelectAndLabel() {
732 if ($this->simulateSelector === '') {
733 return '';
734 }
735
736 return '<p>' .
737 '<label for="field_simulate" style="margin-right: 20px;">' .
738 $this->getLanguageService()->sL('LLL:EXT:setup/Resources/Private/Language/locallang.xlf:simulate') .
739 '</label>' .
740 $this->simulateSelector .
741 '</p>';
742 }
743
744 /**
745 * Returns access check (currently only "admin" is supported)
746 *
747 * @param array $config Configuration of the field, access mode is defined in key 'access'
748 * @return bool Whether it is allowed to modify the given field
749 */
750 protected function checkAccess(array $config) {
751 $access = $config['access'];
752
753 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['setup']['accessLevelCheck'][$access])) {
754 if (class_exists($access)) {
755 $accessObject = GeneralUtility::makeInstance($access);
756 if (method_exists($accessObject, 'accessLevelCheck')) {
757 // Initialize vars. If method fails, $set will be set to FALSE
758 return $accessObject->accessLevelCheck($config);
759 }
760 }
761 } elseif ($access == 'admin') {
762 return $this->isAdmin;
763 }
764
765 return FALSE;
766 }
767
768 /**
769 * Returns the label $str from getLL() and grays out the value if the $str/$key is found in $this->overrideConf array
770 *
771 * @param string $str Locallang key
772 * @param string $key Alternative override-config key
773 * @param bool $addLabelTag Defines whether the string should be wrapped in a <label> tag.
774 * @param string $altLabelTagId Alternative id for use in "for" attribute of <label> tag. By default the $str key is used prepended with "field_".
775 * @return string HTML output.
776 */
777 protected function getLabel($str, $key = '', $addLabelTag = TRUE, $altLabelTagId = '') {
778 if (substr($str, 0, 4) === 'LLL:') {
779 $out = $this->getLanguageService()->sL($str);
780 } else {
781 $out = htmlspecialchars($str);
782 }
783 if (isset($this->overrideConf[$key ?: $str])) {
784 $out = '<span style="color:#999999">' . $out . '</span>';
785 }
786 if ($addLabelTag) {
787 $out = '<label for="' . ($altLabelTagId ?: 'field_' . $key) . '">' . $out . '</label>';
788 }
789 return $out;
790 }
791
792 /**
793 * Returns the CSH Icon for given string
794 *
795 * @param string $str Locallang key
796 * @param string $label The label to be used, that should be wrapped in help
797 * @return string HTML output.
798 */
799 protected function getCSH($str, $label) {
800 $context = '_MOD_user_setup';
801 $field = $str;
802 $strParts = explode(':', $str);
803 if (count($strParts) > 1) {
804 // Setting comes from another extension
805 $context = $strParts[0];
806 $field = $strParts[1];
807 } elseif (!GeneralUtility::inList('language,simuser,reset', $str)) {
808 $field = 'option_' . $str;
809 }
810 return BackendUtility::wrapInHelp($context, $field, $label);
811 }
812
813 /**
814 * Returns array with fields defined in $GLOBALS['TYPO3_USER_SETTINGS']['showitem']
815 *
816 * @return array Array with fieldnames visible in form
817 */
818 protected function getFieldsFromShowItem() {
819 return GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_USER_SETTINGS']['showitem'], TRUE);
820 }
821
822 /**
823 * Returns the current BE user.
824 *
825 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
826 */
827 protected function getBackendUser() {
828 return $GLOBALS['BE_USER'];
829 }
830
831 /**
832 * Returns LanguageService
833 *
834 * @return \TYPO3\CMS\Lang\LanguageService
835 */
836 protected function getLanguageService() {
837 return $GLOBALS['LANG'];
838 }
839
840 /**
841 * @return DatabaseConnection
842 */
843 protected function getDatabaseConnection() {
844 return $GLOBALS['TYPO3_DB'];
845 }
846
847 }