Skip to content

Commit

Permalink
NEW Provide new class description config and methods.
Browse files Browse the repository at this point in the history
This provides a description of what a class is intented to be used for,
which is useful for content authors picking a class to create in the CMS
UI.
  • Loading branch information
GuySartorelli committed Nov 14, 2024
1 parent 2fb7cfa commit 5b16f7d
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 35 deletions.
50 changes: 49 additions & 1 deletion 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 @@ -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
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: 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 5b16f7d

Please sign in to comment.