TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user