uploadsDirectory = '%kernel.project_dir%/var/uploads/documents'; } #[Route('/upload', name: 'api_document_upload', methods: ['POST'])] public function upload(Request $request): JsonResponse { $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); // Resolve the actual path $uploadsDirectory = str_replace('%kernel.project_dir%', $this->getParameter('kernel.project_dir'), $this->uploadsDirectory); // Erstelle Upload-Verzeichnis falls nicht vorhanden if (!is_dir($uploadsDirectory)) { mkdir($uploadsDirectory, 0755, true); } /** @var UploadedFile $file */ $file = $request->files->get('file'); if (!$file) { return $this->json(['error' => 'Keine Datei hochgeladen'], 400); } // Validierung $maxSize = 10 * 1024 * 1024; // 10MB if ($file->getSize() > $maxSize) { return $this->json(['error' => 'Datei ist zu groß (max. 10MB)'], 400); } // Erlaubte Dateitypen $allowedMimeTypes = [ // Bilder 'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml', // PDF 'application/pdf', // Excel 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // CSV 'text/csv', 'text/plain', // Word 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', ]; $mimeType = $file->getClientMimeType(); if (!in_array($mimeType, $allowedMimeTypes)) { return $this->json([ 'error' => 'Dateityp nicht erlaubt. Erlaubt sind: Bilder (JPG, PNG, GIF, WebP, SVG), PDF, Excel (XLS, XLSX), CSV und Word (DOC, DOCX)' ], 400); } $relatedEntity = $request->request->get('relatedEntity'); $relatedEntityId = $request->request->get('relatedEntityId'); if (!$relatedEntity || !$relatedEntityId) { return $this->json(['error' => 'relatedEntity und relatedEntityId sind erforderlich'], 400); } // Datei-Informationen VOR dem Move speichern $originalFilename = $file->getClientOriginalName(); $mimeType = $file->getClientMimeType(); $fileSize = $file->getSize(); // Sichere Dateinamen generieren $safeFilename = $this->slugger->slug(pathinfo($originalFilename, PATHINFO_FILENAME)); $newFilename = $safeFilename . '-' . uniqid() . '.' . $file->guessExtension(); try { $file->move($uploadsDirectory, $newFilename); } catch (FileException $e) { return $this->json(['error' => 'Datei konnte nicht gespeichert werden'], 500); } // Document Entity erstellen $document = new Document(); $document->setFilename($newFilename); $document->setOriginalFilename($originalFilename); $document->setMimeType($mimeType); $document->setSize($fileSize); $document->setRelatedEntity($relatedEntity); $document->setRelatedEntityId((int) $relatedEntityId); $document->setDescription($request->request->get('description')); /** @var User $user */ $user = $this->getUser(); $document->setUploadedBy($user); $this->entityManager->persist($document); $this->entityManager->flush(); return $this->json($document, 201, [], ['groups' => 'document:read']); } #[Route('/{id}/download', name: 'api_document_download', methods: ['GET'])] public function download(Document $document): BinaryFileResponse { $this->denyAccessUnlessGranted('VIEW', $document); $uploadsDirectory = str_replace('%kernel.project_dir%', $this->getParameter('kernel.project_dir'), $this->uploadsDirectory); $filePath = $uploadsDirectory . '/' . $document->getFilename(); if (!file_exists($filePath)) { throw $this->createNotFoundException('Datei nicht gefunden'); } $response = new BinaryFileResponse($filePath); // Inline anzeigen statt Download für gängige Dateitypen $mimeType = $document->getMimeType(); $inlineTypes = ['application/pdf', 'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp']; if (in_array($mimeType, $inlineTypes)) { $response->setContentDisposition( ResponseHeaderBag::DISPOSITION_INLINE, $document->getOriginalFilename() ); } else { $response->setContentDisposition( ResponseHeaderBag::DISPOSITION_ATTACHMENT, $document->getOriginalFilename() ); } return $response; } }