Skip to content

Commit

Permalink
Merge pull request #6448 from getkirby/v5/changes/language-type-hinting
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasbestle authored Jun 10, 2024
2 parents 5f81c72 + 04cbfdd commit 8c8dcbb
Show file tree
Hide file tree
Showing 10 changed files with 589 additions and 312 deletions.
36 changes: 33 additions & 3 deletions src/Cms/Language.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Language implements Stringable
protected string $direction;
protected array $locale;
protected string $name;
protected bool $single;
protected array $slugs;
protected array $smartypants;
protected array $translations;
Expand All @@ -64,6 +65,7 @@ public function __construct(array $props)
$this->default = ($props['default'] ?? false) === true;
$this->direction = ($props['direction'] ?? null) === 'rtl' ? 'rtl' : 'ltr';
$this->name = trim($props['name'] ?? $this->code);
$this->single = $props['single'] ?? false;
$this->slugs = $props['slugs'] ?? [];
$this->smartypants = $props['smartypants'] ?? [];
$this->translations = $props['translations'] ?? [];
Expand Down Expand Up @@ -177,8 +179,8 @@ public static function create(array $props): static
if ($languages->count() === 0) {
foreach ($kirby->models() as $model) {
$model->storage()->convertLanguage(
'default',
$language->code()
Language::single(),
$language
);
}
}
Expand Down Expand Up @@ -225,7 +227,7 @@ public function delete(): bool

