‪TYPO3CMS  ‪main
SetupService.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
35 
41 readonly class ‪SetupService
42 {
43  public function ‪__construct(
44  private ConfigurationManager $configurationManager,
45  private ‪SiteWriter $siteWriter,
46  private ‪YamlFileLoader $yamlFileLoader,
47  ) {}
48 
49  public function ‪setSiteName(string $name): bool
50  {
51  return $this->configurationManager->setLocalConfigurationValueByPath('SYS/sitename', $name);
52  }
53 
58  public function ‪createSiteConfiguration(string ‪$identifier, int $rootPageId, string $siteUrl): void
59  {
60  // Create a default site configuration called "main" as best practice
61  $this->siteWriter->createNewBasicSite(‪$identifier, $rootPageId, $siteUrl);
62  }
63 
75  private function ‪getHashedPassword(string $password): string
76  {
77  $okHashMethods = [
78  Argon2iPasswordHash::class,
79  Argon2idPasswordHash::class,
80  BcryptPasswordHash::class,
81  ];
82  foreach ($okHashMethods as $className) {
84  $instance = GeneralUtility::makeInstance($className);
85  if ($instance->isAvailable()) {
86  return $instance->getHashedPassword($password);
87  }
88  }
89  // Should never happen since bcrypt is always available
90  throw new ‪InvalidPasswordHashException('No suitable hash method found', 1533988846);
91  }
92 
98  public function ‪createUser(string $username, string $password, string $email = ''): void
99  {
100  $adminUserFields = [
101  'username' => $username,
102  'password' => $this->‪getHashedPassword($password),
103  'email' => GeneralUtility::validEmail($email) ? $email : '',
104  'admin' => 1,
105  'tstamp' => ‪$GLOBALS['EXEC_TIME'],
106  'crdate' => ‪$GLOBALS['EXEC_TIME'],
107  ];
108 
109  $databaseConnection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('be_users');
110  $databaseConnection->insert('be_users', $adminUserFields);
111  $adminUserUid = (int)$databaseConnection->lastInsertId();
112 
113  $maintainerIds = $this->configurationManager->getConfigurationValueByPath('SYS/systemMaintainers') ?? [];
114  sort($maintainerIds);
115  $maintainerIds[] = $adminUserUid;
116  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs([
117  'SYS/systemMaintainers' => array_unique($maintainerIds),
118  ]);
119  }
120 
121  public function ‪setInstallToolPassword(string $password): bool
122  {
123  return $this->configurationManager->setLocalConfigurationValuesByPathValuePairs([
124  'BE/installToolPassword' => $this->‪getHashedPassword($password),
125  ]);
126  }
127 
131  public function ‪prepareSystemSettings(bool $forceOverwrite = false): void
132  {
133  $configurationFileLocation = $this->configurationManager->getSystemConfigurationFileLocation();
134  if (!$forceOverwrite && @is_file($configurationFileLocation)) {
136  'Configuration file ' . $configurationFileLocation . ' already exists!',
137  1669747685,
138  );
139  }
140 
141  // @todo Remove once LocalConfiguration.php support was dropped.
142  // @todo Web installer creates default configuration based on default factory configuration. Recheck if we
143  // should use this here too instead of an empty array.
144  // Ugly hack to write system/settings.php, to avoid fallback to
145  // LocalConfiguration.php causing issues because it does not exist!
146  @unlink($configurationFileLocation);
147  $this->configurationManager->writeLocalConfiguration([]);
148 
149  // Get best matching configuration presets
150  $featureManager = new ‪FeatureManager();
151  $configurationValues = $featureManager->getBestMatchingConfigurationForAllFeatures();
152  $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($configurationValues);
153 
154  $randomKey = GeneralUtility::makeInstance(Random::class)->generateRandomHexString(96);
155  $this->configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $randomKey);
156  $this->configurationManager->setLocalConfigurationValueByPath('SYS/trustedHostsPattern', '.*.*');
157  }
158 
159  public function ‪createSite(): string
160  {
161  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
162  $databaseConnectionForPages = $connectionPool->getConnectionForTable('pages');
163  $databaseConnectionForPages->insert(
164  'pages',
165  [
166  'pid' => 0,
167  'crdate' => time(),
168  'tstamp' => time(),
169  'title' => 'Home',
170  'slug' => '/',
171  'doktype' => 1,
172  'is_siteroot' => 1,
173  'perms_userid' => 1,
174  'perms_groupid' => 1,
175  'perms_user' => 31,
176  'perms_group' => 31,
177  'perms_everybody' => 1,
178  ]
179  );
180  $pageUid = $databaseConnectionForPages->lastInsertId();
181 
182  // add a root sys_template with fluid_styled_content and a default PAGE typoscript snippet
183  $connectionPool->getConnectionForTable('sys_template')->insert(
184  'sys_template',
185  [
186  'pid' => $pageUid,
187  'crdate' => time(),
188  'tstamp' => time(),
189  'title' => 'Main TypoScript Rendering',
190  'root' => 1,
191  'clear' => 3,
192  'include_static_file' => 'EXT:fluid_styled_content/Configuration/TypoScript/,EXT:fluid_styled_content/Configuration/TypoScript/Styling/',
193  'constants' => '',
194  'config' => 'page = PAGE
195 page.10 = TEXT
196 page.10.value (
197  <div style="width: 800px; margin: 15% auto;">
198  <div style="width: 300px;">
199  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 42"><path d="M60.2 14.4v27h-3.8v-27h-6.7v-3.3h17.1v3.3h-6.6zm20.2 12.9v14h-3.9v-14l-7.7-16.2h4.1l5.7 12.2 5.7-12.2h3.9l-7.8 16.2zm19.5 2.6h-3.6v11.4h-3.8V11.1s3.7-.3 7.3-.3c6.6 0 8.5 4.1 8.5 9.4 0 6.5-2.3 9.7-8.4 9.7m.4-16c-2.4 0-4.1.3-4.1.3v12.6h4.1c2.4 0 4.1-1.6 4.1-6.3 0-4.4-1-6.6-4.1-6.6m21.5 27.7c-7.1 0-9-5.2-9-15.8 0-10.2 1.9-15.1 9-15.1s9 4.9 9 15.1c.1 10.6-1.8 15.8-9 15.8m0-27.7c-3.9 0-5.2 2.6-5.2 12.1 0 9.3 1.3 12.4 5.2 12.4 3.9 0 5.2-3.1 5.2-12.4 0-9.4-1.3-12.1-5.2-12.1m19.9 27.7c-2.1 0-5.3-.6-5.7-.7v-3.1c1 .2 3.7.7 5.6.7 2.2 0 3.6-1.9 3.6-5.2 0-3.9-.6-6-3.7-6H138V24h3.1c3.5 0 3.7-3.6 3.7-5.3 0-3.4-1.1-4.8-3.2-4.8-1.9 0-4.1.5-5.3.7v-3.2c.5-.1 3-.7 5.2-.7 4.4 0 7 1.9 7 8.3 0 2.9-1 5.5-3.3 6.3 2.6.2 3.8 3.1 3.8 7.3 0 6.6-2.5 9-7.3 9"/><path fill="#FF8700" d="M31.7 28.8c-.6.2-1.1.2-1.7.2-5.2 0-12.9-18.2-12.9-24.3 0-2.2.5-3 1.3-3.6C12 1.9 4.3 4.2 1.9 7.2 1.3 8 1 9.1 1 10.6c0 9.5 10.1 31 17.3 31 3.3 0 8.8-5.4 13.4-12.8M28.4.5c6.6 0 13.2 1.1 13.2 4.8 0 7.6-4.8 16.7-7.2 16.7-4.4 0-9.9-12.1-9.9-18.2C24.5 1 25.6.5 28.4.5"/></svg>
200  </div>
201  <h4 style="font-family: sans-serif;">Welcome to a default website made with <a href="https://typo3.org">TYPO3</a></h4>
202  </div>
203 )
204 page.100 = CONTENT
205 page.100 {
206  table = tt_content
207  select {
208  orderBy = sorting
209  where = {#colPos}=0
210  }
211 }
212 ',
213  'description' => 'This is an Empty Site Package TypoScript record.
214 
215 For each website you need a TypoScript record on the main page of your website (on the top level). For better maintenance all TypoScript should be extracted into external files via @import \'EXT:site_myproject/Configuration/TypoScript/setup.typoscript\'',
216  ]
217  );
218 
219  return $pageUid;
220  }
221 
226  public function ‪createBackendUserGroups(bool $createEditor = true, bool $createAdvancedEditor = true): void
227  {
228  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
229  if ($createEditor) {
230  $connectionPool->getConnectionForTable('be_groups')->insert(
231  'be_groups',
232  [
233  'title' => BackendUserGroupType::EDITOR->value,
234  'description' => 'Editors have access to basic content element and modules in the backend.',
235  'tstamp' => time(),
236  'crdate' => time(),
237  ]
238  );
239  $editorGroupUid = (int)$connectionPool->getConnectionForTable('be_groups')->lastInsertId();
240  $editorPermissionPreset = $this->yamlFileLoader->load('EXT:install/Configuration/PermissionPreset/be_groups_editor.yaml');
241  $this->‪applyPermissionPreset($editorPermissionPreset, 'be_groups', $editorGroupUid);
242  }
243  if ($createAdvancedEditor) {
244  $connectionPool->getConnectionForTable('be_groups')->insert(
245  'be_groups',
246  [
247  'title' => BackendUserGroupType::ADVANCED_EDITOR->value,
248  'description' => 'Advanced Editors have access to all content elements and non administrative modules in the backend.',
249  'tstamp' => time(),
250  'crdate' => time(),
251  ]
252  );
253  $advancedEditorGroupUid = (int)$connectionPool->getConnectionForTable('be_groups')->lastInsertId();
254  $advancedEditorPermissionPreset = $this->yamlFileLoader->load('EXT:install/Configuration/PermissionPreset/be_groups_advanced_editor.yaml');
255  $this->‪applyPermissionPreset($advancedEditorPermissionPreset, 'be_groups', $advancedEditorGroupUid);
256  }
257  }
258 
259  private function ‪applyPermissionPreset(array $permissionPreset, string $table, int $recordId): void
260  {
261  $mappedPermissions = [];
262  if (isset($permissionPreset['dbMountpoints']) && is_array($permissionPreset['dbMountpoints'])) {
263  $mappedPermissions['db_mountpoints'] = implode(',', $permissionPreset['dbMountpoints']);
264  }
265  if (isset($permissionPreset['groupMods']) && is_array($permissionPreset['groupMods'])) {
266  $mappedPermissions['groupMods'] = implode(',', $permissionPreset['groupMods']);
267  }
268  if (isset($permissionPreset['pageTypesSelect']) && is_array($permissionPreset['pageTypesSelect'])) {
269  $mappedPermissions['pagetypes_select'] = implode(',', $permissionPreset['pageTypesSelect']);
270  }
271  if (isset($permissionPreset['tablesModify']) && is_array($permissionPreset['tablesModify'])) {
272  $mappedPermissions['tables_modify'] = implode(',', $permissionPreset['tablesModify']);
273  }
274  if (isset($permissionPreset['tablesSelect']) && is_array($permissionPreset['tablesSelect'])) {
275  $mappedPermissions['tables_select'] = implode(',', $permissionPreset['tablesSelect']);
276  }
277  if (isset($permissionPreset['nonExcludeFields']) && is_array($permissionPreset['nonExcludeFields'])) {
278  $nonExcludeFields = [];
279  foreach ($permissionPreset['nonExcludeFields'] as $tableName => ‪$fields) {
280  foreach (‪$fields as $field) {
281  $nonExcludeFields[] = "$tableName:$field";
282  }
283  }
284  if ($nonExcludeFields !== []) {
285  $mappedPermissions['non_exclude_fields'] = implode(',', $nonExcludeFields);
286  }
287  }
288  if (isset($permissionPreset['explicitAllowDeny']) && is_array($permissionPreset['explicitAllowDeny'])) {
289  $explicitAllowDeny = [];
290  foreach ($permissionPreset['explicitAllowDeny'] as $tableName => $columns) {
291  foreach ($columns as $column => $values) {
292  foreach ($values as $value) {
293  $explicitAllowDeny[] = "$tableName:$column:$value";
294  }
295  }
296  }
297  if ($explicitAllowDeny !== []) {
298  $mappedPermissions['explicit_allowdeny'] = implode(',', $explicitAllowDeny);
299  }
300  }
301  if (isset($permissionPreset['availableWidgets']) && is_array($permissionPreset['availableWidgets'])) {
302  $mappedPermissions['availableWidgets'] = implode(',', $permissionPreset['availableWidgets']);
303  }
304  if ($mappedPermissions !== []) {
305  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
306  $connectionPool->getConnectionForTable($table)->update(
307  $table,
308  $mappedPermissions,
309  ['uid' => $recordId]
310  );
311  }
312  }
313 }
‪TYPO3\CMS\Install\Service\SetupService\createBackendUserGroups
‪createBackendUserGroups(bool $createEditor=true, bool $createAdvancedEditor=true)
Definition: SetupService.php:226
‪TYPO3\CMS\Core\Crypto\PasswordHashing\BcryptPasswordHash
Definition: BcryptPasswordHash.php:32
‪TYPO3\CMS\Core\Configuration\Exception\SiteConfigurationWriteException
Definition: SiteConfigurationWriteException.php:27
‪TYPO3\CMS\Install\Configuration\FeatureManager
Definition: FeatureManager.php:30
‪TYPO3\CMS\Core\Crypto\PasswordHashing\InvalidPasswordHashException
Definition: InvalidPasswordHashException.php:25
‪TYPO3\CMS\Install\Service\SetupService\prepareSystemSettings
‪prepareSystemSettings(bool $forceOverwrite=false)
Definition: SetupService.php:131
‪TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException
Definition: ExistingTargetFileNameException.php:23
‪TYPO3\CMS\Install\Service\SetupService\applyPermissionPreset
‪applyPermissionPreset(array $permissionPreset, string $table, int $recordId)
Definition: SetupService.php:259
‪TYPO3\CMS\Install\Service\SetupService
Definition: SetupService.php:42
‪$fields
‪$fields
Definition: pages.php:5
‪TYPO3\CMS\Install\Service\SetupService\setInstallToolPassword
‪setInstallToolPassword(string $password)
Definition: SetupService.php:121
‪TYPO3\CMS\Install\Service\SetupService\__construct
‪__construct(private ConfigurationManager $configurationManager, private SiteWriter $siteWriter, private YamlFileLoader $yamlFileLoader,)
Definition: SetupService.php:43
‪TYPO3\CMS\Core\Configuration\SiteWriter
Definition: SiteWriter.php:39
‪TYPO3\CMS\Install\Service\SetupService\createUser
‪createUser(string $username, string $password, string $email='')
Definition: SetupService.php:98
‪TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader
Definition: YamlFileLoader.php:47
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Install\Service\SetupService\setSiteName
‪setSiteName(string $name)
Definition: SetupService.php:49
‪TYPO3\CMS\Install\Service\SetupService\createSite
‪createSite()
Definition: SetupService.php:159
‪TYPO3\CMS\Core\Crypto\Random
Definition: Random.php:27
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Install\Service\SetupService\createSiteConfiguration
‪createSiteConfiguration(string $identifier, int $rootPageId, string $siteUrl)
Definition: SetupService.php:58
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashInterface
Definition: PasswordHashInterface.php:25
‪TYPO3\CMS\Install\Service
Definition: ClearCacheService.php:16
‪TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2idPasswordHash
Definition: Argon2idPasswordHash.php:31
‪TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2iPasswordHash
Definition: Argon2iPasswordHash.php:31
‪TYPO3\CMS\Install\Service\SetupService\getHashedPassword
‪string getHashedPassword(string $password)
Definition: SetupService.php:75
‪TYPO3\CMS\Install\Command\BackendUserGroupType
‪BackendUserGroupType
Definition: BackendUserGroupType.php:25
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37