'text/markdown', 'markdown' => 'text/markdown', 'txt' => 'text/plain', 'csv' => 'text/csv', 'json' => 'application/json', 'xml' => 'text/xml', ]; public function __construct( private readonly EntityManagerInterface $entityManager, private readonly Security $security, private readonly string $uploadDir, ) {} /** * @param int $id ID of the task document to update * @param null|string $content New raw text content of the document (e.g. Markdown). Omit to keep the current content. * @param null|string $fileName New display name of the document, including extension. Omit to keep the current name. */ public function __invoke( int $id, ?string $content = null, ?string $fileName = null, ): string { if (!$this->security->isGranted('ROLE_USER')) { throw new AccessDeniedException('Access denied: ROLE_USER required.'); } if (null === $content && null === $fileName) { throw new InvalidArgumentException('At least one of content or fileName must be provided.'); } $document = $this->entityManager->find(TaskDocument::class, $id); if (null === $document) { throw new InvalidArgumentException(sprintf('Task document with ID %d not found.', $id)); } // Rename: update the display name and re-infer the MIME type from its extension. if (null !== $fileName) { $originalName = trim($fileName); if ('' === $originalName) { throw new InvalidArgumentException('fileName cannot be empty.'); } $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION)); if ('' === $extension) { $originalName .= '.md'; $extension = 'md'; } $document->setOriginalName($originalName); $document->setMimeType(self::EXTENSION_TO_MIME[$extension] ?? 'text/markdown'); } // Replace content: overwrite the stored file in place and refresh its size. if (null !== $content) { if ('' === $content) { throw new InvalidArgumentException('Document content cannot be empty.'); } $size = strlen($content); if ($size > self::MAX_CONTENT_SIZE) { throw new InvalidArgumentException('Content size exceeds 5 MB limit.'); } $filePath = $this->uploadDir.'/'.$document->getFileName(); if (false === file_put_contents($filePath, $content)) { throw new InvalidArgumentException('Failed to write document to disk.'); } $document->setSize($size); } $this->entityManager->flush(); return json_encode([ 'id' => $document->getId(), 'taskId' => $document->getTask()?->getId(), 'originalName' => $document->getOriginalName(), 'mimeType' => $document->getMimeType(), 'size' => $document->getSize(), 'createdAt' => $document->getCreatedAt()?->format('c'), 'uploadedBy' => $document->getUploadedBy()?->getUsername(), ]); } }