'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 TaskRepository $taskRepository, private readonly Security $security, private readonly string $uploadDir, ) {} /** * @param int $taskId ID of the task to attach the document to * @param string $content Raw text content of the document (e.g. Markdown) * @param string $fileName Display name of the document, including extension (defaults to "document.md") */ public function __invoke( int $taskId, string $content, string $fileName = 'document.md', ): string { if (!$this->security->isGranted('ROLE_USER')) { throw new AccessDeniedException('Access denied: ROLE_USER required.'); } $task = $this->taskRepository->find($taskId); if (null === $task) { throw new InvalidArgumentException(sprintf('Task with ID %d not found.', $taskId)); } 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.'); } $originalName = '' !== trim($fileName) ? trim($fileName) : 'document.md'; $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION)); $mimeType = self::EXTENSION_TO_MIME[$extension] ?? 'text/markdown'; if ('' === $extension) { $originalName .= '.md'; $extension = 'md'; } $storedName = Uuid::v4()->toRfc4122().'.'.$extension; if (!is_dir($this->uploadDir) && !mkdir($this->uploadDir, 0o775, true) && !is_dir($this->uploadDir)) { throw new InvalidArgumentException(sprintf('Upload directory "%s" could not be created.', $this->uploadDir)); } if (false === file_put_contents($this->uploadDir.'/'.$storedName, $content)) { throw new InvalidArgumentException('Failed to write document to disk.'); } $document = new TaskDocument(); $document->setTask($task); $document->setOriginalName($originalName); $document->setFileName($storedName); $document->setMimeType($mimeType); $document->setSize($size); $document->setCreatedAt(new DateTimeImmutable()); $document->setUploadedBy($this->security->getUser()); $this->entityManager->persist($document); $this->entityManager->flush(); return json_encode([ 'id' => $document->getId(), 'taskId' => $task->getId(), 'originalName' => $document->getOriginalName(), 'mimeType' => $document->getMimeType(), 'size' => $document->getSize(), 'createdAt' => $document->getCreatedAt()?->format('c'), 'uploadedBy' => $document->getUploadedBy()?->getUsername(), ]); } }