Skip to content

Commit

Permalink
FIX: Source locale indicator correction.
Browse files Browse the repository at this point in the history
  • Loading branch information
mfendeksilverstripe committed Apr 8, 2024
1 parent 7bf314a commit 37d1813
Show file tree
Hide file tree
Showing 3 changed files with 231 additions and 1 deletion.
30 changes: 29 additions & 1 deletion src/Model/RecordLocale.php
Original file line number Diff line number Diff line change
Expand Up @@ -360,26 +360,54 @@ public function getStagesDiffer(): bool

/**
* Get the locale which is the source of content for this record
* Source locale for frontend context is used by default as this is the most common use,
* but you can optionally specify CMS context as well
* Passing null will fall back to whatever context is currently in use
*
* @param bool|null $isFrontend
* @return Locale|null
*/
public function getSourceLocale(): ?Locale
public function getSourceLocale(?bool $isFrontend = true): ?Locale
{
$isFrontend ??= FluentState::singleton()->getIsFrontend();

/** @var DataObject|FluentExtension $record */
$record = $this->getOriginalRecord();
$config = $record->config();

$inheritanceMode = $isFrontend
? $config->get('frontend_publish_required')
: $config->get('cms_localisation_required');

// This model has localised data in the current locale so the current locale is also the source locale
if ($record->existsInLocale($this->getLocale())) {
return $this->getLocaleObject();
}

// This model requires localisation so fallback of any kind is not allowed
// hence the content can't come from another locale
// We don't have a source locale for this case
if ($inheritanceMode === FluentExtension::INHERITANCE_MODE_EXACT) {
return null;
}

foreach ($this->getLocaleObject()->Fallbacks() as $fallback) {
if (!$record->existsInLocale($fallback->Locale)) {
continue;
}

// We found a locale to fall back to, so this will be our source locale
return $fallback;
}

// Noting here that we have another case here that isn't handled correctly
// In case this model allows fallback to any locale even bypassing the fallback rules,
// so we just need to find the most recently updated locale
// as that's the one which is going to be providing content
// This is what we call base record fallback
// It's technically possible to figure out which locale the content is coming from but
// displaying this information may actually be confusing so just displaying no source might be more helpful

return null;
}
}
189 changes: 189 additions & 0 deletions tests/php/Extension/LocaleInheritanceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
<?php

namespace TractorCow\Fluent\Tests\Extension;

use Page;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\ValidationException;
use SilverStripe\Versioned\Versioned;
use TractorCow\Fluent\Extension\FluentExtension;
use TractorCow\Fluent\Extension\FluentSiteTreeExtension;
use TractorCow\Fluent\State\FluentState;

