Skip to content

Commit

Permalink
Merge pull request #6457 from getkirby/v5/changes/memory-storage-handler
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasbestle authored Jun 24, 2024
2 parents fca079f + 4c116b3 commit 8b2e74e
Show file tree
Hide file tree
Showing 11 changed files with 730 additions and 91 deletions.
56 changes: 51 additions & 5 deletions src/Content/ContentStorageHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Kirby\Cms\Language;
use Kirby\Cms\ModelWithContent;
use Kirby\Cms\Page;
use Kirby\Exception\NotFoundException;

/**
* Abstract for content storage handlers;
Expand Down Expand Up @@ -52,7 +53,10 @@ public function all(): Generator
*
* @param array<string, string> $fields Content fields
*/
abstract public function create(VersionId $versionId, Language $language, array $fields): void;
public function create(VersionId $versionId, Language $language, array $fields): void
{
$this->write($versionId, $language, $fields);
}

/**
* Deletes an existing version in an idempotent way if it was already deleted
Expand Down Expand Up @@ -91,6 +95,26 @@ public function dynamicVersions(): array
return $versions;
}

/**
* Checks if a version/language combination exists and otherwise
* will throw a `NotFoundException`
*
* @throws \Kirby\Exception\NotFoundException If the version does not exist
*/
public function ensure(VersionId $versionId, Language $language): void
{
if ($this->exists($versionId, $language) === true) {
return;
}

$message = match($this->model->kirby()->multilang()) {
true => 'Version "' . $versionId . ' (' . $language->code() . ')" does not already exist',
false => 'Version "' . $versionId . '" does not already exist',
};

throw new NotFoundException($message);
}

/**
* Checks if a version exists
*/
Expand All @@ -104,12 +128,21 @@ abstract public function modified(VersionId $versionId, Language $language): int
/**
* Moves content from one version-language combination to another
*/
abstract public function move(
public function move(
VersionId $fromVersionId,
Language $fromLanguage,
VersionId $toVersionId,
Language $toLanguage
): void;
): void {
// read the existing fields
$fields = $this->read($fromVersionId, $fromLanguage);

// create the new version
$this->create($toVersionId, $toLanguage, $fields);

// clean up the old version
$this->delete($fromVersionId, $fromLanguage);
}

/**
* Adapts all versions when converting languages
Expand Down Expand Up @@ -158,7 +191,20 @@ public function touchLanguage(Language $language): void
*
* @param array<string, string> $fields Content fields
*
* @throws \Kirby\Exception\NotFoundException If the version does not exist
* @throws \Kirby\Exception\Exception If the file cannot be written
*/
public function update(VersionId $versionId, Language $language, array $fields): void
{
$this->ensure($versionId, $language);
$this->write($versionId, $language, $fields);
}

/**
* Writes the content fields of an existing version
*
* @param array<string, string> $fields Content fields
*
* @throws \Kirby\Exception\Exception If the content cannot be written
*/
abstract public function update(VersionId $versionId, Language $language, array $fields): void;
abstract protected function write(VersionId $versionId, Language $language, array $fields): void;
}
102 changes: 102 additions & 0 deletions src/Content/MemoryContentStorageHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

namespace Kirby\Content;

use Kirby\Cache\MemoryCache;
use Kirby\Cms\Language;
use Kirby\Cms\ModelWithContent;