foreach ($kirby->models() as $model) {
if ($this->isLast() === true) {
$model->storage()->convertLanguage($code, 'default');
$model->storage()->convertLanguage($this, Language::single());
} else {
$model->storage()->deleteLanguage($code);
}
Expand Down Expand Up @@ -272,6 +274,11 @@ public function isDefault(): bool
*/
public function isDeletable(): bool
{
// a single-language object cannot be deleted
if ($this->isSingle() === true) {
return false;
}

// the default language can only be deleted if it's the last
if ($this->isDefault() === true && $this->isLast() === false) {
return false;
Expand All @@ -288,6 +295,15 @@ public function isLast(): bool
return App::instance()->languages()->count() === 1;
}

/**
* Checks if this is the single language object
* @internal
*/
public function isSingle(): bool
{
return $this->single;
}

/**
* The id is required for collections
* to work properly. The code is used as id
Expand Down Expand Up @@ -446,6 +462,20 @@ protected function siblingsCollection(): Languages
return App::instance()->languages();
}

/**
* Create a placeholder language object in a
* single-language installation
*/
public static function single(): static
{
return new static([
'code' => 'en',
'default' => true,
'locale' => App::instance()->option('locale', 'en_US.utf-8'),
'single' => true
]);
}

/**
* Returns the custom slug rules for this language
*/
Expand Down
55 changes: 22 additions & 33 deletions src/Content/ContentStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Kirby\Content;

use Generator;
use Kirby\Cms\Language;
use Kirby\Cms\ModelWithContent;
use Kirby\Cms\Page;
use Kirby\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -73,21 +74,17 @@ public function all(): Generator
public function contentFile(
VersionId $versionId,
string $lang,
bool $force = false
): string {
$lang = $this->language($lang, $force);
$lang = $this->language($lang);
return $this->handler->contentFile($versionId, $lang);
}

/**
* Adapts all versions when converting languages
* @internal
*/
public function convertLanguage(string $from, string $to): void
public function convertLanguage(Language $from, Language $to): void
{
$from = $this->language($from, true);
$to = $this->language($to, true);

foreach ($this->dynamicVersions() as $versionId) {
$this->handler->move($versionId, $from, $versionId, $to);
}
Expand Down Expand Up @@ -116,9 +113,8 @@ public function create(
public function delete(
VersionId $versionId,
string|null $lang = null,
bool $force = false
): void {
$lang = $this->language($lang, $force);
$lang = $this->language($lang);
$this->handler->delete($versionId, $lang);
}

Expand All @@ -128,7 +124,7 @@ public function delete(
*/
public function deleteLanguage(string|null $lang): void
{
$lang = $this->language($lang, true);
$lang = $this->language($lang);

foreach ($this->dynamicVersions() as $version) {
$this->handler->delete($version, $lang);
Expand Down Expand Up @@ -218,7 +214,7 @@ public function touch(
*/
public function touchLanguage(string|null $lang): void
{
$lang = $this->language($lang, true);
$lang = $this->language($lang);

foreach ($this->dynamicVersions() as $version) {
if ($this->exists($version, $lang) === true) {
Expand Down Expand Up @@ -253,41 +249,34 @@ protected function ensureExistingVersion(
string $lang
): void {
if ($this->exists($versionId, $lang) !== true) {
throw new NotFoundException('Version "' . $versionId . ' (' . $lang . ')" does not already exist');

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

throw new NotFoundException($message);
}
}

/**
* Converts a "user-facing" language code to a "raw" language code to be
* used for storage
*
* @param bool $force If set to `true`, the language code is not validated
* @return string Language code
*/
protected function language(
string|null $languageCode = null,
bool $force = false
): string {
// in force mode, use the provided language code even in single-lang for
// compatibility with the previous behavior in `$model->contentFile()`
if ($force === true) {
return $languageCode ?? 'default';
): Language {
// single language
if ($this->model->kirby()->multilang() === false) {
return Language::single();
}

// in multi-lang, …
if ($this->model->kirby()->multilang() === true) {
// look up the actual language object if possible
$language = $this->model->kirby()->language($languageCode);

// validate the language code
if ($language === null) {
throw new InvalidArgumentException('Invalid language: ' . $languageCode);
}

return $language->code();
// look up the actual language object if possible
if ($language = $this->model->kirby()->language($languageCode)) {
return $language;
}

// otherwise use hardcoded "default" code for single lang
return 'default';
// validate the language code
throw new InvalidArgumentException('Invalid language: ' . $languageCode);
}
}
33 changes: 10 additions & 23 deletions src/Content/ContentStorageHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Kirby\Content;

use Kirby\Cms\Language;
use Kirby\Cms\ModelWithContent;

/**
Expand All @@ -25,71 +26,57 @@ public function __construct(ModelWithContent $model);
/**
* Creates a new version
*
* @param string $lang Code `'default'` in a single-lang installation
* @param array<string, string> $fields Content fields
*/
public function create(VersionId $versionId, string $lang, array $fields): void;
public function create(VersionId $versionId, Language $language, array $fields): void;

/**
* Deletes an existing version in an idempotent way if it was already deleted
*
* @param string $lang Code `'default'` in a single-lang installation
*/
public function delete(VersionId $versionId, string $lang): void;
public function delete(VersionId $versionId, Language $language): void;

/**
* Checks if a version exists
*
* @param string $lang Code `'default'` in a single-lang installation
*/
public function exists(VersionId $versionId, string $lang): bool;
public function exists(VersionId $versionId, Language $language): bool;

/**
* Returns the modification timestamp of a version if it exists
*
* @param string $lang Code `'default'` in a single-lang installation
*/
public function modified(VersionId $versionId, string $lang): int|null;
public function modified(VersionId $versionId, Language $language): int|null;

/**
* Moves content from one version-language combination to another
*
* @param string $fromLang Code `'default'` in a single-lang installation
* @param string $toLang Code `'default'` in a single-lang installation
*/
public function move(
VersionId $fromVersionId,
string $fromLang,
Language $fromLanguage,
VersionId $toVersionId,
string $toLang
Language $toLanguage
): void;

/**
* Returns the stored content fields
*
* @param string $lang Code `'default'` in a single-lang installation
* @return array<string, string>
*
* @throws \Kirby\Exception\NotFoundException If the version does not exist
*/
public function read(VersionId $versionId, string $lang): array;
public function read(VersionId $versionId, Language $language): array;

/**
* 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(VersionId $versionId, string $lang): void;
public function touch(VersionId $versionId, Language $language): void;

/**
* Updates the content fields of an existing version
*
* @param string $lang Code `'default'` in a single-lang installation
* @param array<string, string> $fields Content fields
*
* @throws \Kirby\Exception\NotFoundException If the version does not exist
*/
public function update(VersionId $versionId, string $lang, array $fields): void;
public function update(VersionId $versionId, Language $language, array $fields): void;
}
3 changes: 1 addition & 2 deletions src/Content/ContentTranslation.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ public function contentFile(): string
{
return $this->contentFile = $this->parent->storage()->contentFile(
VersionId::default($this->parent),
$this->code,
true
$this->code
);
}

Expand Down
Loading

0 comments on commit 8c8dcbb

Please sign in to comment.