''])] private string $prefix = ''; #[Serializer\Groups(['write'])] #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)] private ?int $id = null; #[Serializer\Groups(['write'])] #[ORM\Column(name: 'title', type: \Doctrine\DBAL\Types\Types::TEXT, options: ['default' => ''])] private string $title = ''; #[Serializer\Groups(['write'])] #[ORM\Column(type: 'uuid', unique: true)] private UuidInterface $uuid; #[ORM\ManyToOne(targetEntity: DocGeneratorTemplate::class)] private ?DocGeneratorTemplate $template = null; /** * Store the number of times a generation has been tryied for this StoredObject. * * This is a workaround, as generation consume lot of memory, and out-of-memory errors * are not handled by messenger. */ #[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, options: ['default' => 0])] private int $generationTrialsCounter = 0; #[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE, nullable: true, options: ['default' => null])] private ?\DateTimeImmutable $deleteAt = null; #[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: false, options: ['default' => ''])] private string $generationErrors = ''; /** * @var Collection */ #[ORM\OneToMany(mappedBy: 'storedObject', targetEntity: StoredObjectVersion::class, cascade: ['persist'], orphanRemoval: true)] private Collection $versions; /** * @param StoredObject::STATUS_* $status */ public function __construct( #[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, options: ['default' => 'ready'])] private string $status = 'empty' ) { $this->uuid = Uuid::uuid4(); $this->versions = new ArrayCollection(); $this->prefix = self::generatePrefix(); } public function addGenerationTrial(): self { ++$this->generationTrialsCounter; return $this; } /** * @deprecated */ #[Serializer\Groups(['write'])] public function getCreationDate(): \DateTime { if (null === $this->createdAt) { // this scenario will quite never happens return new \DateTime('now'); } return \DateTime::createFromImmutable($this->createdAt); } #[AsyncFileExists(message: 'The file is not stored properly')] #[Assert\NotNull(message: 'The store object version must be present')] public function getCurrentVersion(): ?StoredObjectVersion { $maxVersion = null; foreach ($this->versions as $v) { if ($v->getVersion() > ($maxVersion?->getVersion() ?? -1)) { $maxVersion = $v; } } return $maxVersion; } public function getDatas(): array { return $this->datas; } public function getPrefix(): string { return $this->prefix; } public function getFilename(): string { return $this->getCurrentVersion()?->getFilename() ?? ''; } public function getGenerationTrialsCounter(): int { return $this->generationTrialsCounter; } public function getId(): ?int { return $this->id; } /** * @return list */ public function getIv(): array { return $this->getCurrentVersion()?->getIv() ?? []; } public function getKeyInfos(): array { return $this->getCurrentVersion()?->getKeyInfos() ?? []; } /** * @deprecated use method "getFilename()" */ public function getObjectName() { return $this->getFilename(); } /** * @return StoredObject::STATUS_* */ public function getStatus(): string { return $this->status; } public function getTitle(): string { return $this->title; } public function getType(): string { return $this->getCurrentVersion()?->getType() ?? ''; } public function getUuid(): UuidInterface { return $this->uuid; } public function getWopiDocId(): string { return (string) $this->uuid; } /** * @deprecated */ #[Serializer\Groups(['write'])] public function setCreationDate(\DateTime $creationDate): self { $this->createdAt = \DateTimeImmutable::createFromMutable($creationDate); return $this; } public function setDatas(?array $datas): self { $this->datas = (array) $datas; return $this; } /** * @param StoredObject::STATUS_* $status */ public function setStatus(string $status): self { $this->status = $status; return $this; } public function setTitle(?string $title): self { $this->title = (string) $title; return $this; } public function getTemplate(): ?DocGeneratorTemplate { return $this->template; } public function getVersions(): Collection { return $this->versions; } public function hasTemplate(): bool { return null !== $this->template; } public function setTemplate(?DocGeneratorTemplate $template): StoredObject { $this->template = $template; return $this; } public function isPending(): bool { return self::STATUS_PENDING === $this->getStatus(); } public function isFailure(): bool { return self::STATUS_FAILURE === $this->getStatus(); } public function getDeleteAt(): ?\DateTimeImmutable { return $this->deleteAt; } public function setDeleteAt(?\DateTimeImmutable $deleteAt): StoredObject { $this->deleteAt = $deleteAt; return $this; } public function getGenerationErrors(): string { return $this->generationErrors; } /** * Adds generation errors to the stored object. * * The existing generation errors are not removed * * @param string $generationErrors the generation errors to be added * * @return StoredObject the modified StoredObject instance */ public function addGenerationErrors(string $generationErrors): StoredObject { $this->generationErrors = $this->generationErrors.$generationErrors."\n"; return $this; } public function registerVersion( array $iv = [], array $keyInfos = [], string $type = '', ?string $filename = null, ): StoredObjectVersion { $version = new StoredObjectVersion( $this, null === $this->getCurrentVersion() ? 0 : $this->getCurrentVersion()->getVersion() + 1, $iv, $keyInfos, $type, $filename ); $this->versions->add($version); if ('empty' === $this->status) { $this->status = self::STATUS_READY; } return $version; } public function removeVersion(StoredObjectVersion $storedObjectVersion): void { if (!$this->versions->contains($storedObjectVersion)) { throw new \UnexpectedValueException('This stored object does not contains this version'); } $this->versions->removeElement($storedObjectVersion); $storedObjectVersion->resetStoredObject(); } /** * @deprecated */ public function saveHistory(): void {} public static function generatePrefix(): string { try { return base_convert(bin2hex(random_bytes(32)), 16, 36); } catch (RandomException) { return uniqid(more_entropy: true); } } /** * Checks if a stored object can be deleted. * * Currently, return true if the deletedAt date is below the current date, and the object * does not contains any version (which must be removed first). * * @param \DateTimeImmutable $now the current date and time * @param StoredObject $storedObject the stored object to check * * @return bool returns true if the stored object can be deleted, false otherwise */ public static function canBeDeleted(\DateTimeImmutable $now, StoredObject $storedObject): bool { return $storedObject->getDeleteAt() < $now && $storedObject->getVersions()->isEmpty(); } }