option('id') === null && $this->option('submission') === null && $this->option('org') === null ) { $this->error('At least one of --id, --submission, or --org is required.'); return self::FAILURE; } $query = $this->buildQuery(); $failures = $query->get(); if ($failures->isEmpty()) { $this->info('No matching open failures.'); return self::SUCCESS; } $rows = []; foreach ($failures as $failure) { if ($this->option('dry-run')) { $rows[] = ['id' => (string) $failure->id, 'submission' => (string) $failure->form_submission_id, 'result' => 'would-retry']; continue; } $rows[] = $this->retryOne($failure, $retryService); } $this->table(['id', 'submission', 'result'], $rows); return self::SUCCESS; } /** * @return Builder */ private function buildQuery(): Builder { $query = FormSubmissionActionFailure::query()->open(); if (($id = $this->option('id')) !== null) { $query->where('id', $id); } if (($submissionId = $this->option('submission')) !== null) { $query->where('form_submission_id', $submissionId); } if (($listener = $this->option('listener')) !== null) { $query->where('listener_class', $listener); } if (($org = $this->option('org')) !== null) { // FK chain: failure โ†’ submission โ†’ organisation. $query->whereHas('submission', function (Builder $q) use ($org): void { /** @var Builder<\App\Models\FormBuilder\FormSubmission> $q */ $q->where('organisation_id', $org); }); } return $query; } /** * @return array{id:string, submission:string, result:string} */ private function retryOne(FormSubmissionActionFailure $failure, FormFailureRetryService $retryService): array { try { $result = $retryService->retry($failure); return [ 'id' => (string) $failure->id, 'submission' => (string) $failure->form_submission_id, 'result' => $result['outcome'] === 'succeeded' ? 'succeeded' : 'failed-again', ]; } catch (FailureNotRetriableException $e) { return [ 'id' => (string) $failure->id, 'submission' => (string) $failure->form_submission_id, 'result' => "skipped-{$e->reason}", ]; } catch (ParentSubmissionGoneException) { return [ 'id' => (string) $failure->id, 'submission' => (string) $failure->form_submission_id, 'result' => 'submission-gone', ]; } } }