Files
core/src/Privacy/Jobs/ExportDataSubjectJob.php
T

103 lines
4.1 KiB
PHP
Raw Normal View History

2026-08-24 21:06:11 +03:00
<?php
namespace Modules\Core\Privacy\Jobs;
use Throwable;
2026-08-24 21:06:11 +03:00
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use Modules\Core\Privacy\Contracts\PersonalDataProvider;
use Modules\Core\Privacy\DTOs\CustomerSubject;
2026-08-24 21:06:11 +03:00
use Modules\Core\Privacy\Events\PersonalDataGathered;
use Modules\Core\Privacy\DTOs\ExportReport;
use Modules\Core\Privacy\DTOs\ProviderExportResult;
use Modules\Core\Privacy\Enums\ExportRequestStatus;
2026-08-24 21:06:11 +03:00
use Modules\Core\Privacy\Models\DataExportRequest;
use Modules\Core\Privacy\Services\PrivacyManager;
use Modules\Core\Privacy\DTOs\UserSubject;
2026-08-24 21:06:11 +03:00
/**
* Gathers every registered PersonalDataProvider's export data for one request, all
* sequentially in this single job — deliberately not fanned out into one job per
* provider. Per-subject export work is small (a handful of indexed queries per
* provider), so there's no real parallelism win, and one job means "finished" is
* just "handle() returned," with no Bus::batch()/completion-counting needed. If a
* future provider ever does something genuinely slow (an external API call, a
* generated PDF), that's the point to reconsider — not before.
*
* Calls each provider's *ForCustomer() or *ForUser() method depending on the
* request's polymorphic subject — see Modules\Core\Privacy\Services\PrivacyService and
2026-08-24 21:06:11 +03:00
* docs/privacy.md "User-scope vs Customer-scope".
*
* Writing the gathered data to a file is intentionally NOT done here — see
* PersonalDataGathered and Modules\Core\Privacy\Listeners\WriteExportToCsvListener,
* which keeps the export *format* swappable without touching how data is gathered.
*/
class ExportDataSubjectJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
public function __construct(
public readonly DataExportRequest $request,
) {}
public function handle(PrivacyManager $manager): void
{
if ($this->request->isForCustomer()) {
$subject = new CustomerSubject(customerId: $this->request->subject_id);
$results = array_map(
fn (PersonalDataProvider $provider) => $this->safeExport($provider, 'exportForCustomer', $subject),
$manager->providers()
);
2026-08-24 21:06:11 +03:00
} 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()
);
2026-08-24 21:06:11 +03:00
}
Event::dispatch(new PersonalDataGathered(
$this->request,
new ExportReport($subject, $results)
));
}
public function failed(Throwable $exception): void
2026-08-24 21:06:11 +03:00
{
$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());
}
}
2026-08-24 21:06:11 +03:00
}