*/ private const array ALLOWED_MIME_TYPES = [ 'image/png' => 'png', 'image/jpeg' => 'jpg', 'image/gif' => 'gif', 'image/svg+xml' => 'svg', ]; public function __construct(private readonly UpdateDocumentAssetRequest $request) { } public function execute(): UpdateDocumentAssetResponse { $response = new UpdateDocumentAssetResponse(); $name = $this->normalizeName($this->request->name); if ($name === null) { $response->message = 'Bitte einen Namen aus Kleinbuchstaben, Ziffern, Bindestrich oder Unterstrich angeben.'; return $response; } $asset = DocumentAsset::where('name', $name)->first(); $file = $this->request->file; if ($file === null && $asset === null) { $response->message = 'Für ein neues Bild wird eine Datei benötigt.'; return $response; } $attributes = ['name' => $name, 'label' => $this->request->label]; if ($file !== null) { if (!array_key_exists($file->getMimeType(), self::ALLOWED_MIME_TYPES)) { $response->message = 'Nur PNG, JPEG, GIF oder SVG sind zulässig.'; return $response; } if ($file->getSize() > self::MAX_BYTES) { $response->message = 'Das Bild darf höchstens 2 MB groß sein.'; return $response; } $attributes['mime'] = $file->getMimeType(); $attributes['data'] = base64_encode(file_get_contents($file->getRealPath())); } $response->asset = $asset === null ? DocumentAsset::create($attributes) : tap($asset)->update($attributes); $response->success = true; $response->message = 'Das Bild wurde gespeichert.'; return $response; } /** Namen sind Slugs, damit `{asset:name}` eindeutig erkennbar bleibt. */ private function normalizeName(string $name): ?string { $name = strtolower(trim($name)); return preg_match('/^[a-z0-9_-]+$/', $name) === 1 ? $name : null; } }