get(Environment::class); $enabled = $env->getBool('ERROR_REPORTING_ENABLED', true); // Storage $container->bind(ErrorReportStorageInterface::class, function (Container $container) use ($enabled) { if (! $enabled) { // Return storage even if disabled (might be used for queries) return new DatabaseErrorReportStorage( connection: $container->get(ConnectionInterface::class) ); } return new DatabaseErrorReportStorage( connection: $container->get(ConnectionInterface::class) ); }); // Analytics Engine $container->bind(ErrorAnalyticsEngine::class, function (Container $container) { return new ErrorAnalyticsEngine( storage: $container->get(ErrorReportStorageInterface::class), clock: $container->get(Clock::class) ); }); // Error Reporter Interface - bind to concrete or Null implementation $container->bind(ErrorReporterInterface::class, function (Container $container) use ($enabled) { if (! $enabled) { return new NullErrorReporter(); } $env = $container->get(Environment::class); $processors = []; $filters = []; // Add built-in processors if ($container->has(RequestContextProcessor::class)) { $processors[] = $container->get(RequestContextProcessor::class); } if ($container->has(UserContextProcessor::class)) { $processors[] = $container->get(UserContextProcessor::class); } // Add environment-based filters $filterLevels = $env->getString('ERROR_REPORTING_FILTER_LEVELS', ''); if ($filterLevels !== '') { $allowedLevels = explode(',', $filterLevels); $filters[] = function (ErrorReport $report) use ($allowedLevels) { return in_array($report->level, $allowedLevels); }; } // Add environment filter for production $appEnv = $env->getString('APP_ENV', 'production'); if ($appEnv === 'production') { $filters[] = function (ErrorReport $report) { // Don't report debug/info in production return ! in_array($report->level, ['debug', 'info']); }; } return new ErrorReporter( storage: $container->get(ErrorReportStorageInterface::class), clock: $container->get(Clock::class), logger: $container->has(Logger::class) ? $container->get(Logger::class) : null, queue: $container->has(Queue::class) ? $container->get(Queue::class) : null, asyncProcessing: $env->getBool('ERROR_REPORTING_ASYNC', true), processors: $processors, filters: $filters ); }); // Error Reporter (concrete class) - delegate to interface $container->bind(ErrorReporter::class, function (Container $container) use ($enabled) { if (! $enabled) { throw new \RuntimeException('ErrorReporter is disabled. Use ErrorReporterInterface instead.'); } $env = $container->get(Environment::class); $processors = []; $filters = []; // Add built-in processors if ($container->has(RequestContextProcessor::class)) { $processors[] = $container->get(RequestContextProcessor::class); } if ($container->has(UserContextProcessor::class)) { $processors[] = $container->get(UserContextProcessor::class); } // Add environment-based filters $filterLevels = $env->getString('ERROR_REPORTING_FILTER_LEVELS', ''); if ($filterLevels !== '') { $allowedLevels = explode(',', $filterLevels); $filters[] = function (ErrorReport $report) use ($allowedLevels) { return in_array($report->level, $allowedLevels); }; } // Add environment filter for production $appEnv = $env->getString('APP_ENV', 'production'); if ($appEnv === 'production') { $filters[] = function (ErrorReport $report) { // Don't report debug/info in production return ! in_array($report->level, ['debug', 'info']); }; } return new ErrorReporter( storage: $container->get(ErrorReportStorageInterface::class), clock: $container->get(Clock::class), logger: $container->has(Logger::class) ? $container->get(Logger::class) : null, queue: $container->has(Queue::class) ? $container->get(Queue::class) : null, asyncProcessing: $env->getBool('ERROR_REPORTING_ASYNC', true), processors: $processors, filters: $filters ); }); // Middleware $container->bind(ErrorReportingMiddleware::class, function (Container $container) use ($enabled) { return new ErrorReportingMiddleware( reporter: $container->get(ErrorReporter::class), enabled: $enabled ); }); // Processors $container->bind(RequestContextProcessor::class, function (Container $container) { return new RequestContextProcessor(); }); $container->bind(UserContextProcessor::class, function (Container $container) { // Session is not a singleton service - it's created per-request by SessionManager // Don't try to resolve it here as it may not exist or trigger circular dependencies return new UserContextProcessor(null); }); } }