TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,640 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Install\Controller;
|
||||
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
|
||||
use TYPO3\CMS\Backend\Routing\RouteRedirect;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Core\Authentication\CommandLineUserCreation;
|
||||
use TYPO3\CMS\Core\Configuration\ConfigurationManager;
|
||||
use TYPO3\CMS\Core\Core\BootService;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Crypto\HashService;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Schema\Exception\StatementException;
|
||||
use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
|
||||
use TYPO3\CMS\Core\Http\HtmlResponse;
|
||||
use TYPO3\CMS\Core\Http\JsonResponse;
|
||||
use TYPO3\CMS\Core\Imaging\IconRegistry;
|
||||
use TYPO3\CMS\Core\Information\Typo3Version;
|
||||
use TYPO3\CMS\Core\Messaging\FlashMessage;
|
||||
use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
|
||||
use TYPO3\CMS\Core\Middleware\VerifyHostHeader;
|
||||
use TYPO3\CMS\Core\Package\PackageManager;
|
||||
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Configuration\Behavior;
|
||||
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\ConsumableNonce;
|
||||
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\DirectiveHashCollection;
|
||||
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Middleware\PolicyBag;
|
||||
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Scope;
|
||||
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
|
||||
use TYPO3\CMS\Core\Type\Map;
|
||||
use TYPO3\CMS\Core\View\ViewInterface;
|
||||
use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextFactory;
|
||||
use TYPO3\CMS\Fluid\View\FluidViewAdapter;
|
||||
use TYPO3\CMS\Install\Factory\ImportMapFactory;
|
||||
use TYPO3\CMS\Install\FolderStructure\DefaultFactory;
|
||||
use TYPO3\CMS\Install\Service\EnableFileService;
|
||||
use TYPO3\CMS\Install\Service\Exception\ConfigurationDirectoryDoesNotExistException;
|
||||
use TYPO3\CMS\Install\Service\SetupDatabaseService;
|
||||
use TYPO3\CMS\Install\Service\SetupService;
|
||||
use TYPO3\CMS\Install\SystemEnvironment\Check;
|
||||
use TYPO3\CMS\Install\SystemEnvironment\SetupCheck;
|
||||
use TYPO3\CMS\Install\WebserverType;
|
||||
use TYPO3Fluid\Fluid\View\TemplateView as FluidTemplateView;
|
||||
|
||||
/**
|
||||
* Install step controller, dispatcher class of step actions.
|
||||
*
|
||||
* @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API.
|
||||
* @phpstan-import-type Params from DriverManager
|
||||
*/
|
||||
#[Autoconfigure(public: true)]
|
||||
final readonly class InstallerController
|
||||
{
|
||||
use ControllerTrait;
|
||||
|
||||
public function __construct(
|
||||
private BootService $bootService,
|
||||
private ConfigurationManager $configurationManager,
|
||||
private PackageManager $packageManager,
|
||||
private VerifyHostHeader $verifyHostHeader,
|
||||
private FormProtectionFactory $formProtectionFactory,
|
||||
private SetupService $setupService,
|
||||
private SetupDatabaseService $setupDatabaseService,
|
||||
private ImportMapFactory $importMapFactory,
|
||||
private HashService $hashService,
|
||||
private IconRegistry $iconRegistry,
|
||||
private DirectiveHashCollection $directiveHashCollection,
|
||||
private CommandLineUserCreation $commandLineUserCreation,
|
||||
private UriBuilder $uriBuilder,
|
||||
private RenderingContextFactory $renderingContextFactory,
|
||||
private ConnectionPool $connectionPool,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Init action loads <head> with JS initiating further stuff
|
||||
*/
|
||||
public function initAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$bust = $GLOBALS['EXEC_TIME'];
|
||||
if (!Environment::getContext()->isDevelopment()) {
|
||||
$bust = $this->hashService->hmac((new Typo3Version()) . Environment::getProjectPath(), self::class);
|
||||
}
|
||||
$sitePath = $request->getAttribute('normalizedParams')->getSitePath();
|
||||
$importMap = $this->importMapFactory->create($sitePath);
|
||||
$initModule = $importMap->resolveImport('@typo3/install/init-installer.js', true, $sitePath);
|
||||
$view = $this->initializeView($request);
|
||||
$view->assign('bust', $bust);
|
||||
$view->assign('initModule', $initModule);
|
||||
$view->assign('iconCacheIdentifier', sha1($this->iconRegistry->getBackendIconsCacheIdentifier()));
|
||||
$nonce = new ConsumableNonce();
|
||||
$view->assign('importmap', $importMap->render($sitePath, $nonce));
|
||||
|
||||
return new HtmlResponse(
|
||||
$view->render('Installer/Init'),
|
||||
200,
|
||||
[
|
||||
'Content-Security-Policy' => $this->createContentSecurityPolicy()->compile(new PolicyBag(Scope::backend(), new Map(), new Behavior(), $nonce, $this->directiveHashCollection)),
|
||||
'Cache-Control' => 'no-cache, no-store',
|
||||
'Pragma' => 'no-cache',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main layout with progress bar, header
|
||||
*/
|
||||
public function mainLayoutAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$view = $this->initializeView($request);
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
'html' => $view->render('Installer/MainLayout'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render "FIRST_INSTALL file need to exist" view
|
||||
*/
|
||||
public function showInstallerNotAvailableAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$view = $this->initializeView($request);
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
'html' => $view->render('Installer/ShowInstallerNotAvailable'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if "environment and folders" should be shown
|
||||
*/
|
||||
public function checkEnvironmentAndFoldersAction(): ResponseInterface
|
||||
{
|
||||
return new JsonResponse([
|
||||
'success' => @is_file($this->configurationManager->getSystemConfigurationFileLocation()),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render "environment and folders"
|
||||
*/
|
||||
public function showEnvironmentAndFoldersAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$view = $this->initializeView($request);
|
||||
$systemCheckMessageQueue = new FlashMessageQueue('install');
|
||||
$checkMessages = (new Check())->getStatus();
|
||||
foreach ($checkMessages as $message) {
|
||||
$systemCheckMessageQueue->enqueue($message);
|
||||
}
|
||||
$setupCheckMessages = (new SetupCheck())->getStatus();
|
||||
foreach ($setupCheckMessages as $message) {
|
||||
$systemCheckMessageQueue->enqueue($message);
|
||||
}
|
||||
$folderStructureFactory = new DefaultFactory();
|
||||
$structureFacade = $folderStructureFactory->getStructure(WebserverType::fromRequest($request));
|
||||
$structureMessageQueue = $structureFacade->getStatus();
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
'html' => $view->render('Installer/ShowEnvironmentAndFolders'),
|
||||
'environmentStatusErrors' => $systemCheckMessageQueue->getAllMessages(ContextualFeedbackSeverity::ERROR),
|
||||
'environmentStatusWarnings' => $systemCheckMessageQueue->getAllMessages(ContextualFeedbackSeverity::WARNING),
|
||||
'structureErrors' => $structureMessageQueue->getAllMessages(ContextualFeedbackSeverity::ERROR),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create main folder layout, LocalConfiguration, PackageStates
|
||||
*/
|
||||
public function executeEnvironmentAndFoldersAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$errorsFromStructure = $this->setupService->createDirectoryStructure(WebserverType::fromRequest($request));
|
||||
try {
|
||||
$this->setupService->prepareSystemSettings();
|
||||
} catch (ConfigurationDirectoryDoesNotExistException) {
|
||||
return new JsonResponse([
|
||||
'success' => false,
|
||||
'status' => $errorsFromStructure,
|
||||
]);
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if trusted hosts pattern needs to be adjusted
|
||||
*/
|
||||
public function checkTrustedHostsPatternAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$serverParams = $request->getServerParams();
|
||||
$host = $serverParams['HTTP_HOST'] ?? '';
|
||||
|
||||
return new JsonResponse([
|
||||
'success' => $this->verifyHostHeader->isAllowedHostHeaderValue($host, $serverParams),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust trusted hosts pattern to '.*' if it does not match yet
|
||||
*/
|
||||
public function executeAdjustTrustedHostsPatternAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$serverParams = $request->getServerParams();
|
||||
$host = $serverParams['HTTP_HOST'] ?? '';
|
||||
|
||||
if (!$this->verifyHostHeader->isAllowedHostHeaderValue($host, $serverParams)) {
|
||||
$this->configurationManager->setLocalConfigurationValueByPath('SYS/trustedHostsPattern', '.*');
|
||||
}
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if database connect step needs to be shown
|
||||
*/
|
||||
public function checkDatabaseConnectAction(): ResponseInterface
|
||||
{
|
||||
return new JsonResponse([
|
||||
'success' => $this->setupDatabaseService->isDatabaseConfigurationComplete() && $this->setupDatabaseService->isDatabaseConnectSuccessful(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show database connect step
|
||||
*/
|
||||
public function showDatabaseConnectAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$view = $this->initializeView($request);
|
||||
|
||||
$driverOptions = $this->setupDatabaseService->getDriverOptions();
|
||||
$formProtection = $this->formProtectionFactory->createFromRequest($request);
|
||||
$driverOptions['executeDatabaseConnectToken'] = $formProtection->generateToken('installTool', 'executeDatabaseConnect');
|
||||
$view->assignMultiple($driverOptions);
|
||||
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
'html' => $view->render('Installer/ShowDatabaseConnect'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test database connect data
|
||||
*/
|
||||
public function executeDatabaseConnectAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$postValues = $request->getParsedBody()['install']['values'];
|
||||
[$success, $messages] = $this->setupDatabaseService->setDefaultConnectionSettings($postValues);
|
||||
|
||||
return new JsonResponse([
|
||||
'success' => $success,
|
||||
'status' => $messages,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a database needs to be selected
|
||||
*/
|
||||
public function checkDatabaseSelectAction(): ResponseInterface
|
||||
{
|
||||
return new JsonResponse([
|
||||
'success' => $this->setupDatabaseService->checkDatabaseSelect(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render "select a database"
|
||||
*/
|
||||
public function showDatabaseSelectAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$view = $this->initializeView($request);
|
||||
$formProtection = $this->formProtectionFactory->createFromRequest($request);
|
||||
$errors = [];
|
||||
try {
|
||||
$view->assign('databaseList', $this->setupDatabaseService->getDatabaseList());
|
||||
} catch (\Exception $exception) {
|
||||
$errors[] = $exception->getMessage();
|
||||
}
|
||||
$view->assignMultiple([
|
||||
'errors' => $errors,
|
||||
'executeDatabaseSelectToken' => $formProtection->generateToken('installTool', 'executeDatabaseSelect'),
|
||||
'executeCheckDatabaseRequirementsToken' => $formProtection->generateToken('installTool', 'checkDatabaseRequirements'),
|
||||
]);
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
'html' => $view->render('Installer/ShowDatabaseSelect'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-check whether all requirements for the installed database driver and platform are fulfilled
|
||||
*/
|
||||
public function checkDatabaseRequirementsAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$success = true;
|
||||
$messages = [];
|
||||
$databaseDriverName = $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][ConnectionPool::DEFAULT_CONNECTION_NAME]['driver'];
|
||||
|
||||
$databaseName = $this->retrieveDatabaseNameFromRequest($request);
|
||||
if ($databaseName === '') {
|
||||
return new JsonResponse([
|
||||
'success' => false,
|
||||
'status' => [
|
||||
new FlashMessage(
|
||||
'You must select a database.',
|
||||
'No Database selected',
|
||||
ContextualFeedbackSeverity::ERROR
|
||||
),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][ConnectionPool::DEFAULT_CONNECTION_NAME]['dbname'] = $databaseName;
|
||||
|
||||
foreach ($this->setupDatabaseService->checkDatabaseRequirementsForDriver($databaseDriverName) as $message) {
|
||||
if ($message->getSeverity() === ContextualFeedbackSeverity::ERROR) {
|
||||
$success = false;
|
||||
$messages[] = $message;
|
||||
}
|
||||
}
|
||||
|
||||
// Check create and drop permissions
|
||||
$statusMessages = [];
|
||||
foreach ($this->setupDatabaseService->checkRequiredDatabasePermissions() as $checkRequiredPermission) {
|
||||
$statusMessages[] = new FlashMessage(
|
||||
$checkRequiredPermission,
|
||||
'Missing required permissions',
|
||||
ContextualFeedbackSeverity::ERROR
|
||||
);
|
||||
}
|
||||
if ($statusMessages !== []) {
|
||||
return new JsonResponse([
|
||||
'success' => false,
|
||||
'status' => $statusMessages,
|
||||
]);
|
||||
}
|
||||
|
||||
// if requirements are not fulfilled
|
||||
if ($success === false) {
|
||||
// remove the database again if we created it
|
||||
if ($request->getParsedBody()['install']['values']['type'] === 'new') {
|
||||
$connection = $this->connectionPool
|
||||
->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
|
||||
$connection
|
||||
->createSchemaManager()
|
||||
->dropDatabase($connection->quoteIdentifier($databaseName));
|
||||
}
|
||||
|
||||
$this->configurationManager->removeLocalConfigurationKeysByPath(['DB/Connections/Default/dbname']);
|
||||
|
||||
$message = new FlashMessage(
|
||||
sprintf(
|
||||
'Database with name "%s" has been removed due to the following errors. '
|
||||
. 'Please solve them first and try again. If you tried to create a new database make also sure, that the DBMS charset is to use UTF-8',
|
||||
$databaseName
|
||||
),
|
||||
'',
|
||||
ContextualFeedbackSeverity::INFO
|
||||
);
|
||||
array_unshift($messages, $message);
|
||||
}
|
||||
|
||||
unset($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][ConnectionPool::DEFAULT_CONNECTION_NAME]['dbname']);
|
||||
|
||||
return new JsonResponse([
|
||||
'success' => $success,
|
||||
'status' => $messages,
|
||||
]);
|
||||
}
|
||||
|
||||
private function retrieveDatabaseNameFromRequest(ServerRequestInterface $request): string
|
||||
{
|
||||
$postValues = $request->getParsedBody()['install']['values'];
|
||||
if ($postValues['type'] === 'new') {
|
||||
return $postValues['new'];
|
||||
}
|
||||
|
||||
if ($postValues['type'] === 'existing' && !empty($postValues['existing'])) {
|
||||
return $postValues['existing'];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Select / create and test a database
|
||||
*/
|
||||
public function executeDatabaseSelectAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$databaseName = $this->retrieveDatabaseNameFromRequest($request);
|
||||
if ($databaseName === '') {
|
||||
return new JsonResponse([
|
||||
'success' => false,
|
||||
'status' => [
|
||||
new FlashMessage(
|
||||
'You must select a database.',
|
||||
'No Database selected',
|
||||
ContextualFeedbackSeverity::ERROR
|
||||
),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
$postValues = $request->getParsedBody()['install']['values'];
|
||||
if ($postValues['type'] === 'new') {
|
||||
$status = $this->setupDatabaseService->createNewDatabase($databaseName);
|
||||
if ($status->getSeverity() === ContextualFeedbackSeverity::ERROR) {
|
||||
return new JsonResponse([
|
||||
'success' => false,
|
||||
'status' => [$status],
|
||||
]);
|
||||
}
|
||||
} elseif ($postValues['type'] === 'existing') {
|
||||
$status = $this->setupDatabaseService->checkExistingDatabase($databaseName);
|
||||
if ($status->getSeverity() === ContextualFeedbackSeverity::ERROR) {
|
||||
return new JsonResponse([
|
||||
'success' => false,
|
||||
'status' => [$status],
|
||||
]);
|
||||
}
|
||||
}
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if initial data needs to be imported
|
||||
*/
|
||||
public function checkDatabaseDataAction(): ResponseInterface
|
||||
{
|
||||
$existingTables = $this->connectionPool
|
||||
->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME)
|
||||
->createSchemaManager()
|
||||
->listTableNames();
|
||||
return new JsonResponse([
|
||||
'success' => !empty($existingTables),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render "import initial data"
|
||||
*/
|
||||
public function showDatabaseDataAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$view = $this->initializeView($request);
|
||||
$formProtection = $this->formProtectionFactory->createFromRequest($request);
|
||||
$view->assignMultiple([
|
||||
'executeDatabaseDataToken' => $formProtection->generateToken('installTool', 'executeDatabaseData'),
|
||||
]);
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
'html' => $view->render('Installer/ShowDatabaseData'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create main db layout
|
||||
*/
|
||||
public function executeDatabaseDataAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$messages = [];
|
||||
$postValues = $request->getParsedBody()['install']['values'];
|
||||
$username = (string)$postValues['username'] !== '' ? $postValues['username'] : 'admin';
|
||||
// Check password and return early if not good enough
|
||||
$password = (string)($postValues['password'] ?? '');
|
||||
$email = $postValues['email'] ?? '';
|
||||
$passwordValidationErrors = $this->setupDatabaseService->getBackendUserPasswordValidationErrors($password);
|
||||
if (!empty($passwordValidationErrors)) {
|
||||
$messages[] = new FlashMessage(
|
||||
'Administrator password not secure enough!',
|
||||
'',
|
||||
ContextualFeedbackSeverity::ERROR
|
||||
);
|
||||
|
||||
// Add all password validation errors to the messages array
|
||||
foreach ($passwordValidationErrors as $error) {
|
||||
$messages[] = new FlashMessage(
|
||||
$error,
|
||||
'',
|
||||
ContextualFeedbackSeverity::ERROR
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'success' => false,
|
||||
'status' => $messages,
|
||||
]);
|
||||
}
|
||||
// Set site name
|
||||
if (!empty($postValues['sitename'])) {
|
||||
$this->setupService->setSiteName($postValues['sitename']);
|
||||
}
|
||||
try {
|
||||
$messages = $this->setupDatabaseService->importDatabaseData();
|
||||
if (!empty($messages)) {
|
||||
return new JsonResponse([
|
||||
'success' => false,
|
||||
'status' => $messages,
|
||||
]);
|
||||
}
|
||||
} catch (StatementException $exception) {
|
||||
$messages[] = new FlashMessage(
|
||||
'Error detected in SQL statement:' . LF . $exception->getMessage(),
|
||||
'Import of database data could not be performed',
|
||||
ContextualFeedbackSeverity::ERROR
|
||||
);
|
||||
return new JsonResponse([
|
||||
'success' => false,
|
||||
'status' => $messages,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->commandLineUserCreation->ensureCliUserExists();
|
||||
$this->setupService->createUser($username, $password, $email);
|
||||
$this->setupService->setInstallToolPassword($password);
|
||||
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
'status' => $messages,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show last "create site with theme / install distribution"
|
||||
*/
|
||||
public function showDefaultConfigurationAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$view = $this->initializeView($request);
|
||||
$formProtection = $this->formProtectionFactory->createFromRequest($request);
|
||||
$distributions = [];
|
||||
if ($this->packageManager->isPackageActive('impexp')) {
|
||||
$distributions = $this->setupService->getAvailableDistributions();
|
||||
}
|
||||
$view->assignMultiple([
|
||||
'composerMode' => Environment::isComposerMode(),
|
||||
'offerToCreateBasicSite' => $this->packageManager->isPackageActive('fluid_styled_content'),
|
||||
'distributions' => $distributions,
|
||||
'executeDefaultConfigurationToken' => $formProtection->generateToken('installTool', 'executeDefaultConfiguration'),
|
||||
]);
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
'html' => $view->render('Installer/ShowDefaultConfiguration'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Last step execution: clean up, remove FIRST_INSTALL file, ...
|
||||
*/
|
||||
public function executeDefaultConfigurationAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
// Let the admin user redirect to the distributions page on first login
|
||||
$siteSetup = $request->getParsedBody()['install']['values']['sitesetup'] ?? '';
|
||||
$selectedDistribution = '';
|
||||
if (str_starts_with($siteSetup, 'createsite:')) {
|
||||
$selectedDistribution = substr($siteSetup, strlen('createsite:'));
|
||||
$siteSetup = 'activateDistribution';
|
||||
}
|
||||
// It is crucial to activate the package *before* loading the container
|
||||
if ($siteSetup === 'activateDistribution') {
|
||||
// Distribution handles all site creation (pages, content, site configuration)
|
||||
$this->setupService->activateDistributionPackage($selectedDistribution);
|
||||
}
|
||||
$nextStepUrl = $this->uriBuilder->buildUriFromRoute('login');
|
||||
|
||||
if ($siteSetup === 'createsite') {
|
||||
$siteUrl = $request->getAttribute('normalizedParams')->getSiteUrl();
|
||||
$this->setupService->createSite('main', $siteUrl);
|
||||
} elseif ($siteSetup === 'loaddistribution'
|
||||
&& !Environment::isComposerMode()
|
||||
&& $this->packageManager->isPackageActive('extensionmanager')
|
||||
) {
|
||||
// Update the URL to redirect after login to the extension manager distributions list
|
||||
$nextStepUrl = $this->uriBuilder->buildUriWithRedirect(
|
||||
'login',
|
||||
[],
|
||||
RouteRedirect::create(
|
||||
'extensionmanager',
|
||||
[
|
||||
'action' => 'distributions',
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (($request->getParsedBody()['install']['values']['backendgroups'] ?? '') === 'creategroups') {
|
||||
$this->setupService->createBackendUserGroups();
|
||||
}
|
||||
|
||||
$this->bootService->unsetInternalContainerInstance();
|
||||
$container = $this->bootService->loadExtLocalconfDatabase(true);
|
||||
|
||||
// Mark upgrade wizards as done
|
||||
$this->setupDatabaseService->markWizardsDone($container);
|
||||
|
||||
// Set up all installed extensions
|
||||
// (includes e.g. publishing of assets, importing distribution data)
|
||||
$this->setupService->setupExtensions($container);
|
||||
|
||||
$formProtection = $this->formProtectionFactory->createFromRequest($request);
|
||||
$formProtection->clean();
|
||||
|
||||
EnableFileService::removeFirstInstallFile();
|
||||
|
||||
return new JsonResponse([
|
||||
'success' => true,
|
||||
'redirect' => (string)$nextStepUrl,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to initialize a standalone view instance.
|
||||
*/
|
||||
private function initializeView(ServerRequestInterface $request): ViewInterface
|
||||
{
|
||||
$templatePaths = [
|
||||
'templateRootPaths' => ['EXT:install/Resources/Private/Templates'],
|
||||
];
|
||||
$renderingContext = $this->renderingContextFactory->create($templatePaths, $request);
|
||||
$fluidView = new FluidTemplateView($renderingContext);
|
||||
return new FluidViewAdapter($fluidView);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user