mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-12 13:24:25 +00:00
Add versioning to stored objects
This update introduces a versioning system to the stored objects in the ChillDocStoreBundle. The 'StoredObject' entity now includes several new methods, and maintains a collection of 'StoredObjectVersion' instances. Each time a 'StoredObject' is modified, a new version instance is created and added to the collection, ensuring a history of changes. Migration file for the addition of new database column included. Corresponding tests are also updated.
This commit is contained in:
parent
8a374864fa
commit
2b7ea4178b
@ -16,9 +16,12 @@ use ChampsLibres\WopiLib\Contract\Entity\Document;
|
|||||||
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
|
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
|
||||||
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
||||||
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
|
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Ramsey\Uuid\Uuid;
|
use Ramsey\Uuid\Uuid;
|
||||||
use Ramsey\Uuid\UuidInterface;
|
use Ramsey\Uuid\UuidInterface;
|
||||||
|
use Random\RandomException;
|
||||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,9 +31,12 @@ use Symfony\Component\Serializer\Annotation as Serializer;
|
|||||||
*
|
*
|
||||||
* The property `$deleteAt` allow a deletion of the document after the given date. But this property should
|
* The property `$deleteAt` allow a deletion of the document after the given date. But this property should
|
||||||
* be set before the document is actually written by the StoredObjectManager.
|
* be set before the document is actually written by the StoredObjectManager.
|
||||||
|
*
|
||||||
|
* Each version is stored within a @see{StoredObjectVersion}, associated with this current's object. The creation
|
||||||
|
* of each new version should be done using the method @see{self::registerVersion}.
|
||||||
*/
|
*/
|
||||||
#[ORM\Entity]
|
#[ORM\Entity]
|
||||||
#[ORM\Table('chill_doc.stored_object')]
|
#[ORM\Table('stored_object', schema: 'chill_doc')]
|
||||||
#[AsyncFileExists(message: 'The file is not stored properly')]
|
#[AsyncFileExists(message: 'The file is not stored properly')]
|
||||||
class StoredObject implements Document, TrackCreationInterface
|
class StoredObject implements Document, TrackCreationInterface
|
||||||
{
|
{
|
||||||
@ -43,9 +49,11 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON, name: 'datas')]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON, name: 'datas')]
|
||||||
private array $datas = [];
|
private array $datas = [];
|
||||||
|
|
||||||
#[Serializer\Groups(['write'])]
|
/**
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT)]
|
* the prefix of each version.
|
||||||
private string $filename = '';
|
*/
|
||||||
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: false, options: ['default' => ''])]
|
||||||
|
private string $prefix = '';
|
||||||
|
|
||||||
#[Serializer\Groups(['write'])]
|
#[Serializer\Groups(['write'])]
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
@ -53,25 +61,10 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
||||||
private ?int $id = null;
|
private ?int $id = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int[]
|
|
||||||
*/
|
|
||||||
#[Serializer\Groups(['write'])]
|
#[Serializer\Groups(['write'])]
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON, name: 'iv')]
|
#[ORM\Column(name: 'title', type: \Doctrine\DBAL\Types\Types::TEXT, options: ['default' => ''])]
|
||||||
private array $iv = [];
|
|
||||||
|
|
||||||
#[Serializer\Groups(['write'])]
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON, name: 'key')]
|
|
||||||
private array $keyInfos = [];
|
|
||||||
|
|
||||||
#[Serializer\Groups(['write'])]
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, name: 'title')]
|
|
||||||
private string $title = '';
|
private string $title = '';
|
||||||
|
|
||||||
#[Serializer\Groups(['write'])]
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, name: 'type', options: ['default' => ''])]
|
|
||||||
private string $type = '';
|
|
||||||
|
|
||||||
#[Serializer\Groups(['write'])]
|
#[Serializer\Groups(['write'])]
|
||||||
#[ORM\Column(type: 'uuid', unique: true)]
|
#[ORM\Column(type: 'uuid', unique: true)]
|
||||||
private UuidInterface $uuid;
|
private UuidInterface $uuid;
|
||||||
@ -94,6 +87,12 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: false, options: ['default' => ''])]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: false, options: ['default' => ''])]
|
||||||
private string $generationErrors = '';
|
private string $generationErrors = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Collection<int, StoredObjectVersion>
|
||||||
|
*/
|
||||||
|
#[ORM\OneToMany(targetEntity: StoredObjectVersion::class, cascade: ['persist'], mappedBy: 'storedObject')]
|
||||||
|
private Collection $versions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param StoredObject::STATUS_* $status
|
* @param StoredObject::STATUS_* $status
|
||||||
*/
|
*/
|
||||||
@ -102,6 +101,8 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
private string $status = 'ready'
|
private string $status = 'ready'
|
||||||
) {
|
) {
|
||||||
$this->uuid = Uuid::uuid4();
|
$this->uuid = Uuid::uuid4();
|
||||||
|
$this->versions = new ArrayCollection();
|
||||||
|
$this->prefix = self::generatePrefix();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addGenerationTrial(): self
|
public function addGenerationTrial(): self
|
||||||
@ -125,14 +126,32 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
return \DateTime::createFromImmutable($this->createdAt);
|
return \DateTime::createFromImmutable($this->createdAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
public function getDatas(): array
|
||||||
{
|
{
|
||||||
return $this->datas;
|
return $this->datas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPrefix(): string
|
||||||
|
{
|
||||||
|
return $this->prefix;
|
||||||
|
}
|
||||||
|
|
||||||
public function getFilename(): string
|
public function getFilename(): string
|
||||||
{
|
{
|
||||||
return $this->filename;
|
return $this->getCurrentVersion()?->getFilename() ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getGenerationTrialsCounter(): int
|
public function getGenerationTrialsCounter(): int
|
||||||
@ -145,14 +164,17 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<int>
|
||||||
|
*/
|
||||||
public function getIv(): array
|
public function getIv(): array
|
||||||
{
|
{
|
||||||
return $this->iv;
|
return $this->getCurrentVersion()?->getIv() ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getKeyInfos(): array
|
public function getKeyInfos(): array
|
||||||
{
|
{
|
||||||
return $this->keyInfos;
|
return $this->getCurrentVersion()?->getKeyInfos() ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,14 +193,14 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
return $this->status;
|
return $this->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTitle()
|
public function getTitle(): string
|
||||||
{
|
{
|
||||||
return $this->title;
|
return $this->title;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getType()
|
public function getType(): string
|
||||||
{
|
{
|
||||||
return $this->type;
|
return $this->getCurrentVersion()?->getType() ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUuid(): UuidInterface
|
public function getUuid(): UuidInterface
|
||||||
@ -209,27 +231,6 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setFilename(?string $filename): self
|
|
||||||
{
|
|
||||||
$this->filename = (string) $filename;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setIv(?array $iv): self
|
|
||||||
{
|
|
||||||
$this->iv = (array) $iv;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setKeyInfos(?array $keyInfos): self
|
|
||||||
{
|
|
||||||
$this->keyInfos = (array) $keyInfos;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param StoredObject::STATUS_* $status
|
* @param StoredObject::STATUS_* $status
|
||||||
*/
|
*/
|
||||||
@ -247,18 +248,16 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setType(?string $type): self
|
|
||||||
{
|
|
||||||
$this->type = (string) $type;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTemplate(): ?DocGeneratorTemplate
|
public function getTemplate(): ?DocGeneratorTemplate
|
||||||
{
|
{
|
||||||
return $this->template;
|
return $this->template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getVersions(): Collection
|
||||||
|
{
|
||||||
|
return $this->versions;
|
||||||
|
}
|
||||||
|
|
||||||
public function hasTemplate(): bool
|
public function hasTemplate(): bool
|
||||||
{
|
{
|
||||||
return null !== $this->template;
|
return null !== $this->template;
|
||||||
@ -314,6 +313,29 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
return $this;
|
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);
|
||||||
|
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
public function saveHistory(): void
|
public function saveHistory(): void
|
||||||
{
|
{
|
||||||
if ('' === $this->getFilename()) {
|
if ('' === $this->getFilename()) {
|
||||||
@ -328,4 +350,13 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
'before' => (new \DateTimeImmutable('now'))->getTimestamp(),
|
'before' => (new \DateTimeImmutable('now'))->getTimestamp(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function generatePrefix(): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return base_convert(bin2hex(random_bytes(8)), 16, 36);
|
||||||
|
} catch (RandomException $e) {
|
||||||
|
return uniqid(more_entropy: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
127
src/Bundle/ChillDocStoreBundle/Entity/StoredObjectVersion.php
Normal file
127
src/Bundle/ChillDocStoreBundle/Entity/StoredObjectVersion.php
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\DocStoreBundle\Entity;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
||||||
|
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Random\RandomException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store each version of StoredObject's.
|
||||||
|
*
|
||||||
|
* A version should not be created manually: use the method @see{StoredObject::registerVersion} instead.
|
||||||
|
*/
|
||||||
|
#[ORM\Entity]
|
||||||
|
#[ORM\Table('chill_doc.stored_object_version')]
|
||||||
|
#[ORM\UniqueConstraint(name: 'chill_doc_stored_object_version_unique_by_object', columns: ['stored_object_id', 'version'])]
|
||||||
|
class StoredObjectVersion implements TrackCreationInterface
|
||||||
|
{
|
||||||
|
use TrackCreationTrait;
|
||||||
|
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filename of the version in the stored object.
|
||||||
|
*/
|
||||||
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: false, options: ['default' => ''])]
|
||||||
|
private string $filename = '';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
/**
|
||||||
|
* The stored object associated with this version.
|
||||||
|
*/
|
||||||
|
#[ORM\ManyToOne(targetEntity: StoredObject::class, inversedBy: 'versions')]
|
||||||
|
#[ORM\JoinColumn(name: 'stored_object_id', nullable: true)]
|
||||||
|
private StoredObject $storedObject,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The incremental version.
|
||||||
|
*/
|
||||||
|
#[ORM\Column(name: 'version', type: \Doctrine\DBAL\Types\Types::INTEGER, options: ['default' => 0])]
|
||||||
|
private int $version = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vector for encryption.
|
||||||
|
*
|
||||||
|
* @var int[]
|
||||||
|
*/
|
||||||
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON, name: 'iv')]
|
||||||
|
private array $iv = [],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key infos for document encryption.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON, name: 'key')]
|
||||||
|
private array $keyInfos = [],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* type of the document.
|
||||||
|
*/
|
||||||
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, name: 'type', options: ['default' => ''])]
|
||||||
|
private string $type = '',
|
||||||
|
?string $filename = null,
|
||||||
|
) {
|
||||||
|
$this->filename = $filename ?? self::generateFilename($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function generateFilename(StoredObjectVersion $storedObjectVersion): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$suffix = base_convert(bin2hex(random_bytes(16)), 16, 36);
|
||||||
|
} catch (RandomException $e) {
|
||||||
|
$suffix = uniqid(more_entropy: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $storedObjectVersion->getStoredObject()->getPrefix().'/'.$suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFilename(): string
|
||||||
|
{
|
||||||
|
return $this->filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIv(): array
|
||||||
|
{
|
||||||
|
return $this->iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKeyInfos(): array
|
||||||
|
{
|
||||||
|
return $this->keyInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStoredObject(): StoredObject
|
||||||
|
{
|
||||||
|
return $this->storedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType(): string
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVersion(): int
|
||||||
|
{
|
||||||
|
return $this->version;
|
||||||
|
}
|
||||||
|
}
|
@ -25,18 +25,22 @@ class StoredObjectTest extends KernelTestCase
|
|||||||
{
|
{
|
||||||
$storedObject = new StoredObject();
|
$storedObject = new StoredObject();
|
||||||
$storedObject
|
$storedObject
|
||||||
->setFilename('test_0')
|
->registerVersion(
|
||||||
->setIv([2, 4, 6, 8])
|
[2, 4, 6, 8],
|
||||||
->setKeyInfos(['key' => ['data0' => 'data0']])
|
['key' => ['data0' => 'data0']],
|
||||||
->setType('text/html');
|
'text/html',
|
||||||
|
'test_0',
|
||||||
|
);
|
||||||
|
|
||||||
$storedObject->saveHistory();
|
$storedObject->saveHistory();
|
||||||
|
|
||||||
$storedObject
|
$storedObject
|
||||||
->setFilename('test_1')
|
->registerVersion(
|
||||||
->setIv([8, 10, 12])
|
[8, 10, 12],
|
||||||
->setKeyInfos(['key' => ['data1' => 'data1']])
|
['key' => ['data1' => 'data1']],
|
||||||
->setType('text/text');
|
'text/text',
|
||||||
|
'test_1',
|
||||||
|
);
|
||||||
|
|
||||||
$storedObject->saveHistory();
|
$storedObject->saveHistory();
|
||||||
|
|
||||||
@ -50,4 +54,33 @@ class StoredObjectTest extends KernelTestCase
|
|||||||
self::assertEquals(['key' => ['data1' => 'data1']], $storedObject->getDatas()['history'][1]['key_infos']);
|
self::assertEquals(['key' => ['data1' => 'data1']], $storedObject->getDatas()['history'][1]['key_infos']);
|
||||||
self::assertEquals('text/text', $storedObject->getDatas()['history'][1]['type']);
|
self::assertEquals('text/text', $storedObject->getDatas()['history'][1]['type']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRegisterVersion(): void
|
||||||
|
{
|
||||||
|
$object = new StoredObject();
|
||||||
|
$firstVersion = $object->registerVersion(
|
||||||
|
[5, 6, 7, 8],
|
||||||
|
['key' => ['some key']],
|
||||||
|
'text/html',
|
||||||
|
);
|
||||||
|
$version = $object->registerVersion(
|
||||||
|
[1, 2, 3, 4],
|
||||||
|
$k = ['key' => ['data0' => 'data0']],
|
||||||
|
'text/text',
|
||||||
|
'abcde',
|
||||||
|
);
|
||||||
|
|
||||||
|
self::assertCount(2, $object->getVersions());
|
||||||
|
self::assertEquals('abcde', $object->getFilename());
|
||||||
|
self::assertEquals([1, 2, 3, 4], $object->getIv());
|
||||||
|
self::assertEqualsCanonicalizing($k, $object->getKeyInfos());
|
||||||
|
self::assertEquals('text/text', $object->getType());
|
||||||
|
|
||||||
|
self::assertEquals('abcde', $version->getFilename());
|
||||||
|
self::assertEquals([1, 2, 3, 4], $version->getIv());
|
||||||
|
self::assertEqualsCanonicalizing($k, $version->getKeyInfos());
|
||||||
|
self::assertEquals('text/text', $version->getType());
|
||||||
|
|
||||||
|
self::assertNotSame($firstVersion, $version);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\Migrations\DocStore;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20240709102730 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Add versioning to stored objects';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('CREATE SEQUENCE chill_doc.stored_object_version_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql(
|
||||||
|
<<<'SQL'
|
||||||
|
CREATE TABLE chill_doc.stored_object_version (
|
||||||
|
id INT NOT NULL,
|
||||||
|
stored_object_id INT DEFAULT NULL,
|
||||||
|
version INT DEFAULT 0 NOT NULL,
|
||||||
|
filename TEXT NOT NULL,
|
||||||
|
iv JSON NOT NULL,
|
||||||
|
key JSON NOT NULL,
|
||||||
|
type TEXT DEFAULT '' NOT NULL,
|
||||||
|
createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL,
|
||||||
|
createdBy_id INT DEFAULT NULL,
|
||||||
|
PRIMARY KEY(id))
|
||||||
|
SQL
|
||||||
|
);
|
||||||
|
$this->addSql('CREATE INDEX IDX_C1D55302232D562B ON chill_doc.stored_object_version (stored_object_id)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_C1D553023174800F ON chill_doc.stored_object_version (createdBy_id)');
|
||||||
|
$this->addSql('CREATE UNIQUE INDEX chill_doc_stored_object_version_unique_by_object ON chill_doc.stored_object_version (stored_object_id, version)');
|
||||||
|
$this->addSql('COMMENT ON COLUMN chill_doc.stored_object_version.createdAt IS \'(DC2Type:datetime_immutable)\'');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object_version ADD CONSTRAINT FK_C1D55302232D562B FOREIGN KEY (stored_object_id) REFERENCES chill_doc.stored_object (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object_version ADD CONSTRAINT FK_C1D553023174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql(
|
||||||
|
<<<'SQL'
|
||||||
|
INSERT INTO chill_doc.stored_object_version (id, stored_object_id, version, filename, iv, key, type)
|
||||||
|
SELECT nextval('chill_doc.stored_object_version_id_seq'), id, 1, filename, iv, key, type FROM chill_doc.stored_object
|
||||||
|
SQL
|
||||||
|
);
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object RENAME COLUMN filename TO prefix');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object DROP key');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object DROP iv');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object DROP type');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object ALTER title SET DEFAULT \'\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('DROP SEQUENCE chill_doc.stored_object_version_id_seq CASCADE');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object RENAME COLUMN prefix TO filename');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object ADD type TEXT NOT NULL DEFAULT \'\'');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object ADD key JSON NOT NULL DEFAULT \'{}\'');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object ADD iv JSON NOT NULL DEFAULT \'[]\'');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object ALTER title DROP DEFAULT');
|
||||||
|
$this->addSql(
|
||||||
|
<<<'SQL'
|
||||||
|
UPDATE chill_doc.stored_object SET filename=sov.filename, type=sov.type, iv=sov.iv, key=sov.key
|
||||||
|
FROM chill_doc.stored_object_version sov WHERE sov.stored_object_id = stored_object.id
|
||||||
|
AND sov.version = (SELECT MAX(version) FROM chill_doc.stored_object_version AS sub_sov WHERE sub_sov.stored_object_id = stored_object.id)
|
||||||
|
SQL
|
||||||
|
);
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object_version DROP CONSTRAINT FK_C1D55302232D562B');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object_version DROP CONSTRAINT FK_C1D553023174800F');
|
||||||
|
$this->addSql('DROP TABLE chill_doc.stored_object_version');
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user