class LocaleInheritanceTest extends SapphireTest
{
protected static $fixture_file = 'LocaleInheritanceTest.yml';

protected static $required_extensions = [
SiteTree::class => [
FluentSiteTreeExtension::class,
],
];

/**
* @param string $cmsInheritanceMode
* @param string $frontendInheritanceMode
* @param bool $frontendContext
* @param string $locale
* @param string|null $expected
* @return void
* @throws ValidationException
* @dataProvider sourceLocaleCasesProvider
*/
public function testGetSourceLocale(
string $cmsInheritanceMode,
string $frontendInheritanceMode,
bool $frontendContext,
string $locale,
?string $expected
): void {
Page::config()
->set('cms_localisation_required', $cmsInheritanceMode)
->set('frontend_publish_required', $frontendInheritanceMode);

Versioned::withVersionedMode(function () use ($frontendContext, $locale, $expected): void {
// Make sure we have the correct stage set
Versioned::set_stage(Versioned::DRAFT);

// Create the page in the default locale
FluentState::singleton()->withState(
function (FluentState $state) use ($frontendContext, $locale, $expected): void {
$state
->setLocale('en_US')
->setIsFrontend($frontendContext);

/** @var Page|FluentExtension $page */
$page = Page::create();
$page->Title = 'Page title';
$page->URLSegment = 'test-page';
$page->write();

$localeInformation = $page->LocaleInformation($locale);
$sourceLocaleObject = $localeInformation->getSourceLocale($frontendContext);
$sourceLocale = $sourceLocaleObject?->Locale;
$this->assertEquals(
$expected,
$sourceLocale,
'We expect a specific source locale (locale information)'
);

if (!$sourceLocale) {
return;
}

// Re-fetch the page in the target locale
$state->setLocale($locale);

/** @var Page|FluentExtension $page */
$page = Page::get()->byID($page->ID);

$this->assertNotNull($page, 'We expect the page to be available in this locale');
$sourceLocaleObject = $page->getSourceLocale($frontendContext);
$this->assertEquals(
$expected,
$sourceLocaleObject->Locale,
'We expect a specific source locale (page shorthand method)'
);
}
);
});
}

public function sourceLocaleCasesProvider(): array
{
return [
'default locale, cms with any mode, frontend with any mode, frontend context' => [
FluentExtension::INHERITANCE_MODE_ANY,
FluentExtension::INHERITANCE_MODE_ANY,
true,
'en_US',
'en_US',
],
'default locale, cms with exact mode, frontend with any mode, frontend context' => [
FluentExtension::INHERITANCE_MODE_EXACT,
FluentExtension::INHERITANCE_MODE_ANY,
true,
'en_US',
'en_US',
],
'default locale, cms with any mode, frontend with exact mode, frontend context' => [
FluentExtension::INHERITANCE_MODE_ANY,
FluentExtension::INHERITANCE_MODE_EXACT,
true,
'en_US',
'en_US',
],
'fallback locale, cms with any mode, frontend with any mode, frontend context' => [
FluentExtension::INHERITANCE_MODE_ANY,
FluentExtension::INHERITANCE_MODE_ANY,
true,
'de_DE',
'en_US',
],
'fallback locale, cms with exact mode, frontend with any mode, frontend context' => [
FluentExtension::INHERITANCE_MODE_EXACT,
FluentExtension::INHERITANCE_MODE_ANY,
true,
'de_DE',
'en_US',
],
'fallback locale, cms with any mode, frontend with exact mode, frontend context' => [
FluentExtension::INHERITANCE_MODE_ANY,
FluentExtension::INHERITANCE_MODE_EXACT,
true,
'de_DE',
null,
],
'fallback locale, cms with any mode, frontend with fallback mode, frontend context' => [
FluentExtension::INHERITANCE_MODE_ANY,
FluentExtension::INHERITANCE_MODE_FALLBACK,
true,
'de_DE',
'en_US',
],
'fallback locale, cms with any mode, frontend with exact mode, cms context' => [
FluentExtension::INHERITANCE_MODE_ANY,
FluentExtension::INHERITANCE_MODE_EXACT,
false,
'de_DE',
'en_US',
],
'no fallback locale, cms with any mode, frontend with any mode, frontend context' => [
FluentExtension::INHERITANCE_MODE_ANY,
FluentExtension::INHERITANCE_MODE_ANY,
true,
'es_ES',
null,
],
'no fallback locale, cms with exact mode, frontend with any mode, frontend context' => [
FluentExtension::INHERITANCE_MODE_EXACT,
FluentExtension::INHERITANCE_MODE_ANY,
true,
'es_ES',
null,
],
'no fallback locale, cms with any mode, frontend with exact mode, frontend context' => [
FluentExtension::INHERITANCE_MODE_ANY,
FluentExtension::INHERITANCE_MODE_EXACT,
true,
'es_ES',
null,
],
'no fallback locale, cms with any mode, frontend with fallback mode, frontend context' => [
FluentExtension::INHERITANCE_MODE_ANY,
FluentExtension::INHERITANCE_MODE_FALLBACK,
true,
'es_ES',
null,
],
'no fallback locale, cms with any mode, frontend with exact mode, cms context' => [
FluentExtension::INHERITANCE_MODE_ANY,
FluentExtension::INHERITANCE_MODE_EXACT,
false,
'es_ES',
null,
],
];
}
}
13 changes: 13 additions & 0 deletions tests/php/Extension/LocaleInheritanceTest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
TractorCow\Fluent\Model\Locale:
default:
Title: US English
Locale: en_US
IsGlobalDefault: true
german:
Title: German
Locale: de_DE
Fallbacks:
- =>TractorCow\Fluent\Model\Locale.default
spanish:
Title: Spanish
Locale: es_ES

0 comments on commit 37d1813

Please sign in to comment.