$additionalHeaders HTTP headers to add to response */ public function __construct( public string $exceptionClass, public ErrorSeverity $errorLevel, public int $httpStatus, public ?string $errorCode = null, public ?string $errorCategory = null, public ?string $errorSeverity = null, public ?bool $isRecoverable = null, public ?string $recoveryHint = null, public array $additionalHeaders = [] ) {} /** * Create basic metadata for non-FrameworkException errors. */ public static function basic( string $exceptionClass, ErrorSeverity $errorLevel, int $httpStatus ): self { return new self( exceptionClass: $exceptionClass, errorLevel: $errorLevel, httpStatus: $httpStatus ); } /** * Create enhanced metadata for FrameworkException errors. */ public static function enhanced( string $exceptionClass, ErrorSeverity $errorLevel, int $httpStatus, string $errorCode, string $errorCategory, string $errorSeverity, bool $isRecoverable, ?string $recoveryHint = null ): self { return new self( exceptionClass: $exceptionClass, errorLevel: $errorLevel, httpStatus: $httpStatus, errorCode: $errorCode, errorCategory: $errorCategory, errorSeverity: $errorSeverity, isRecoverable: $isRecoverable, recoveryHint: $recoveryHint ); } /** * Add additional HTTP headers (immutable). */ public function withAdditionalHeaders(array $headers): self { return new self( exceptionClass: $this->exceptionClass, errorLevel: $this->errorLevel, httpStatus: $this->httpStatus, errorCode: $this->errorCode, errorCategory: $this->errorCategory, errorSeverity: $this->errorSeverity, isRecoverable: $this->isRecoverable, recoveryHint: $this->recoveryHint, additionalHeaders: array_merge($this->additionalHeaders, $headers) ); } /** * Check if this is enhanced metadata (from FrameworkException). */ public function isEnhanced(): bool { return $this->errorCode !== null; } /** * Check if metadata has additional headers. */ public function hasAdditionalHeaders(): bool { return !empty($this->additionalHeaders); } /** * Convert to array for legacy compatibility. * * @return array */ public function toArray(): array { $array = [ 'exception_class' => $this->exceptionClass, 'error_level' => $this->errorLevel->name, 'http_status' => $this->httpStatus, ]; // Add enhanced fields if present if ($this->errorCode !== null) { $array['error_code'] = $this->errorCode; } if ($this->errorCategory !== null) { $array['error_category'] = $this->errorCategory; } if ($this->errorSeverity !== null) { $array['error_severity'] = $this->errorSeverity; } if ($this->isRecoverable !== null) { $array['is_recoverable'] = $this->isRecoverable; } if ($this->recoveryHint !== null) { $array['recovery_hint'] = $this->recoveryHint; } if (!empty($this->additionalHeaders)) { $array['additional_headers'] = $this->additionalHeaders; } return $array; } /** * Create from array (for testing/migration). * * @param array $data */ public static function fromArray(array $data): self { return new self( exceptionClass: $data['exception_class'] ?? '', errorLevel: ErrorSeverity::from($data['error_level'] ?? 'ERROR'), httpStatus: $data['http_status'] ?? 500, errorCode: $data['error_code'] ?? null, errorCategory: $data['error_category'] ?? null, errorSeverity: $data['error_severity'] ?? null, isRecoverable: $data['is_recoverable'] ?? null, recoveryHint: $data['recovery_hint'] ?? null, additionalHeaders: $data['additional_headers'] ?? [] ); } }