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 32a802d
Show file tree
Hide file tree
Showing 4 changed files with 242 additions and 8 deletions.
26 changes: 19 additions & 7 deletions src/Extension/FluentExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
*
* @template T of DataObject
* @extends DataExtension<T&static>
* @property DataObject|$this $owner
*/
class FluentExtension extends DataExtension
{
Expand Down Expand Up @@ -582,11 +583,11 @@ public function augmentSQL(SQLSelect $query, DataQuery $dataQuery = null)

// Apply substitutions
$localisedPredicate = str_replace($conditionSearch, $conditionReplace, $predicate);

if (empty($localisedPredicate)) {
continue;
}

$where[$index] = [
$localisedPredicate => $parameters
];
Expand Down Expand Up @@ -968,16 +969,27 @@ protected function getRecordLocale()

/**
* Returns the source locale that will display the content for this record
* Source locale for frontend context is used by default as this is the most common use case,
* but you can optionally specify CMS context as well
* Passing null will fall back to whatever context is currently in use in global fluent state
*
* @param bool|null $isFrontend
*
* @return Locale|null
*/
public function getSourceLocale()
public function getSourceLocale(?bool $isFrontend = true): ?Locale
{
$sourceLocale = $this->owner->getField('SourceLocale');
if ($sourceLocale) {
return Locale::getByLocale($sourceLocale);
$currentLocale = FluentState::singleton()->getLocale();

// We do not have any locales set up yet, so there is no source locale to find
if (!$currentLocale) {
return null;
}
return Locale::getDefault();

$owner = $this->owner;
$localeInformation = $owner->LocaleInformation($currentLocale);

return $localeInformation->getSourceLocale($isFrontend);
}

/**
Expand Down
22 changes: 21 additions & 1 deletion src/Model/RecordLocale.php
Original file line number Diff line number Diff line change
Expand Up @@ -360,23 +360,43 @@ 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 case,
* but you can optionally specify CMS context as well
* Passing null will fall back to whatever context is currently in use in global fluent state
*
* @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 such 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;
}

Expand Down
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 32a802d

Please sign in to comment.