/**
* @package Kirby Content
* @author Bastian Allgeier <[email protected]>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://getkirby.com/license
*/
class MemoryContentStorageHandler extends ContentStorageHandler
{
/**
* Cache instance, used to store content in memory
*/
protected MemoryCache $cache;

/**
* Sets up the cache instance
*/
public function __construct(protected ModelWithContent $model)
{
parent::__construct($model);
$this->cache = new MemoryCache();
}

/**
* Returns a unique id for a combination
* of the version id, the language code and the model id
*/
protected function cacheId(VersionId $versionId, Language $language): string
{
return $versionId->value() . '/' . $language->code() . '/' . $this->model->id();
}

/**
* Deletes an existing version in an idempotent way if it was already deleted
*/
public function delete(VersionId $versionId, Language $language): void
{
$this->cache->remove($this->cacheId($versionId, $language));
}

/**
* Checks if a version exists
*/
public function exists(VersionId $versionId, Language $language): bool
{
return $this->cache->exists($this->cacheId($versionId, $language));
}

/**
* Returns the modification timestamp of a version if it exists
*/
public function modified(VersionId $versionId, Language $language): int|null
{
if ($this->exists($versionId, $language) === false) {
return null;
}

return $this->cache->modified($this->cacheId($versionId, $language));
}

/**
* Returns the stored content fields
*
* @return array<string, string>
*
* @throws \Kirby\Exception\NotFoundException If the version does not exist
*/
public function read(VersionId $versionId, Language $language): array
{
$this->ensure($versionId, $language);
return $this->cache->get($this->cacheId($versionId, $language));
}

/**
* Updates the modification timestamp of an existing version
*
* @throws \Kirby\Exception\NotFoundException If the version does not exist
*/
public function touch(VersionId $versionId, Language $language): void
{
$fields = $this->read($versionId, $language);
$this->write($versionId, $language, $fields);
}

/**
* Writes the content fields of an existing version
*
* @param array<string, string> $fields Content fields
*/
protected function write(VersionId $versionId, Language $language, array $fields): void
{
$this->cache->set($this->cacheId($versionId, $language), $fields);
}
}
24 changes: 0 additions & 24 deletions src/Content/PlainTextContentStorageHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,18 +141,6 @@ public function contentFiles(VersionId $versionId): array
];
}

/**
* Creates a new version
*
* @param array<string, string> $fields Content fields
*
* @throws \Kirby\Exception\Exception If the file cannot be written
*/
public function create(VersionId $versionId, Language $language, array $fields): void
{
$this->write($versionId, $language, $fields);
}

/**
* Deletes an existing version in an idempotent way if it was already deleted
*/
Expand Down Expand Up @@ -247,18 +235,6 @@ public function touch(VersionId $versionId, Language $language): void
// @codeCoverageIgnoreEnd
}

/**
* Updates the content fields of an existing version
*
* @param array<string, string> $fields Content fields
*
* @throws \Kirby\Exception\Exception If the file cannot be written
*/
public function update(VersionId $versionId, Language $language, array $fields): void
{
$this->write($versionId, $language, $fields);
}

/**
* Writes the content fields of an existing version
*
Expand Down
12 changes: 1 addition & 11 deletions src/Content/Version.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Kirby\Cms\Language;
use Kirby\Cms\ModelWithContent;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Exception\NotFoundException;

/**
* The Version class handles all actions for a single
Expand Down Expand Up @@ -88,16 +87,7 @@ public function delete(): void
public function ensure(
Language|string $language = 'default'
): void {
if ($this->exists($language) === true) {
return;
}

$message = match($this->model->kirby()->multilang()) {
true => 'Version "' . $this->id . ' (' . $language . ')" does not already exist',
false => 'Version "' . $this->id . '" does not already exist',
};

throw new NotFoundException($message);
$this->model->storage()->ensure($this->id, $this->language($language));
}

/**
Expand Down
14 changes: 14 additions & 0 deletions tests/Cache/MemoryCacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,18 @@ public function testFlushWithMultipleInstances()
$this->assertTrue($cache2->exists('a'));
$this->assertTrue($cache2->exists('b'));
}

/**
* @covers ::modified
*/
public function testModified()
{
$cache = new MemoryCache();

$time = time();

$cache->set('a', 'A basic value');

$this->assertGreaterThanOrEqual($time, $cache->modified('a'));
}
}
Loading

0 comments on commit 8b2e74e

Please sign in to comment.