tryLoadCompiledContainer($basePath, $collector); // if ($optimizedContainer !== null) { // return $optimizedContainer; // } // Fallback to fresh container bootstrap return $this->bootstrapFreshContainer($basePath, $collector); } /** * Try to load compiled container if valid */ private function tryLoadCompiledContainer( string $basePath, PerformanceCollectorInterface $collector ): ?Container { try { $cacheDir = sys_get_temp_dir() . '/framework-cache'; $compiledPath = ContainerCompiler::getCompiledContainerPath($cacheDir); // Quick existence check first if (! file_exists($compiledPath)) { return null; } // Create temporary fresh container to validate against $tempContainer = $this->createFreshContainer($basePath, $collector); // Create compiler for validation $reflectionProvider = new CachedReflectionProvider(); $dependencyResolver = new DependencyResolver($reflectionProvider, $tempContainer); $compiler = new ContainerCompiler($reflectionProvider, $dependencyResolver); // Validate compiled container if (! $compiler->isCompiledContainerValid($tempContainer, $compiledPath)) { return null; // Invalid, will trigger fresh bootstrap } // Load and return compiled container $compiledContainer = ContainerCompiler::load($compiledPath); // Add runtime instances that can't be compiled $this->addRuntimeInstances($compiledContainer, $basePath, $collector); return $compiledContainer; } catch (\ParseError $e) { // Parse error in compiled container - delete cache and fallback $this->clearCompiledCache($compiledPath); error_log("Compiled container has syntax error, deleted cache: " . $e->getMessage()); return null; } catch (\Exception $e) { // Any other error means we fallback to fresh container return null; } } /** * Bootstrap fresh container and compile for next request */ private function bootstrapFreshContainer( string $basePath, PerformanceCollectorInterface $collector ): Container { $container = $this->createFreshContainer($basePath, $collector); // Compile for next request (async in production) $this->compileContainerAsync($container); return $container; } /** * Create fresh container with all bindings */ private function createFreshContainer( string $basePath, PerformanceCollectorInterface $collector ): DefaultContainer { // Use the existing container or create new DefaultContainer $container = $this->container instanceof DefaultContainer ? $this->container : new DefaultContainer(); $this->addRuntimeInstances($container, $basePath, $collector); $this->autowire($container); return $container; } /** * Add instances that must be created at runtime */ private function addRuntimeInstances( Container $container, string $basePath, PerformanceCollectorInterface $collector ): void { // Core services that need runtime data $container->instance(Logger::class, new DefaultLogger()); $container->instance(PerformanceCollectorInterface::class, $collector); $container->instance(Cache::class, new CacheInitializer($collector, $container)()); $container->instance(PathProvider::class, new PathProvider($basePath)); $container->instance(ResponseEmitter::class, new ResponseEmitter()); $container->instance(Clock::class, new SystemClock()); // TEMPORARY FIX: Manual RequestFactory binding until Discovery issue is resolved $container->singleton(\App\Framework\Http\Request::class, function ($container) { error_log("ContainerBootstrapper: Creating Request singleton"); // Get Cache from container (it was just registered above) $frameworkCache = $container->get(\App\Framework\Cache\Cache::class); $parserCache = new \App\Framework\Http\Parser\ParserCache($frameworkCache); $parser = new \App\Framework\Http\Parser\HttpRequestParser($parserCache); $factory = new \App\Framework\Http\RequestFactory($parser); error_log("ContainerBootstrapper: About to call factory->createFromGlobals()"); $request = $factory->createFromGlobals(); error_log("ContainerBootstrapper: Request created successfully"); return $request; }); // TEMPORARY FIX: Manual DatabasePlatform binding until Initializer Discovery issue is resolved $container->singleton(\App\Framework\Database\Platform\DatabasePlatform::class, function ($container) { error_log("ContainerBootstrapper: Creating DatabasePlatform singleton"); $env = $container->get(\App\Framework\Config\Environment::class); $driver = $env->get('DB_DRIVER', 'pgsql'); error_log("ContainerBootstrapper: DB_DRIVER = {$driver}"); $platform = match($driver) { 'mysql', 'mysqli' => new \App\Framework\Database\Platform\MySQLPlatform(), 'pgsql', 'postgres', 'postgresql' => new \App\Framework\Database\Platform\PostgreSQLPlatform(), 'sqlite' => throw new \RuntimeException('SQLite platform not yet implemented'), default => throw new \RuntimeException("Unsupported database driver: {$driver}") }; error_log("ContainerBootstrapper: DatabasePlatform created: " . get_class($platform)); return $platform; }); } /** * Compile container asynchronously for next request */ private function compileContainerAsync(DefaultContainer $container): void { try { $cacheDir = sys_get_temp_dir() . '/framework-cache'; $compiledPath = ContainerCompiler::getCompiledContainerPath($cacheDir); $reflectionProvider = new CachedReflectionProvider(); $dependencyResolver = new DependencyResolver($reflectionProvider, $container); $compiler = new ContainerCompiler($reflectionProvider, $dependencyResolver); // Compile (async in production, sync in development) #$isProduction = $this->config->get('app.environment') === 'production'; $isProduction = false; if ($isProduction) { $compiler->compileAsync($container, $compiledPath); } else { $compiler->compile($container, $compiledPath); } } catch (\Exception $e) { // Compilation errors should not break the application // In production, log this error } } private function autowire(Container $container): void { // Discovery service bootstrapping $clock = $container->get(Clock::class); // Create a simple logger for Discovery phase // In MCP mode, use NullHandler to suppress output $isMcpMode = getenv('MCP_SERVER_MODE') === '1'; $handlers = $isMcpMode ? [new \App\Framework\Logging\Handlers\NullHandler()] : [new \App\Framework\Logging\Handlers\ConsoleHandler()]; $logger = new \App\Framework\Logging\DefaultLogger( minLevel: \App\Framework\Logging\LogLevel::DEBUG, handlers: $handlers, processorManager: new \App\Framework\Logging\ProcessorManager(), contextManager: new \App\Framework\Logging\LogContextManager() ); $bootstrapper = new DiscoveryServiceBootstrapper($container, $clock, $logger); $results = $bootstrapper->bootstrap(); } /** * Clear compiled container cache files */ private function clearCompiledCache(string $compiledPath): void { try { // Delete the compiled container file if (file_exists($compiledPath)) { @unlink($compiledPath); } // Also clear related cache directory if it exists $cacheDir = dirname($compiledPath); if (is_dir($cacheDir)) { // Clear all cache files in the directory $files = glob($cacheDir . '/*'); foreach ($files as $file) { if (is_file($file)) { @unlink($file); } } } } catch (\Throwable $e) { // Ignore cache cleanup errors, just log them error_log("Error clearing compiled cache: " . $e->getMessage()); } } }