Skip to content

Commit

Permalink
Merge pull request #11461 from creative-commoners/pulls/5/class-descr…
Browse files Browse the repository at this point in the history
…iption

New BC-safe API to support CMSMain refactoring
  • Loading branch information
emteknetnz authored Nov 14, 2024
2 parents d74670b + 5b16f7d commit 3896ae7
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 46 deletions.
52 changes: 50 additions & 2 deletions src/ORM/DataObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*/
private static $plural_name = null;

/**
* Description of the class.
* Unlike most configuration, this is usually used uninherited, meaning it should be defined
* on each subclass.
*
* Used in some areas of the CMS, e.g. when selecting what type of record to create.
*/
private static ?string $class_description = null;

/**
* @config
*/
Expand Down Expand Up @@ -940,6 +949,44 @@ public function i18n_plural_name()
return _t(static::class . '.PLURALNAME', $this->plural_name());
}

/**
* Get description for this class
* @return null|string
*/
public function classDescription()
{
return static::config()->get('class_description', Config::UNINHERITED);
}

/**
* Get localised description for this class
* @return null|string
*/
public function i18n_classDescription()
{
$notDefined = 'NOT_DEFINED';
$baseDescription = $this->classDescription() ?? $notDefined;

// Check the new i18n key first
$description = _t(static::class . '.CLASS_DESCRIPTION', $baseDescription);
if ($description !== $baseDescription) {
return $description;
}

// Fall back on the deprecated localisation key
$legacyI18n = _t(static::class . '.DESCRIPTION', $baseDescription);
if ($legacyI18n !== $baseDescription) {
return $legacyI18n;
}

// If there was no description available in config nor in i18n, return null
if ($baseDescription === $notDefined) {
return null;
}
// Return raw description
return $baseDescription;
}

