Files
fotospiel-app/app/Services/Storage/EventStorageManager.php
Codex Agent fa33e7cbcf Fix Event & EventType resource issues and apply formatting
- Fix EventType deletion error handling (constraint violations)
- Fix Event update error (package_id column missing)
- Fix Event Type dropdown options (JSON display issue)
- Fix EventPackagesRelationManager query error
- Add missing translations for deletion errors
- Apply Pint formatting
2026-01-21 10:34:06 +01:00

157 lines
4.2 KiB
PHP

<?php
namespace App\Services\Storage;
use App\Models\Event;
use App\Models\EventMediaAsset;
use App\Models\EventStorageAssignment;
use App\Models\MediaStorageTarget;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
class EventStorageManager
{
public function getHotDiskForEvent(Event $event): string
{
$target = $event->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;
}
}