setNumber($this->calculateNextProjectNumber()); if ($customer !== null) { $project->setCustomer($customer); } $this->dispatcher->dispatch(new ProjectMetaDefinitionEvent($project)); $this->dispatcher->dispatch(new ProjectCreateEvent($project)); return $project; } public function saveNewProject(Project $project, ?Context $context = null): Project { if (null !== $project->getId()) { throw new InvalidArgumentException('Cannot create project, already persisted'); } $this->validateProject($project); if ($context !== null && $this->configuration->isProjectCopyTeamsOnCreate()) { foreach ($context->getUser()->getTeams() as $team) { $project->addTeam($team); $team->addProject($project); } } $this->dispatcher->dispatch(new ProjectCreatePreEvent($project)); $this->repository->saveProject($project); $this->dispatcher->dispatch(new ProjectCreatePostEvent($project)); return $project; } public function deleteProject(Project $project): void { $this->dispatcher->dispatch(new ProjectDeleteEvent($project)); $this->repository->deleteProject($project); } /** * @param string[] $groups * @throws ValidationFailedException */ private function validateProject(Project $project, array $groups = []): void { $errors = $this->validator->validate($project, null, $groups); if ($errors->count() > 0) { throw new ValidationFailedException($errors, 'Validation Failed'); } } public function updateProject(Project $project): Project { $this->validateProject($project); $this->dispatcher->dispatch(new ProjectUpdatePreEvent($project)); $this->repository->saveProject($project); $this->dispatcher->dispatch(new ProjectUpdatePostEvent($project)); return $project; } public function findProjectByName(string $name): ?Project { return $this->repository->findOneBy(['name' => $name]); } public function findProjectByNumber(string $number): ?Project { return $this->repository->findOneBy(['number' => $number]); } public function calculateNextProjectNumber(): ?string { $format = $this->configuration->find('project.number_format'); if (empty($format) || !\is_string($format)) { return null; } // we cannot use max(number) because a varchar column returns unexpected results $start = $this->repository->countProject(); $i = 0; do { $start++; $numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start): string|int { return match ($format) { 'pc' => $start + $increaseBy, default => $originalFormat, }; }); $number = $numberGenerator->getNumber(); $project = $this->findProjectByNumber($number); } while ($project !== null && $i++ < 100); if ($project !== null) { return null; } return $number; } }