TYPO3 v15 dev-main snapshot ()

This commit is contained in:
2026-08-10 22:31:31 +02:00
commit 3e43c11539
407 changed files with 51272 additions and 0 deletions
+221
View File
@@ -0,0 +1,221 @@
<?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\Database;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Install\Configuration\Exception;
/**
* Check all required permissions within the install process.
* @internal This is NOT an API class, it is for internal use in the install tool only.
*/
class PermissionsCheck
{
private $testTableName = 't3install_test_table';
private $messages = [];
public function checkCreateAndDrop(): self
{
$tableCreated = $this->checkCreateTable($this->testTableName);
if (!$tableCreated) {
$this->messages[] = 'The database user needs CREATE permissions.';
}
$tableDropped = $this->checkDropTable($this->testTableName);
if (!$tableDropped) {
$this->messages[] = 'The database user needs DROP permissions.';
}
if ($tableCreated && !$tableDropped) {
$this->messages[] = sprintf('Attention: A test table with name "%s" was created but could not be deleted, please remove the table manually!', $this->testTableName);
}
if (!$tableCreated || !$tableDropped) {
throw new Exception('A test table could not be created or dropped, skipping all further checks now', 1590850369);
}
return $this;
}
public function checkAlter(): self
{
$this->checkCreateTable($this->testTableName);
$connection = $this->getConnection();
$schemaManager = $this->createSchemaManager();
$schemaCurrent = $schemaManager->introspectSchema();
$schemaNew = $schemaManager->introspectSchema();
$schemaDiff = $schemaManager->createComparator()->compareSchemas($schemaCurrent, $schemaNew);
$schemaNew
->getTable($this->testTableName)
->addColumn('index_test', 'integer', ['unsigned' => true]);
$platform = $connection->getDatabasePlatform();
try {
foreach ($platform->getAlterSchemaSQL($schemaDiff) as $query) {
$connection->executeQuery($query);
}
} catch (\Exception) {
$this->messages[] = 'The database user needs ALTER permission';
}
$this->checkDropTable($this->testTableName);
return $this;
}
public function checkIndex(): self
{
if ($this->checkCreateTable($this->testTableName)) {
$connection = $this->getConnection();
$schemaManager = $this->createSchemaManager();
$schemaCurrent = $schemaManager->introspectSchema();
$schemaNew = $schemaManager->introspectSchema();
$testTable = $schemaNew->getTable($this->testTableName);
$testTable->addColumn('index_test', 'integer', ['unsigned' => true]);
$testTable->addIndex(['index_test'], 'test_index');
$schemaDiff = $schemaManager->createComparator()->compareSchemas($schemaCurrent, $schemaNew);
$platform = $connection->getDatabasePlatform();
try {
$statements = $platform->getAlterSchemaSQL($schemaDiff);
foreach ($statements as $query) {
$connection->executeQuery($query);
}
} catch (\Exception) {
$this->messages[] = 'The database user needs INDEX permission';
}
$this->checkDropTable($this->testTableName);
}
return $this;
}
public function checkCreateTemporaryTable(): self
{
$this->checkCreateTable($this->testTableName);
$connection = $this->getConnection();
try {
$sql = 'CREATE TEMPORARY TABLE %s AS (SELECT id FROM %s )';
$connection->executeStatement(sprintf($sql, $this->testTableName . '_tmp', $this->testTableName));
} catch (\Exception) {
$this->messages[] = 'The database user needs CREATE TEMPORARY TABLE permission';
}
$this->checkDropTable($this->testTableName);
return $this;
}
public function checkSelect(): self
{
$connection = $this->getConnection();
try {
$connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL());
} catch (\Exception) {
$this->messages[] = 'The database user needs SELECT permission';
}
return $this;
}
public function checkInsert(): self
{
$this->checkCreateTable($this->testTableName);
$connection = $this->getConnection();
try {
$connection->insert($this->testTableName, ['id' => 1]);
} catch (\Exception) {
$this->messages[] = 'The database user needs INSERT permission';
}
$this->checkDropTable($this->testTableName);
return $this;
}
public function checkUpdate(): self
{
$this->checkCreateTable($this->testTableName);
$connection = $this->getConnection();
try {
$connection->insert($this->testTableName, ['id' => 1]);
$connection->update($this->testTableName, ['id' => 2], ['id' => 1]);
} catch (\Exception) {
$this->messages[] = 'The database user needs UPDATE permission';
}
$this->checkDropTable($this->testTableName);
return $this;
}
public function checkDelete(): self
{
$this->checkCreateTable($this->testTableName);
$connection = $this->getConnection();
try {
$connection->insert($this->testTableName, ['id' => 1]);
$connection->delete($this->testTableName, ['id' => 1]);
} catch (\Exception) {
$this->messages[] = 'The database user needs DELETE permission';
}
$this->checkDropTable($this->testTableName);
return $this;
}
public function getMessages(): array
{
return $this->messages;
}
private function checkCreateTable(string $tablename): bool
{
$connection = $this->getConnection();
$schema = $connection->createSchemaManager()->introspectSchema();
$testTable = $schema->createTable($tablename);
$testTable->addColumn('id', 'integer', ['unsigned' => true]);
$testTable->setPrimaryKey(['id']);
$platform = $connection->getDatabasePlatform();
try {
foreach ($schema->toSql($platform) as $query) {
$connection->executeQuery($query);
}
} catch (\Exception) {
return false;
}
return true;
}
private function checkDropTable(string $tablename): bool
{
$connection = $this->getConnection();
try {
$schemaManager = $connection->createSchemaManager();
$schemaCurrent = $schemaManager->introspectSchema();
$schemaNew = $schemaManager->introspectSchema();
$schemaNew->dropTable($tablename);
$schemaDiff = $schemaManager->createComparator()->compareSchemas($schemaCurrent, $schemaNew);
$platform = $connection->getDatabasePlatform();
foreach ($platform->getAlterSchemaSQL($schemaDiff) as $query) {
$connection->executeQuery($query);
}
} catch (\Exception) {
return false;
}
return true;
}
private function getConnection(): Connection
{
// Use plain Doctrine connection to avoid early TYPO3 context dependencies
return DriverManager::getConnection($GLOBALS['TYPO3_CONF_VARS']['DB']['Connections'][ConnectionPool::DEFAULT_CONNECTION_NAME]);
}
private function createSchemaManager(): AbstractSchemaManager
{
return $this->getConnection()->createSchemaManager();
}
}