request->isForCustomer()) { $subject = new CustomerSubject(customerId: $this->request->subject_id); $results = array_map( fn (PersonalDataProvider $provider) => $this->safeExport($provider, 'exportForCustomer', $subject), $manager->providers() ); } else { $subject = new UserSubject(userId: $this->request->subject_id, email: $this->request->email); $results = array_map( fn (PersonalDataProvider $provider) => $this->safeExport($provider, 'exportForUser', $subject), $manager->providers() ); } Event::dispatch(new PersonalDataGathered( $this->request, new ExportReport($subject, $results) )); } public function failed(Throwable $exception): void { $this->request->update(['status' => ExportRequestStatus::Failed]); } /** * Catches per-provider so one provider throwing doesn't discard every * other provider's already-gathered export data for this same request — * without this, the whole array_map aborts, handle() never reaches * Event::dispatch(), and failed() marks the ENTIRE request Failed even * though most providers may have already gathered their data * successfully. Logged via Log::error() so a thrown provider is still * visible to staff, not just an empty/missing section in the export. * * @param 'exportForCustomer'|'exportForUser' $method */ private function safeExport(PersonalDataProvider $provider, string $method, CustomerSubject|UserSubject $subject): ProviderExportResult { try { return $provider->{$method}($subject); } catch (Throwable $e) { Log::error("Privacy provider {$provider->name()}::{$method}() threw during export", [ 'provider' => $provider->name(), 'exception' => $e, ]); return new ProviderExportResult($provider->name(), [], $e->getMessage()); } } }