- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
333 lines
11 KiB
PHP
333 lines
11 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Database;
|
|
|
|
use App\Framework\Cache\Cache;
|
|
use App\Framework\Database\Cache\CacheAdapterStrategy;
|
|
use App\Framework\Database\Cache\CacheStrategy;
|
|
use App\Framework\Database\Cache\SimpleCacheStrategy;
|
|
use App\Framework\Database\Driver\Driver;
|
|
use App\Framework\Database\Driver\DriverConfig;
|
|
use App\Framework\Database\Driver\DriverType;
|
|
use App\Framework\Database\Driver\MysqlDriver;
|
|
use App\Framework\Database\Driver\PostgresDriver;
|
|
use App\Framework\Database\Driver\SqliteDriver;
|
|
use App\Framework\Database\Exception\DatabaseException;
|
|
use App\Framework\Database\Middleware\CacheMiddleware;
|
|
use App\Framework\Database\Middleware\HealthCheckMiddleware;
|
|
use App\Framework\Database\Middleware\MiddlewarePipeline;
|
|
use App\Framework\Database\Middleware\RetryMiddleware;
|
|
use Pdo\Mysql;
|
|
use Pdo\Pgsql;
|
|
use Pdo\Sqlite;
|
|
|
|
final readonly class DatabaseFactory
|
|
{
|
|
public static function createConnection(
|
|
array|DriverConfig $config,
|
|
array $middlewareConfig = []
|
|
): ConnectionInterface {
|
|
$lazy = $middlewareConfig['lazy'] ?? false;
|
|
$retry = $middlewareConfig['retry'] ?? false;
|
|
$healthCheck = $middlewareConfig['health_check'] ?? false;
|
|
$cache = $middlewareConfig['cache'] ?? false;
|
|
|
|
if (! $lazy && ! $retry && ! $healthCheck && ! $cache) {
|
|
// Keine Middleware - direkte Verbindung
|
|
return self::createDirectConnection($config);
|
|
}
|
|
|
|
// Base Connection erstellen
|
|
if ($lazy) {
|
|
$baseConnection = LazyConnectionFactory::createLazyGhost($config);
|
|
} else {
|
|
$baseConnection = self::createDirectConnection($config);
|
|
}
|
|
|
|
// Middleware-Pipeline erstellen
|
|
$pipeline = new MiddlewarePipeline();
|
|
|
|
if ($cache) {
|
|
$cacheConfig = is_array($cache) ? $cache : [];
|
|
$cacheStrategy = self::createCacheStrategy($cacheConfig);
|
|
|
|
$pipeline->add(new CacheMiddleware(
|
|
$cacheStrategy,
|
|
$cacheConfig['ttl'] ?? 300,
|
|
$cacheConfig['enabled'] ?? true,
|
|
$cacheConfig['cacheable_operations'] ?? ['query', 'queryOne', 'queryColumn', 'queryScalar']
|
|
));
|
|
}
|
|
|
|
if ($retry) {
|
|
$retryConfig = is_array($retry) ? $retry : [];
|
|
$pipeline->add(new RetryMiddleware(
|
|
$retryConfig['max_retries'] ?? 3,
|
|
$retryConfig['delay_ms'] ?? 100,
|
|
$retryConfig['retryable_exceptions'] ?? [\PDOException::class, DatabaseException::class]
|
|
));
|
|
}
|
|
|
|
if ($healthCheck) {
|
|
$healthConfig = is_array($healthCheck) ? $healthCheck : [];
|
|
$pipeline->add(new HealthCheckMiddleware(
|
|
$healthConfig['interval'] ?? 30,
|
|
$healthConfig['enabled'] ?? true
|
|
));
|
|
}
|
|
|
|
// Wenn Pipeline leer ist, gib direkt die Base Connection zurück
|
|
if (empty($pipeline->getMiddleware())) {
|
|
return $baseConnection;
|
|
}
|
|
|
|
return new MiddlewareConnection($baseConnection, $pipeline);
|
|
}
|
|
|
|
public static function createDirectConnection(array|DriverConfig $config): ConnectionInterface
|
|
{
|
|
if (is_array($config)) {
|
|
$config = DriverConfig::fromArray($config);
|
|
}
|
|
|
|
$driver = self::createDriver($config);
|
|
$pdo = self::createPdo($driver);
|
|
|
|
return new PdoConnection($pdo);
|
|
}
|
|
|
|
public static function createLazyConnection(
|
|
array|DriverConfig $config,
|
|
array $additionalMiddleware = []
|
|
): ConnectionInterface {
|
|
return self::createConnection($config, array_merge(
|
|
['lazy' => true],
|
|
$additionalMiddleware
|
|
));
|
|
}
|
|
|
|
public static function createRetryableConnection(
|
|
array|DriverConfig $config,
|
|
int $maxRetries = 3,
|
|
int $retryDelayMs = 100
|
|
): ConnectionInterface {
|
|
return self::createConnection($config, [
|
|
'retry' => [
|
|
'max_retries' => $maxRetries,
|
|
'delay_ms' => $retryDelayMs,
|
|
],
|
|
]);
|
|
}
|
|
|
|
public static function createRobustConnection(
|
|
array|DriverConfig $config,
|
|
array $middlewareConfig = []
|
|
): ConnectionInterface {
|
|
// Standard "robuste" Konfiguration
|
|
$defaultConfig = [
|
|
'lazy' => true,
|
|
'retry' => [
|
|
'max_retries' => 3,
|
|
'delay_ms' => 100,
|
|
],
|
|
'health_check' => [
|
|
'interval' => 30,
|
|
'enabled' => true,
|
|
],
|
|
];
|
|
|
|
return self::createConnection($config, array_merge($defaultConfig, $middlewareConfig));
|
|
}
|
|
|
|
public static function createPureLazyConnection(array|DriverConfig $config): ConnectionInterface
|
|
{
|
|
// Reine LazyGhost-Connection ohne zusätzliche Middleware
|
|
return LazyConnectionFactory::createLazyGhost($config);
|
|
}
|
|
|
|
public static function isLazyConnection(ConnectionInterface $connection): bool
|
|
{
|
|
if ($connection instanceof MiddlewareConnection) {
|
|
$baseConnection = $connection->getBaseConnection();
|
|
|
|
return LazyConnectionFactory::isLazyGhost($baseConnection);
|
|
}
|
|
|
|
return LazyConnectionFactory::isLazyGhost($connection);
|
|
}
|
|
|
|
public static function forceLazyInitialization(ConnectionInterface $connection): void
|
|
{
|
|
if ($connection instanceof MiddlewareConnection) {
|
|
$baseConnection = $connection->getBaseConnection();
|
|
if (LazyConnectionFactory::isLazyGhost($baseConnection)) {
|
|
LazyConnectionFactory::initializeLazyGhost($baseConnection);
|
|
}
|
|
} elseif (LazyConnectionFactory::isLazyGhost($connection)) {
|
|
LazyConnectionFactory::initializeLazyGhost($connection);
|
|
}
|
|
}
|
|
|
|
private static function createCacheStrategy(array $config): CacheStrategy
|
|
{
|
|
// Verwende direktes CacheInterface oder fallback zu ArrayCache
|
|
$keyPrefix = $config['prefix'] ?? 'db_query:';
|
|
$tags = $config['tags'] ?? ['database_query'];
|
|
|
|
// Wenn eine CacheInterface-Instanz direkt übergeben wird
|
|
if (isset($config['cache_instance']) && $config['cache_instance'] instanceof Cache) {
|
|
return new CacheAdapterStrategy($config['cache_instance'], $keyPrefix);
|
|
}
|
|
|
|
// Fallback zu einfacher Array-basierter Implementierung
|
|
return new SimpleCacheStrategy($keyPrefix);
|
|
}
|
|
|
|
/**
|
|
* Erstelle Cache-Strategy mit direkter CacheInterface-Instanz
|
|
*/
|
|
public static function createCacheStrategyFromCache(
|
|
Cache $cache,
|
|
string $keyPrefix = 'db_query:',
|
|
array $tags = ['database_query']
|
|
): CacheStrategy {
|
|
return CacheAdapterStrategy::withTags($cache, $tags, $keyPrefix);
|
|
}
|
|
|
|
public static function createCachedConnection(
|
|
array|DriverConfig $config,
|
|
array $cacheConfig = []
|
|
): ConnectionInterface {
|
|
return self::createConnection($config, [
|
|
'cache' => array_merge([
|
|
'ttl' => 300,
|
|
'enabled' => true,
|
|
'prefix' => 'db_query:',
|
|
'tags' => ['database_query'],
|
|
], $cacheConfig),
|
|
]);
|
|
}
|
|
|
|
public static function createCachedConnectionWithCache(
|
|
array|DriverConfig $config,
|
|
Cache $cache,
|
|
array $additionalConfig = []
|
|
): ConnectionInterface {
|
|
return self::createCachedConnection($config, array_merge([
|
|
'cache_instance' => $cache,
|
|
], $additionalConfig));
|
|
}
|
|
|
|
/**
|
|
* Erstelle Connection mit externem Cache-System
|
|
*/
|
|
public static function createConnectionWithCustomCache(
|
|
array|DriverConfig $config,
|
|
Cache $cache,
|
|
string $keyPrefix = 'db_query:',
|
|
int $ttl = 300
|
|
): ConnectionInterface {
|
|
return self::createConnection($config, [
|
|
'cache' => [
|
|
'cache_instance' => $cache,
|
|
'prefix' => $keyPrefix,
|
|
'ttl' => $ttl,
|
|
'enabled' => true,
|
|
],
|
|
]);
|
|
}
|
|
|
|
public static function createFullFeaturedConnection(
|
|
array|DriverConfig $config,
|
|
array $middlewareConfig = []
|
|
): ConnectionInterface {
|
|
// "Alles dabei" - Connection mit allen Features
|
|
$defaultConfig = [
|
|
'lazy' => true,
|
|
'cache' => [
|
|
'ttl' => 300,
|
|
'enabled' => true,
|
|
'prefix' => 'db_query:',
|
|
'tags' => ['database_query'],
|
|
],
|
|
'retry' => [
|
|
'max_retries' => 3,
|
|
'delay_ms' => 100,
|
|
],
|
|
'health_check' => [
|
|
'interval' => 30,
|
|
'enabled' => true,
|
|
],
|
|
];
|
|
|
|
return self::createConnection($config, array_merge($defaultConfig, $middlewareConfig));
|
|
}
|
|
|
|
public static function createProductionConnection(
|
|
array|DriverConfig $config,
|
|
?Cache $cache = null,
|
|
array $middlewareConfig = []
|
|
): ConnectionInterface {
|
|
// Production-optimierte Konfiguration
|
|
$defaultConfig = [
|
|
'lazy' => true,
|
|
'cache' => [
|
|
'ttl' => 1800,
|
|
'enabled' => true,
|
|
'prefix' => 'prod_db:',
|
|
'tags' => ['database_query', 'production'],
|
|
],
|
|
'retry' => [
|
|
'max_retries' => 5,
|
|
'delay_ms' => 200,
|
|
],
|
|
'health_check' => [
|
|
'interval' => 60,
|
|
'enabled' => true,
|
|
],
|
|
];
|
|
|
|
// Wenn externe Cache-Instanz übergeben wird
|
|
if ($cache !== null) {
|
|
$defaultConfig['cache']['cache_instance'] = $cache;
|
|
}
|
|
|
|
return self::createConnection($config, array_merge($defaultConfig, $middlewareConfig));
|
|
}
|
|
|
|
private static function createDriver(DriverConfig $config): Driver
|
|
{
|
|
return match($config->driverType) {
|
|
DriverType::MYSQL => new MysqlDriver($config),
|
|
DriverType::PGSQL => new PostgresDriver($config),
|
|
DriverType::SQLITE => new SqliteDriver($config),
|
|
};
|
|
}
|
|
|
|
private static function createPdo(Driver $driver): \PDO
|
|
{
|
|
return match($driver->config->driverType) {
|
|
DriverType::MYSQL => new Mysql(
|
|
$driver->dsn,
|
|
$driver->config->username,
|
|
$driver->config->password,
|
|
$driver->options
|
|
),
|
|
DriverType::PGSQL => new Pgsql(
|
|
$driver->dsn,
|
|
$driver->config->username,
|
|
$driver->config->password,
|
|
$driver->options
|
|
),
|
|
DriverType::SQLITE => new Sqlite(
|
|
$driver->dsn,
|
|
$driver->config->username,
|
|
$driver->config->password,
|
|
$driver->options
|
|
),
|
|
};
|
|
}
|
|
}
|