From dba4287dff0eaac207836e5d886da17a4f699f8b Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Mon, 6 May 2024 16:15:13 +0200 Subject: [PATCH 1/4] First steps to implement the new Version class --- src/Content/Version.php | 128 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/Content/Version.php diff --git a/src/Content/Version.php b/src/Content/Version.php new file mode 100644 index 0000000000..46a4fd298a --- /dev/null +++ b/src/Content/Version.php @@ -0,0 +1,128 @@ + + * @link https://getkirby.com + * @copyright Bastian Allgeier + * @license https://getkirby.com/license + */ +class Version +{ + public function __construct( + protected ModelWithContent $model, + protected VersionId $id + ) { + } + + /** + * Returns a Content object for the given language + */ + public function content(string $language = 'default'): Content + { + return new Content( + parent: $this->model, + data: $this->model->storage()->read($this->id, $language), + ); + } + + /** + * Creates a new version for the given language + */ + public function create(string $language, array $fields): void + { + $this->model->storage()->create($this->id, $language, $fields); + } + + /** + * Deletes a version by language or for any language + */ + public function delete(string|null $language = null): void + { + // delete a single language + if ($language !== null) { + $this->model->storage()->delete($this->id, $language); + return; + } + + // delete all languages + foreach ($this->model->kirby()->languages() as $language) { + $this->model->storage()->delete($this->id, $language->code()); + } + } + + /** + * Checks if a version exists for the given language + */ + public function exists(string $language = 'default'): bool + { + return $this->model->storage()->exists($this->id, $language); + } + + /** + * Returns the VersionId instance for this version + */ + public function id(): VersionId + { + return $this->id; + } + + /** + * Returns the parent model + */ + public function model(): ModelWithContent + { + return $this->model; + } + + public function move(string $fromLanguage, VersionId $toVersionId, string $toLanguage): void + { + $this->model->storage()->move($this->id, $fromLanguage, $toVersionId, $toLanguage); + } + + /** + * Returns the stored content fields + * + * @param string $lang Code `'default'` in a single-lang installation + * @return array + */ + public function read(string $language = 'default'): array + { + return $this->model->storage()->read($this->id, $language); + } + + /** + * Updates the modification timestamp of an existing version + * + * @param string $lang Code `'default'` in a single-lang installation + * + * @throws \Kirby\Exception\NotFoundException If the version does not exist + */ + public function touch(string $language): void + { + $this->model->storage()->touch($this->id, $language); + } + + /** + * Updates the content fields of an existing version + * + * @param string $lang Code `'default'` in a single-lang installation + * @param array $fields Content fields + * + * @throws \Kirby\Exception\NotFoundException If the version does not exist + */ + public function update(string $language, array $fields): void + { + $this->model->storage()->update($this->id, $language, $fields); + } +} From 9e7c27f32819c612587ab892293bf4b65d4c3998 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Mon, 6 May 2024 17:33:15 +0200 Subject: [PATCH 2/4] First set of unit tests and fixes for the Version class --- src/Content/Version.php | 75 ++++++++++++-- tests/Content/VersionTest.php | 180 ++++++++++++++++++++++++++++++++++ 2 files changed, 246 insertions(+), 9 deletions(-) create mode 100644 tests/Content/VersionTest.php diff --git a/src/Content/Version.php b/src/Content/Version.php index 46a4fd298a..e18baa05f7 100644 --- a/src/Content/Version.php +++ b/src/Content/Version.php @@ -3,6 +3,7 @@ namespace Kirby\Content; use Kirby\Cms\ModelWithContent; +use Kirby\Exception\NotFoundException; /** * The Version class handles all actions for a single @@ -39,7 +40,7 @@ public function content(string $language = 'default'): Content /** * Creates a new version for the given language */ - public function create(string $language, array $fields): void + public function create(array $fields, string $language = 'default'): void { $this->model->storage()->create($this->id, $language, $fields); } @@ -49,15 +50,35 @@ public function create(string $language, array $fields): void */ public function delete(string|null $language = null): void { - // delete a single language - if ($language !== null) { - $this->model->storage()->delete($this->id, $language); + // delete all languages + if ($language === null) { + foreach ($this->model->kirby()->languages() as $language) { + $this->model->storage()->delete($this->id, $language->code()); + } + } + + // delete the default language in single-language mode + if ($this->model->kirby()->multilang() === false) { + $this->model->storage()->delete($this->id, 'default'); return; } - // delete all languages - foreach ($this->model->kirby()->languages() as $language) { - $this->model->storage()->delete($this->id, $language->code()); + // delete a single language + $this->model->storage()->delete($this->id, $language); + return; + } + + /** + * Ensure that the version exists and otherwise + * throw an exception + * + * @throws \Kirby\Exception\NotFoundException if the version does not exist + */ + public function ensure( + string $language = 'default' + ): void { + if ($this->exists($language) !== true) { + throw new NotFoundException('Version "' . $this->id . ' (' . $language . ')" does not already exist'); } } @@ -85,8 +106,25 @@ public function model(): ModelWithContent return $this->model; } + /** + * Returns the modification timestamp of a version + * if it exists + * + * @param string $lang Code `'default'` in a single-lang installation + */ + public function modified( + string $language = 'default' + ): int|null { + $this->ensure($language); + return $this->model->storage()->modified($this->id, $language); + } + + /** + * Moves the version to a new language and/or version + */ public function move(string $fromLanguage, VersionId $toVersionId, string $toLanguage): void { + $this->ensure($fromLanguage); $this->model->storage()->move($this->id, $fromLanguage, $toVersionId, $toLanguage); } @@ -98,6 +136,7 @@ public function move(string $fromLanguage, VersionId $toVersionId, string $toLan */ public function read(string $language = 'default'): array { + $this->ensure($language); return $this->model->storage()->read($this->id, $language); } @@ -108,8 +147,25 @@ public function read(string $language = 'default'): array * * @throws \Kirby\Exception\NotFoundException If the version does not exist */ - public function touch(string $language): void + public function touch(string|null $language = null): void { + // touch all languages + if ($language === null) { + foreach ($this->model->kirby()->languages() as $language) { + $this->touch($language->code()); + } + } + + // make sure the version exists + $this->ensure($language); + + // touch the default language in single-language mode + if ($this->model->kirby()->multilang() === false) { + $this->model->storage()->touch($this->id, 'default'); + return; + } + + // touch a single language $this->model->storage()->touch($this->id, $language); } @@ -121,8 +177,9 @@ public function touch(string $language): void * * @throws \Kirby\Exception\NotFoundException If the version does not exist */ - public function update(string $language, array $fields): void + public function update(array $fields, string $language = 'default'): void { + $this->ensure($language); $this->model->storage()->update($this->id, $language, $fields); } } diff --git a/tests/Content/VersionTest.php b/tests/Content/VersionTest.php new file mode 100644 index 0000000000..fc476a15ff --- /dev/null +++ b/tests/Content/VersionTest.php @@ -0,0 +1,180 @@ +model = new Page([ + 'kirby' => new App(), + 'root' => static::TMP, + 'slug' => 'a-page', + 'template' => 'article' + ]); + } + + public function tearDown(): void + { + App::destroy(); + Dir::remove(static::TMP); + } + + /** + * @covers ::create + */ + public function testCreate(): void + { + $version = new Version( + model: $this->model, + id: VersionId::published() + ); + + $this->assertFalse($version->exists()); + + $version->create([ + 'title' => 'Test' + ]); + + $this->assertTrue($version->exists()); + } + + /** + * @covers ::create + */ + public function testCreateLanguage(): void + { + $version = new Version( + model: $this->model, + id: VersionId::published() + ); + + $this->assertFalse($version->exists('de')); + + $version->create([ + 'title' => 'Test' + ], 'de'); + + $this->assertTrue($version->exists('de')); + } + + /** + * @covers ::delete + */ + public function testDelete(): void + { + $version = new Version( + model: $this->model, + id: VersionId::published() + ); + + $this->assertFalse($version->exists()); + + $version->create([ + 'title' => 'Test' + ]); + + $this->assertTrue($version->exists()); + + $version->delete(); + + $this->assertFalse($version->exists()); + } + + /** + * @covers ::exists + */ + public function testExists(): void + { + $version = new Version( + model: $this->model, + id: VersionId::published() + ); + + $this->assertFalse($version->exists()); + + $version->create([]); + + $this->assertTrue($version->exists()); + } + + /** + * @covers ::id + */ + public function testId(): void + { + $version = new Version( + model: $this->model, + id: $id = VersionId::published() + ); + + $this->assertSame($id, $version->id()); + } + + /** + * @covers ::model + */ + public function testModel(): void + { + $version = new Version( + model: $this->model, + id: VersionId::published() + ); + + $this->assertSame($this->model, $version->model()); + } + + /** + * @covers ::read + */ + public function testRead(): void + { + $version = new Version( + model: $this->model, + id: VersionId::published() + ); + + $version->create($content = [ + 'title' => 'Test' + ]); + + $this->assertSame($content, $version->read()); + } + + /** + * @covers ::update + */ + public function testUpdate(): void + { + $version = new Version( + model: $this->model, + id: VersionId::published() + ); + + $version->create([ + 'title' => 'Test' + ]); + + $this->assertSame('Test', $version->read()['title']); + + $version->create([ + 'title' => 'Updated Title' + ]); + + $this->assertSame('Updated Title', $version->read()['title']); + } +} From a9f038d85833ad553077fcc490d1be9e83b6d581 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Thu, 16 May 2024 15:07:18 +0200 Subject: [PATCH 3/4] Fix CS issues --- src/Content/Version.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Content/Version.php b/src/Content/Version.php index e18baa05f7..5d6613d0b2 100644 --- a/src/Content/Version.php +++ b/src/Content/Version.php @@ -65,12 +65,12 @@ public function delete(string|null $language = null): void // delete a single language $this->model->storage()->delete($this->id, $language); - return; + } /** * Ensure that the version exists and otherwise - * throw an exception + * throw an exception * * @throws \Kirby\Exception\NotFoundException if the version does not exist */ @@ -130,7 +130,7 @@ public function move(string $fromLanguage, VersionId $toVersionId, string $toLan /** * Returns the stored content fields - * + * * @param string $lang Code `'default'` in a single-lang installation * @return array */ @@ -172,8 +172,8 @@ public function touch(string|null $language = null): void /** * Updates the content fields of an existing version * - * @param string $lang Code `'default'` in a single-lang installation * @param array $fields Content fields + * @param string $lang Code `'default'` in a single-lang installation * * @throws \Kirby\Exception\NotFoundException If the version does not exist */ From 073d0a5c477396f40d86bd86356bceae919204d8 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Wed, 5 Jun 2024 10:40:12 +0200 Subject: [PATCH 4/4] Fix ::update unit test --- tests/Content/VersionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Content/VersionTest.php b/tests/Content/VersionTest.php index fc476a15ff..d8f528e2dc 100644 --- a/tests/Content/VersionTest.php +++ b/tests/Content/VersionTest.php @@ -171,7 +171,7 @@ public function testUpdate(): void $this->assertSame('Test', $version->read()['title']); - $version->create([ + $version->update([ 'title' => 'Updated Title' ]);