From 5b16f7de82037e9363f5ff6402d40652dae42614 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Tue, 12 Nov 2024 10:50:15 +1300 Subject: [PATCH] NEW Provide new class description config and methods. 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. --- src/ORM/DataObject.php | 50 +++++++- tests/php/ORM/DataObjectTest.php | 140 +++++++++++++++++------ tests/php/ORM/DataObjectTest/Team.php | 2 + tests/php/i18n/i18nTest/MyObject.php | 2 + tests/php/i18n/i18nTextCollectorTest.php | 1 + 5 files changed, 160 insertions(+), 35 deletions(-) diff --git a/src/ORM/DataObject.php b/src/ORM/DataObject.php index 96909dcbe17..76172c96177 100644 --- a/src/ORM/DataObject.php +++ b/src/ORM/DataObject.php @@ -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 */ @@ -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', @@ -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, diff --git a/tests/php/ORM/DataObjectTest.php b/tests/php/ORM/DataObjectTest.php index af99c2decc5..fec9aa4c164 100644 --- a/tests/php/ORM/DataObjectTest.php +++ b/tests/php/ORM/DataObjectTest.php @@ -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() diff --git a/tests/php/ORM/DataObjectTest/Team.php b/tests/php/ORM/DataObjectTest/Team.php index 07c0b310ec6..42de8d3ad56 100644 --- a/tests/php/ORM/DataObjectTest/Team.php +++ b/tests/php/ORM/DataObjectTest/Team.php @@ -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', diff --git a/tests/php/i18n/i18nTest/MyObject.php b/tests/php/i18n/i18nTest/MyObject.php index 63b2e76254d..9405faad7a2 100644 --- a/tests/php/i18n/i18nTest/MyObject.php +++ b/tests/php/i18n/i18nTest/MyObject.php @@ -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(); diff --git a/tests/php/i18n/i18nTextCollectorTest.php b/tests/php/i18n/i18nTextCollectorTest.php index 5005c814a8e..6c3600738f4 100644 --- a/tests/php/i18n/i18nTextCollectorTest.php +++ b/tests/php/i18n/i18nTextCollectorTest.php @@ -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 );