242 lines
8.0 KiB
PHP
242 lines
8.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Core;
|
|
|
|
use App\Framework\Config\EncryptedEnvLoader;
|
|
use App\Framework\Config\Environment;
|
|
use App\Framework\Config\EnvironmentType;
|
|
use App\Framework\Config\SecretManager;
|
|
use App\Framework\Config\TypedConfigInitializer;
|
|
use App\Framework\Config\TypedConfiguration;
|
|
use App\Framework\Console\ConsoleApplication;
|
|
use App\Framework\Console\ConsoleOutput;
|
|
use App\Framework\Context\ExecutionContext;
|
|
use App\Framework\Core\Events\EventDispatcher;
|
|
use App\Framework\Core\Events\EventDispatcherInterface;
|
|
use App\Framework\DI\Container;
|
|
use App\Framework\DI\DefaultContainer;
|
|
use App\Framework\Encryption\EncryptionFactory;
|
|
use App\Framework\ErrorHandling\CliErrorHandler;
|
|
use App\Framework\ErrorHandling\ErrorHandler;
|
|
use App\Framework\Http\MiddlewareManager;
|
|
use App\Framework\Http\MiddlewareManagerInterface;
|
|
use App\Framework\Http\ResponseEmitter;
|
|
use App\Framework\Http\ServerEnvironment;
|
|
use App\Framework\Performance\Contracts\PerformanceCollectorInterface;
|
|
use App\Framework\Performance\MemoryMonitor;
|
|
use App\Framework\Performance\PerformanceCategory;
|
|
use App\Framework\Random\RandomGenerator;
|
|
|
|
/**
|
|
* Verantwortlich für die grundlegende Initialisierung der Anwendung
|
|
*/
|
|
final readonly class AppBootstrapper
|
|
{
|
|
private Container $container;
|
|
|
|
private ContainerBootstrapper $bootstrapper;
|
|
|
|
public function __construct(
|
|
private string $basePath,
|
|
private PerformanceCollectorInterface $collector,
|
|
private MemoryMonitor $memoryMonitor = new MemoryMonitor,
|
|
#private array $config = [],
|
|
) {
|
|
$this->container = new DefaultContainer();
|
|
$this->bootstrapper = new ContainerBootstrapper($this->container);
|
|
|
|
// Initialize environment with encryption support
|
|
$env = $this->initializeEnvironment();
|
|
|
|
// Make Environment available throughout the application
|
|
$this->container->instance(Environment::class, $env);
|
|
|
|
$typedConfig = new TypedConfigInitializer($env)($this->container);
|
|
$this->container->instance(TypedConfiguration::class, $typedConfig);
|
|
|
|
|
|
// ExecutionContext detection sollte das erste sein, das nach dem Instanziieren des containers passiert. noch bevor dem bootstrap des containers.
|
|
$executionContext = ExecutionContext::detect($typedConfig->app);
|
|
$this->container->instance(ExecutionContext::class, $executionContext);
|
|
|
|
// Register MemoryMonitor as singleton
|
|
$this->container->singleton(MemoryMonitor::class, $this->memoryMonitor);
|
|
|
|
|
|
|
|
// Only log context in development - production doesn't need this noise
|
|
//$envType = EnvironmentType::fromEnvironment($env);
|
|
|
|
//if ($envType->isDevelopment()) {
|
|
|
|
if($typedConfig->app->type->isDevelopment()) {
|
|
// Fehleranzeige für die Entwicklung aktivieren
|
|
ini_set('display_errors', 1);
|
|
ini_set('display_startup_errors', 1);
|
|
error_reporting(E_ALL);
|
|
|
|
spl_autoload_register(function ($class) {
|
|
if (empty($class)) {
|
|
error_log('Empty class name detected in autoloader. Stack trace: ' .
|
|
json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10)));
|
|
|
|
return false; // Don't throw, just log and continue
|
|
}
|
|
|
|
return false;
|
|
}, true, true);
|
|
}
|
|
}
|
|
|
|
public function bootstrapWeb(): ApplicationInterface
|
|
{
|
|
$this->bootstrap();
|
|
$this->registerWebErrorHandler();
|
|
$this->registerApplication();
|
|
|
|
$mm = $this->container->get(MiddlewareManager::class);
|
|
$this->container->instance(MiddlewareManagerInterface::class, $mm);
|
|
|
|
$ed = $this->container->get(EventDispatcher::class);
|
|
$this->container->instance(EventDispatcherInterface::class, $ed);
|
|
|
|
return $this->container->get(ApplicationInterface::class);
|
|
}
|
|
|
|
public function bootstrapConsole(): ConsoleApplication
|
|
{
|
|
$this->bootstrap();
|
|
$this->registerCliErrorHandler();
|
|
$this->registerConsoleApplication();
|
|
|
|
return $this->container->get(ConsoleApplication::class);
|
|
}
|
|
|
|
public function bootstrapWorker(): Container
|
|
{
|
|
$this->bootstrap();
|
|
$this->registerCliErrorHandler();
|
|
|
|
$ed = $this->container->get(EventDispatcher::class);
|
|
$this->container->instance(EventDispatcherInterface::class, $ed);
|
|
|
|
$consoleOutput = new ConsoleOutput();
|
|
$this->container->instance(ConsoleOutput::class, $consoleOutput);
|
|
|
|
return $this->container;
|
|
}
|
|
|
|
public function bootstrapWebSocket(): Container
|
|
{
|
|
$this->bootstrap();
|
|
$this->registerCliErrorHandler();
|
|
|
|
$consoleOutput = new ConsoleOutput();
|
|
$this->container->instance(ConsoleOutput::class, $consoleOutput);
|
|
|
|
return $this->container;
|
|
}
|
|
|
|
private function bootstrap(): void
|
|
{
|
|
$this->collector->startTiming('bootstrap', PerformanceCategory::SYSTEM);
|
|
|
|
$this->bootstrapper->bootstrap($this->basePath, $this->collector);
|
|
|
|
$this->collector->endTiming('bootstrap');
|
|
|
|
// Initialize secrets management after container is bootstrapped
|
|
$env = $this->container->get(Environment::class);
|
|
$this->initializeSecretsManagement($env);
|
|
|
|
// ErrorHandler wird jetzt kontextabhängig registriert
|
|
// $this->container->get(ErrorHandler::class)->register();
|
|
}
|
|
|
|
private function registerWebErrorHandler(): void
|
|
{
|
|
$this->container->get(ErrorHandler::class)->register();
|
|
}
|
|
|
|
private function registerCliErrorHandler(): void
|
|
{
|
|
$output = $this->container->has(ConsoleOutput::class)
|
|
? $this->container->get(ConsoleOutput::class)
|
|
: new ConsoleOutput();
|
|
|
|
$cliErrorHandler = new CliErrorHandler($output);
|
|
$cliErrorHandler->register();
|
|
}
|
|
|
|
private function registerApplication(): void
|
|
{
|
|
$this->container->singleton(ApplicationInterface::class, function (Container $c) {
|
|
return new Application(
|
|
$c,
|
|
$c->get(ResponseEmitter::class),
|
|
$c->get(TypedConfiguration::class)
|
|
);
|
|
});
|
|
}
|
|
|
|
private function registerConsoleApplication(): void
|
|
{
|
|
$this->container->singleton(ConsoleApplication::class, function (Container $c) {
|
|
return new ConsoleApplication(
|
|
$c,
|
|
'console',
|
|
'My Console App',
|
|
null,
|
|
);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize environment with smart priority handling
|
|
*
|
|
* Uses EnvironmentLoader which orchestrates:
|
|
* - Docker ENV vars loading (via $_ENV, $_SERVER)
|
|
* - .env file loading
|
|
* - Smart priority (Production: Docker ENV > .env, Development: .env > Docker ENV)
|
|
* - Automatic encryption support for .env.secrets
|
|
*/
|
|
private function initializeEnvironment(): Environment
|
|
{
|
|
$loader = new EncryptedEnvLoader();
|
|
|
|
return $loader->load($this->basePath);
|
|
}
|
|
|
|
/**
|
|
* Initialize secrets management after container is bootstrapped
|
|
*/
|
|
private function initializeSecretsManagement(Environment $env): void
|
|
{
|
|
$encryptionKey = $env->get('ENCRYPTION_KEY');
|
|
|
|
if ($encryptionKey === null) {
|
|
return; // No secrets management without encryption key
|
|
}
|
|
|
|
try {
|
|
$randomGenerator = $this->container->get(RandomGenerator::class);
|
|
$serverEnvironment = $this->container->get(ServerEnvironment::class);
|
|
$encryptionFactory = new EncryptionFactory($randomGenerator);
|
|
$encryption = $encryptionFactory->createBest($encryptionKey);
|
|
|
|
$secretManager = new SecretManager(
|
|
$env,
|
|
$encryption,
|
|
$serverEnvironment,
|
|
$randomGenerator
|
|
);
|
|
|
|
$this->container->instance(SecretManager::class, $secretManager);
|
|
} catch (\Throwable $e) {
|
|
error_log("Failed to initialize secrets management: " . $e->getMessage());
|
|
}
|
|
}
|
|
}
|