currentStorageTarget('hot') ?? $this->resolveDefaultHotTarget(); return $target?->key ?? Config::get('filesystems.default', 'local'); } public function getArchiveDiskForEvent(Event $event): ?string { $assignment = $event->storageAssignments() ->where('role', 'archive') ->where('status', 'active') ->latest('assigned_at') ->first(); if ($assignment?->storageTarget) { return $assignment->storageTarget->key; } $default = $this->resolveDefaultArchiveTarget(); if (! $default) { return null; } $assignment = $this->ensureAssignment($event, $default, 'archive'); return $assignment->storageTarget?->key; } public function ensureAssignment(Event $event, ?MediaStorageTarget $target = null, string $role = 'hot'): EventStorageAssignment { if (! $target) { $target = $role === 'archive' ? $this->resolveDefaultArchiveTarget() : $this->resolveDefaultHotTarget(); } $assignment = $event->storageAssignments() ->where('role', $role) ->where('status', 'active') ->where('media_storage_target_id', $target?->id) ->latest('assigned_at') ->first(); if ($assignment) { return $assignment; } if (! $target) { throw new \RuntimeException('No storage target available for role '.$role); } $assignment = $event->storageAssignments()->create([ 'media_storage_target_id' => $target->id, 'role' => $role, 'status' => 'active', 'assigned_at' => now(), ]); return $assignment; } public function recordAsset( Event $event, string $disk, string $path, array $attributes = [], ?EventMediaAsset $existing = null, ): EventMediaAsset { $target = MediaStorageTarget::where('key', $disk)->first(); if (! $target) { $target = $this->resolveDefaultHotTarget(); } $payload = array_merge([ 'event_id' => $event->id, 'media_storage_target_id' => $target?->id, 'disk' => $disk, 'path' => $path, 'status' => 'hot', 'processed_at' => now(), ], $attributes); if ($existing) { $existing->fill($payload)->save(); return $existing; } return EventMediaAsset::create($payload); } public function registerDynamicDisks(): void { if (! $this->targetsTableExists()) { return; } $targets = MediaStorageTarget::active()->get(); foreach ($targets as $target) { $config = $target->toFilesystemConfig(); Config::set('filesystems.disks.'.$target->key, $config); } } protected function resolveDefaultHotTarget(): ?MediaStorageTarget { return MediaStorageTarget::active() ->where('is_hot', true) ->orderByDesc('is_default') ->orderByDesc('priority') ->first(); } protected function resolveDefaultArchiveTarget(): ?MediaStorageTarget { return MediaStorageTarget::active() ->where('is_hot', false) ->orderByDesc('priority') ->first(); } protected function targetsTableExists(): bool { static $cached; if ($cached !== null) { return $cached; } try { $cached = \Schema::hasTable('media_storage_targets'); } catch (\Throwable $e) { Log::debug('Skipping storage target bootstrap: '.$e->getMessage()); $cached = false; } return $cached; } }