dispatcher->dispatch(new ActivityMetaDefinitionEvent($activity)); } public function createNewActivity(?Project $project = null): Activity { $activity = new Activity(); $activity->setNumber($this->calculateNextActivityNumber()); if ($project !== null) { $activity->setProject($project); } $this->loadMetaFields($activity); $this->dispatcher->dispatch(new ActivityCreateEvent($activity)); return $activity; } public function saveActivity(Activity $activity): Activity { if ($activity->isNew()) { return $this->saveNewActivity($activity); // @phpstan-ignore method.deprecated } else { return $this->updateActivity($activity); // @phpstan-ignore method.deprecated } } /** * @deprecated since 2.35 - use saveActivity() instead */ public function saveNewActivity(Activity $activity): Activity { if (null !== $activity->getId()) { throw new InvalidArgumentException('Cannot create activity, already persisted'); } $this->validateActivity($activity); $this->dispatcher->dispatch(new ActivityCreatePreEvent($activity)); $this->repository->saveActivity($activity); $this->dispatcher->dispatch(new ActivityCreatePostEvent($activity)); return $activity; } public function deleteActivity(Activity $activity, ?Activity $replace = null): void { $this->dispatcher->dispatch(new ActivityDeleteEvent($activity, $replace)); $this->repository->deleteActivity($activity, $replace); } /** * @param string[] $groups * @throws ValidationFailedException */ private function validateActivity(Activity $activity, array $groups = []): void { $errors = $this->validator->validate($activity, null, $groups); if ($errors->count() > 0) { throw new ValidationFailedException($errors); } } /** * @deprecated since 2.35 - use saveActivity() instead */ public function updateActivity(Activity $activity): Activity { $this->validateActivity($activity); $this->dispatcher->dispatch(new ActivityUpdatePreEvent($activity)); $this->repository->saveActivity($activity); $this->dispatcher->dispatch(new ActivityUpdatePostEvent($activity)); return $activity; } public function findActivityByName(string $name, ?Project $project = null): ?Activity { return $this->repository->findOneBy(['project' => $project?->getId(), 'name' => $name]); } public function findActivityByNumber(string $number): ?Activity { return $this->repository->findOneBy(['number' => $number]); } private function calculateNextActivityNumber(): ?string { $format = $this->configuration->find('activity.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->countActivity(); $i = 0; $createDate = new \DateTimeImmutable(); do { $start++; $numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start, $createDate): string|int { return match ($format) { 'Y' => $createDate->format('Y'), 'y' => $createDate->format('y'), 'M' => $createDate->format('m'), 'm' => $createDate->format('n'), 'D' => $createDate->format('d'), 'd' => $createDate->format('j'), 'YY' => (int) $createDate->format('Y') + $increaseBy, 'yy' => (int) $createDate->format('y') + $increaseBy, 'MM' => (int) $createDate->format('m') + $increaseBy, 'DD' => (int) $createDate->format('d') + $increaseBy, 'ac' => $start + $increaseBy, default => $originalFormat, }; }); $number = $numberGenerator->getNumber(); $activity = $this->findActivityByNumber($number); } while ($activity !== null && $i++ < 100); if ($activity !== null) { return null; } return $number; } }