bind(ErrorBoundaryFactory::class, function (Container $container) { $logger = $container->has(Logger::class) ? $container->get(Logger::class) : null; // Load custom route configurations from environment $routeConfigs = $this->loadRouteConfigs(); return new ErrorBoundaryFactory( logger: $logger, routeConfigs: $routeConfigs ); }); // Default boundary for general use $container->bind(ErrorBoundary::class, function (Container $container) { $factory = $container->get(ErrorBoundaryFactory::class); return $factory->create('default', BoundaryConfig::database()); }); } private function loadRouteConfigs(): array { $configs = []; // Load from environment variables // Format: ERROR_BOUNDARY_ROUTE_[ROUTE_NAME]_[SETTING] = value foreach ($_ENV as $key => $value) { if (! str_starts_with($key, 'ERROR_BOUNDARY_ROUTE_')) { continue; } $parts = explode('_', str_replace('ERROR_BOUNDARY_ROUTE_', '', $key)); if (count($parts) < 2) { continue; } $setting = array_pop($parts); $routeName = strtolower(implode('_', $parts)); if (! isset($configs[$routeName])) { $configs[$routeName] = []; } $configs[$routeName][$setting] = $this->parseConfigValue($setting, $value); } // Convert to BoundaryConfig objects $boundaryConfigs = []; foreach ($configs as $routeName => $settings) { $boundaryConfigs[$routeName] = $this->createConfigFromArray($settings); } return $boundaryConfigs; } private function parseConfigValue(string $setting, string $value): mixed { return match (strtolower($setting)) { 'max_retries', 'circuit_breaker_threshold' => (int) $value, 'circuit_breaker_enabled', 'enable_metrics', 'enable_tracing' => filter_var($value, FILTER_VALIDATE_BOOLEAN), 'max_bulk_error_rate' => (float) $value, 'retry_strategy' => RetryStrategy::tryFrom(strtolower($value)) ?? RetryStrategy::EXPONENTIAL_JITTER, 'base_delay_ms' => Duration::fromMilliseconds((int) $value), 'max_delay_ms' => Duration::fromMilliseconds((int) $value), 'circuit_breaker_timeout_s' => Duration::fromSeconds((int) $value), default => $value, }; } private function createConfigFromArray(array $settings): BoundaryConfig { return new BoundaryConfig( maxRetries: $settings['max_retries'] ?? 3, retryStrategy: $settings['retry_strategy'] ?? RetryStrategy::EXPONENTIAL_JITTER, baseDelay: $settings['base_delay_ms'] ?? Duration::fromMilliseconds(100), maxDelay: $settings['max_delay_ms'] ?? Duration::fromSeconds(5), circuitBreakerEnabled: $settings['circuit_breaker_enabled'] ?? false, circuitBreakerThreshold: $settings['circuit_breaker_threshold'] ?? 5, circuitBreakerTimeout: $settings['circuit_breaker_timeout_s'] ?? Duration::fromMinutes(1), maxBulkErrorRate: $settings['max_bulk_error_rate'] ?? 0.5, enableMetrics: $settings['enable_metrics'] ?? true, enableTracing: $settings['enable_tracing'] ?? false, ); } }