security->isGranted('ROLE_USER')) { throw new AccessDeniedException('Access denied: ROLE_USER required.'); } $user = $this->userRepository->find($userId); if (null === $user) { throw new InvalidArgumentException(sprintf('User with ID %d not found.', $userId)); } // Check for existing active timer if creating a new active one if (null === $stoppedAt) { $activeEntry = $this->timeEntryRepository->findActiveByUser($user); if (null !== $activeEntry) { throw new InvalidArgumentException(sprintf('User "%s" already has an active timer (ID %d). Stop it before starting a new one.', $user->getUsername(), $activeEntry->getId())); } } $entry = new TimeEntry(); $entry->setUser($user); $entry->setStartedAt(new DateTimeImmutable($startedAt)); if (null !== $title) { $entry->setTitle($title); } if (null !== $stoppedAt) { $entry->setStoppedAt(new DateTimeImmutable($stoppedAt)); } if (null !== $description) { $entry->setDescription($description); } if (null !== $projectId) { $project = $this->projectRepository->find($projectId); if (null === $project) { throw new InvalidArgumentException(sprintf('Project with ID %d not found.', $projectId)); } $entry->setProject($project); } if (null !== $taskId) { $task = $this->taskRepository->find($taskId); if (null === $task) { throw new InvalidArgumentException(sprintf('Task with ID %d not found.', $taskId)); } $entry->setTask($task); } if (null !== $tagIds) { foreach ($tagIds as $tagId) { $tag = $this->taskTagRepository->find($tagId); if (null === $tag) { throw new InvalidArgumentException(sprintf('TaskTag with ID %d not found.', $tagId)); } $entry->addTag($tag); } } $this->entityManager->persist($entry); $this->entityManager->flush(); return json_encode(Serializer::timeEntry($entry)); } }