'[0-9a-f]{32}\.(jpg|png|webp)'], methods: ['GET'])] public function original(string $name, CoverStorage $covers): Response { $path = $covers->originalPath($name); if (!is_file($path)) { throw $this->createNotFoundException(); } $response = new BinaryFileResponse($path); $response->headers->set('X-Content-Type-Options', 'nosniff'); return $response; } #[Route('/book/{id}/cover', name: 'cover_upload', requirements: ['id' => Requirement::DIGITS], methods: ['POST'])] public function upload(Request $request, Book $book, Library $library): Response { $form = $this->createForm(CoverType::class); $form->handleRequest($request); if (!$form->isSubmitted()) { $this->addFlash('error', 'cover_too_large'); } elseif (!$form->isValid()) { $this->addFlash('error', $form->getErrors(true)->current()->getMessage()); } else { try { $library->changeCover($book, $form->getData()['cover']); $this->addFlash('success', 'cover_saved'); } catch (CoverProcessingException) { $this->addFlash('error', 'cover_failed'); } } return $this->redirectToRoute('book_show', ['id' => $book->getId()]); } #[Route('/book/{id}/cover/remove', name: 'cover_remove', requirements: ['id' => Requirement::DIGITS], methods: ['POST'])] public function remove(Request $request, Book $book, Library $library): Response { if ($this->isCsrfTokenValid('remove-cover' . $book->getId(), $request->getPayload()->getString('_token'))) { $library->changeCover($book, null); } else { $this->addFlash('error', 'action_rejected'); } return $this->redirectToRoute('book_show', ['id' => $book->getId()]); } }