'boolean', 'idempotency_key' => 'string', 'requested_items' => 'array', 'preview' => 'array', 'results' => 'array', 'metadata' => 'array', 'group_mapping' => 'array', 'started_at' => 'datetime', 'completed_at' => 'datetime', ]; public function tenant(): BelongsTo { return $this->belongsTo(Tenant::class); } public function backupSet(): BelongsTo { return $this->belongsTo(BackupSet::class)->withTrashed(); } public function scopeDeletable(Builder $query): Builder { return $query->whereIn('status', array_map( static fn (RestoreRunStatus $status): string => $status->value, [ RestoreRunStatus::Draft, RestoreRunStatus::Scoped, RestoreRunStatus::Checked, RestoreRunStatus::Previewed, RestoreRunStatus::Completed, RestoreRunStatus::Partial, RestoreRunStatus::Failed, RestoreRunStatus::Cancelled, RestoreRunStatus::Aborted, RestoreRunStatus::CompletedWithErrors, ] )); } public function isDeletable(): bool { $status = RestoreRunStatus::fromString($this->status); return $status?->isDeletable() ?? false; } // Group mapping helpers public function hasGroupMapping(): bool { return ! empty($this->group_mapping); } public function getMappedGroupId(string $sourceGroupId): ?string { $mapping = $this->group_mapping ?? []; return $mapping[$sourceGroupId] ?? null; } public function isGroupSkipped(string $sourceGroupId): bool { $mapping = $this->group_mapping ?? []; return ($mapping[$sourceGroupId] ?? null) === 'SKIP'; } public function getUnmappedGroupIds(array $sourceGroupIds): array { return array_diff($sourceGroupIds, array_keys($this->group_mapping ?? [])); } public function addGroupMapping(string $sourceGroupId, string $targetGroupId): void { $mapping = $this->group_mapping ?? []; $mapping[$sourceGroupId] = $targetGroupId; $this->group_mapping = $mapping; } // Assignment restore outcome helpers public function getAssignmentRestoreOutcomes(): array { $results = $this->results ?? []; if (isset($results['assignment_outcomes']) && is_array($results['assignment_outcomes'])) { return $results['assignment_outcomes']; } if (isset($results['items']) && is_array($results['items'])) { return collect($results['items']) ->pluck('assignment_outcomes') ->flatten(1) ->filter() ->values() ->all(); } if (! is_array($results)) { return []; } return collect($results) ->pluck('assignment_outcomes') ->flatten(1) ->filter(static fn (mixed $outcome): bool => is_array($outcome)) ->values() ->all(); } public function getSuccessfulAssignmentsCount(): int { return count(array_filter( $this->getAssignmentRestoreOutcomes(), static fn (mixed $outcome): bool => is_array($outcome) && ($outcome['status'] ?? null) === 'success' )); } public function getFailedAssignmentsCount(): int { return count(array_filter( $this->getAssignmentRestoreOutcomes(), static fn (mixed $outcome): bool => is_array($outcome) && ($outcome['status'] ?? null) === 'failed' )); } public function getSkippedAssignmentsCount(): int { return count(array_filter( $this->getAssignmentRestoreOutcomes(), static fn (mixed $outcome): bool => is_array($outcome) && ($outcome['status'] ?? null) === 'skipped' )); } }