Skip to content

Commit

Permalink
Merge pull request #6442 from getkirby/v5/changes/version-class
Browse files Browse the repository at this point in the history
Changes 3: New Version class
  • Loading branch information
bastianallgeier authored Jun 5, 2024
2 parents 2c487bc + 073d0a5 commit 362e86a
Show file tree
Hide file tree
Showing 2 changed files with 365 additions and 0 deletions.
185 changes: 185 additions & 0 deletions src/Content/Version.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<?php

namespace Kirby\Content;

use Kirby\Cms\ModelWithContent;
use Kirby\Exception\NotFoundException;

/**
* The Version class handles all actions for a single
* version and is identified by a VersionId instance
*
* @internal
* @since 5.0.0
*
* @package Kirby Content
* @author Bastian Allgeier <[email protected]>
* @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(array $fields, string $language = 'default'): 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 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 a single language
$this->model->storage()->delete($this->id, $language);

}

/**
* 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');
}
}

/**
* 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;
}

/**
* 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);
}

/**
* Returns the stored content fields
*
* @param string $lang Code `'default'` in a single-lang installation
* @return array<string, string>
*/
public function read(string $language = 'default'): array
{
$this->ensure($language);
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|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);
}

/**
* Updates the content fields of an existing version
*
* @param array<string, string> $fields Content fields
* @param string $lang Code `'default'` in a single-lang installation
*
* @throws \Kirby\Exception\NotFoundException If the version does not exist
*/
public function update(array $fields, string $language = 'default'): void
{
$this->ensure($language);
$this->model->storage()->update($this->id, $language, $fields);
}
}
180 changes: 180 additions & 0 deletions tests/Content/VersionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
<?php

namespace Kirby\Content;

use Kirby\Cms\App;
use Kirby\Cms\Page;
use Kirby\Filesystem\Dir;
use Kirby\TestCase;

/**
* @coversDefaultClass Kirby\Content\Version
*/
class VersionTest extends TestCase
{
public const TMP = KIRBY_TMP_DIR . '/Content.Version';

protected $model;

public function setUp(): void
{
Dir::make(static::TMP);

$this->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->update([
'title' => 'Updated Title'
]);

$this->assertSame('Updated Title', $version->read()['title']);
}
}

0 comments on commit 362e86a

Please sign in to comment.