/**
* Standard implementation of a title/label for a specific
* record. Tries to find properties 'Title' or 'Name',
Expand Down Expand Up @@ -3552,7 +3599,7 @@ public static function flush_and_destroy_cache()
*/
public static function reset()
{
DBEnum::flushCache();
DBEnum::reset();
ClassInfo::reset_db_cache();
static::getSchema()->reset();
DataObject::$_cache_get_one = [];
Expand Down Expand Up @@ -4372,7 +4419,8 @@ public function provideI18nEntities()
$singularName = $this->singular_name();
$conjunction = preg_match('/^[aeiou]/i', $singularName ?? '') ? 'An ' : 'A ';
return [
static::class . '.SINGULARNAME' => $this->singular_name(),
static::class . '.CLASS_DESCRIPTION' => $this->classDescription(),
static::class . '.SINGULARNAME' => $singularName,
static::class . '.PLURALNAME' => $pluralName,
static::class . '.PLURALS' => [
'one' => $conjunction . $singularName,
Expand Down
13 changes: 11 additions & 2 deletions src/ORM/FieldType/DBEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace SilverStripe\ORM\FieldType;

use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Resettable;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Forms\DropdownField;
use SilverStripe\ORM\ArrayLib;
use SilverStripe\ORM\Connect\MySQLDatabase;
Expand All @@ -13,7 +15,7 @@
*
* See {@link DropdownField} for a {@link FormField} to select enum values.
*/
class DBEnum extends DBString
class DBEnum extends DBString implements Resettable
{

/**
Expand Down Expand Up @@ -42,8 +44,15 @@ class DBEnum extends DBString

/**
* Clear all cached enum values.
* @deprecated 5.4.0 Use reset() instead.
*/
public static function flushCache()
{
Deprecation::notice('5.4.0', 'Use reset() instead.');
static::reset();
}

public static function reset(): void
{
DBEnum::$enum_cache = [];
}
Expand Down Expand Up @@ -195,7 +204,7 @@ public function getEnum()
* If table or name are not set, or if it is not a valid field on the given table,
* then only known enum values are returned.
*
* Values cached in this method can be cleared via `DBEnum::flushCache();`
* Values cached in this method can be cleared via `DBEnum::reset();`
*
* @return array
*/
Expand Down
6 changes: 3 additions & 3 deletions tests/php/ORM/DBEnumTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public function testObsoleteValues()
// Test values with a record
$obj->Colour = 'Red';
$obj->write();
DBEnum::flushCache();
DBEnum::reset();

$this->assertEquals(
['Red', 'Blue', 'Green'],
Expand All @@ -103,7 +103,7 @@ public function testObsoleteValues()

// If the value is removed from the enum, obsolete content is still retained
$colourField->setEnum(['Blue', 'Green', 'Purple']);
DBEnum::flushCache();
DBEnum::reset();

$this->assertEquals(
['Blue', 'Green', 'Purple', 'Red'], // Red on the end now, because it's obsolete
Expand Down Expand Up @@ -134,7 +134,7 @@ public function testObsoleteValues()
// If obsolete records are deleted, the extra values go away
$obj->delete();
$obj2->delete();
DBEnum::flushCache();
DBEnum::reset();
$this->assertEquals(
['Blue', 'Green'],
$colourField->getEnumObsolete()
Expand Down
8 changes: 4 additions & 4 deletions tests/php/ORM/DataObjectSchemaGenerationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public function testClassNameSpecGeneration()
$schema = DataObject::getSchema();

// Test with blank entries
DBEnum::flushCache();
DBEnum::reset();
$do1 = new TestObject();
$fields = $schema->databaseFields(TestObject::class, false);
// May be overridden from DBClassName to DBClassNameVarchar by config
Expand All @@ -215,7 +215,7 @@ public function testClassNameSpecGeneration()
// Test with instance of subclass
$item1 = new TestIndexObject();
$item1->write();
DBEnum::flushCache();
DBEnum::reset();
$this->assertEquals(
[
TestObject::class,
Expand All @@ -228,7 +228,7 @@ public function testClassNameSpecGeneration()
// Test with instance of main class
$item2 = new TestObject();
$item2->write();
DBEnum::flushCache();
DBEnum::reset();
$this->assertEquals(
[
TestObject::class,
Expand All @@ -243,7 +243,7 @@ public function testClassNameSpecGeneration()
$item1->write();
$item2 = new TestObject();
$item2->write();
DBEnum::flushCache();
DBEnum::reset();
$this->assertEquals(
[
TestObject::class,
Expand Down
140 changes: 106 additions & 34 deletions tests/php/ORM/DataObjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1907,52 +1907,124 @@ public function testManyManyUnlimitedRowCount()
$this->assertEquals(2, $player->Teams()->dataQuery()->query()->unlimitedRowCount());
}

public function provideSingularName(): array
{
return [
[
'class' => DataObjectTest\Player::class,
'expected' => 'Player',
],
[
'class' => DataObjectTest\Team::class,
'expected' => 'Team',
],
[
'class' => DataObjectTest\Fixture::class,
'expected' => 'Fixture',
],
];
}

/**
* Tests that singular_name() generates sensible defaults.
* @dataProvider provideSingularName
*/
public function testSingularName()
public function testSingularName(string $class, string $expected): void
{
$assertions = [
DataObjectTest\Player::class => 'Player',
DataObjectTest\Team::class => 'Team',
DataObjectTest\Fixture::class => 'Fixture',
];
i18n::set_locale('en_NZ');
/** @var DataObject $object */
$object = new $class();
$this->assertEquals(
$expected,
$object->singular_name(),
"Assert that the singular_name for '$class' is correct."
);
$this->assertEquals(
$expected,
$object->i18n_singular_name(),
"Assert that the i18n_singular_name for '$class' is correct."
);
}

foreach ($assertions as $class => $expectedSingularName) {
$this->assertEquals(
$expectedSingularName,
singleton($class)->singular_name(),
"Assert that the singular_name for '$class' is correct."
);
}
public function providePluralName(): array
{
return [
[
'class' => DataObjectTest\Player::class,
'expected' => 'Players',
],
[
'class' => DataObjectTest\Team::class,
'expected' => 'Teams',
],
[
'class' => DataObjectTest\Fixture::class,
'expected' => 'Fixtures',
],
[
'class' => DataObjectTest\Play::class,
'expected' => 'Plays',
],
[
'class' => DataObjectTest\Bogey::class,
'expected' => 'Bogeys',
],
[
'class' => DataObjectTest\Ploy::class,
'expected' => 'Ploys',
],
];
}

/**
* Tests that plural_name() generates sensible defaults.
* @dataProvider providePluralName
*/
public function testPluralName()
{
$assertions = [
DataObjectTest\Player::class => 'Players',
DataObjectTest\Team::class => 'Teams',
DataObjectTest\Fixture::class => 'Fixtures',
DataObjectTest\Play::class => 'Plays',
DataObjectTest\Bogey::class => 'Bogeys',
DataObjectTest\Ploy::class => 'Ploys',
public function testPluralName(string $class, string $expected): void
{
i18n::set_locale('en_NZ');
/** @var DataObject $object */
$object = new $class();
$this->assertEquals(
$expected,
$object->plural_name(),
"Assert that the plural_name for '$class' is correct."
);
$this->assertEquals(
$expected,
$object->i18n_plural_name(),
"Assert that the i18n_plural_name for '$class' is correct."
);
}

public function provideClassDescription(): array
{
return [
'no description by default' => [
'class' => DataObjectTest\Player::class,
'expected' => null,
],
'explicitly set description' => [
'class' => DataObjectTest\Team::class,
'expected' => 'A team of players',
],
'cannot inherit description from superclass' => [
'class' => DataObjectTest\SubTeam::class,
'expected' => null,
],
];
}

/**
* @dataProvider provideClassDescription
*/
public function testClassDescription(string $class, ?string $expected): void
{
i18n::set_locale('en_NZ');
foreach ($assertions as $class => $expectedPluralName) {
$this->assertEquals(
$expectedPluralName,
DataObject::singleton($class)->plural_name(),
"Assert that the plural_name for '$class' is correct."
);
$this->assertEquals(
$expectedPluralName,
DataObject::singleton($class)->i18n_plural_name(),
"Assert that the i18n_plural_name for '$class' is correct."
);
}
/** @var DataObject $object */
$object = new $class();
$this->assertEquals($expected, $object->classDescription());
$this->assertEquals($expected, $object->i18n_classDescription());
}

public function testHasDatabaseField()
Expand Down
2 changes: 2 additions & 0 deletions tests/php/ORM/DataObjectTest/Team.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class Team extends DataObject implements TestOnly
{
private static $table_name = 'DataObjectTest_Team';

private static $class_description = 'A team of players';

private static $db = [
'Title' => 'Varchar',
'DatabaseField' => 'HTMLVarchar',
Expand Down
2 changes: 1 addition & 1 deletion tests/php/Security/SecurityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ public function testSuccessfulLoginAttempts()
public function testDatabaseIsReadyWithInsufficientMemberColumns()
{
Security::clear_database_is_ready();
DBEnum::flushCache();
DBEnum::reset();

// Assumption: The database has been built correctly by the test runner,
// and has all columns present in the ORM
Expand Down
2 changes: 2 additions & 0 deletions tests/php/i18n/i18nTest/MyObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class MyObject extends DataObject implements TestOnly

private static $plural_name = "My Objects";

private static $class_description = 'A class that represents objects';

public function provideI18nEntities()
{
$entities = parent::provideI18nEntities();
Expand Down
1 change: 1 addition & 0 deletions tests/php/i18n/i18nTextCollectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,7 @@ public function testCollectFromEntityProvidersInCustomObject()
'other' => '{count} My Objects',
],
'SilverStripe\i18n\Tests\i18nTest\MyObject.SINGULARNAME' => 'My Object',
'SilverStripe\i18n\Tests\i18nTest\MyObject.CLASS_DESCRIPTION' => 'A class that represents objects',
],
$matches
);
Expand Down

0 comments on commit 3896ae7

Please sign in to comment.