Merge pull request #9408 from chrometoasters/pulls/classes-with-extension

Add ClassInfo method to get all classes with a given extension applied
This commit is contained in:
Garion Herman 2020-04-20 20:11:01 +12:00 committed by GitHub
commit f94078d963
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 169 additions and 0 deletions

View File

@ -560,4 +560,40 @@ class ClassInfo
static::$_cache_parse[$classSpec] = $result;
return $result;
}
/**
* Returns a list of classes with a particular extension applied
*
* This reflects all extensions added (or removed) both via the configuration API as well as dynamically
* using Extensible::add_extension() and Extensible::remove_extension().
*
* @param string $extensionClass Extension class name
* @param string $baseClassOrObject Class or object to find subclasses of with the extension applied
* @param bool $includeBaseClass Include the base class itself if it has the extension applied?
* @return string[] Class names with the extension applied
* @throws \ReflectionException
*/
public static function classesWithExtension(
string $extensionClass,
string $baseClassOrObject = DataObject::class,
bool $includeBaseClass = false
): array {
// get class names
$baseClass = self::class_name($baseClassOrObject);
// get a list of all subclasses for a given class
$classes = ClassInfo::subclassesFor($baseClass, $includeBaseClass);
// include the base class if required
if ($includeBaseClass) {
$classes = array_merge([strtolower($baseClass) => $baseClass], $classes);
}
// only keep classes with the Extension applied
$classes = array_filter($classes, function ($class) use ($extensionClass) {
return Extensible::has_extension($class, $extensionClass);
});
return $classes;
}
}

View File

@ -6,7 +6,13 @@ use ReflectionException;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Tests\ClassInfoTest\BaseClass;
use SilverStripe\Core\Tests\ClassInfoTest\BaseDataClass;
use SilverStripe\Core\Tests\ClassInfoTest\BaseObject;
use SilverStripe\Core\Tests\ClassInfoTest\ChildClass;
use SilverStripe\Core\Tests\ClassInfoTest\ExtendTest;
use SilverStripe\Core\Tests\ClassInfoTest\ExtendTest2;
use SilverStripe\Core\Tests\ClassInfoTest\ExtendTest3;
use SilverStripe\Core\Tests\ClassInfoTest\ExtensionTest1;
use SilverStripe\Core\Tests\ClassInfoTest\ExtensionTest2;
use SilverStripe\Core\Tests\ClassInfoTest\GrandChildClass;
use SilverStripe\Core\Tests\ClassInfoTest\HasFields;
use SilverStripe\Core\Tests\ClassInfoTest\NoFields;
@ -28,6 +34,10 @@ class ClassInfoTest extends SapphireTest
NoFields::class,
WithCustomTable::class,
WithRelation::class,
BaseObject::class,
ExtendTest::class,
ExtendTest2::class,
ExtendTest3::class,
);
protected function setUp()
@ -189,4 +199,70 @@ class ClassInfoTest extends SapphireTest
ClassInfo::reset_db_cache();
$this->assertEquals($expect, ClassInfo::dataClassesFor(strtolower($classes[2])));
}
/**
* @covers \SilverStripe\Core\ClassInfo::classesWithExtension()
*/
public function testClassesWithExtensionUsingConfiguredExtensions()
{
$expect = [
'silverstripe\\core\\tests\\classinfotest\\extendtest' => ExtendTest::class,
'silverstripe\\core\\tests\\classinfotest\\extendtest2' => ExtendTest2::class,
'silverstripe\\core\\tests\\classinfotest\\extendtest3' => ExtendTest3::class,
];
$this->assertEquals(
$expect,
ClassInfo::classesWithExtension(ExtensionTest1::class, BaseObject::class),
'ClassInfo::testClassesWithExtension() returns class with extensions applied via class config'
);
$expect = [
'silverstripe\\core\\tests\\classinfotest\\extendtest' => ExtendTest::class,
'silverstripe\\core\\tests\\classinfotest\\extendtest2' => ExtendTest2::class,
'silverstripe\\core\\tests\\classinfotest\\extendtest3' => ExtendTest3::class,
];
$this->assertEquals(
$expect,
ClassInfo::classesWithExtension(ExtensionTest1::class, ExtendTest::class, true),
'ClassInfo::testClassesWithExtension() returns class with extensions applied via class config, including the base class'
);
}
/**
* @covers \SilverStripe\Core\ClassInfo::classesWithExtension()
*/
public function testClassesWithExtensionUsingDynamicallyAddedExtensions()
{
$this->assertEquals(
[],
ClassInfo::classesWithExtension(ExtensionTest2::class, BaseObject::class),
'ClassInfo::testClassesWithExtension() returns no classes for extension that hasn\'t been applied yet.'
);
ExtendTest::add_extension(ExtensionTest2::class);
$expect = [
'silverstripe\\core\\tests\\classinfotest\\extendtest2' => ExtendTest2::class,
'silverstripe\\core\\tests\\classinfotest\\extendtest3' => ExtendTest3::class,
];
$this->assertEquals(
$expect,
ClassInfo::classesWithExtension(ExtensionTest2::class, ExtendTest::class),
'ClassInfo::testClassesWithExtension() returns class with extra extension dynamically added'
);
}
/**
* @covers \SilverStripe\Core\ClassInfo::classesWithExtension()
*/
public function testClassesWithExtensionWithDynamicallyRemovedExtensions()
{
ExtendTest::remove_extension(ExtensionTest1::class);
$this->assertEquals(
[],
ClassInfo::classesWithExtension(ExtensionTest1::class, BaseObject::class),
'ClassInfo::testClassesWithExtension() returns no classes after an extension being removed'
);
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace SilverStripe\Core\Tests\ClassInfoTest;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Extensible;
use SilverStripe\Dev\TestOnly;
class BaseObject implements TestOnly
{
use Configurable;
use Extensible;
}

View File

@ -0,0 +1,10 @@
<?php
namespace SilverStripe\Core\Tests\ClassInfoTest;
class ExtendTest extends BaseObject
{
private static $extensions = [
ExtensionTest1::class,
];
}

View File

@ -0,0 +1,7 @@
<?php
namespace SilverStripe\Core\Tests\ClassInfoTest;
class ExtendTest2 extends ExtendTest
{
}

View File

@ -0,0 +1,7 @@
<?php
namespace SilverStripe\Core\Tests\ClassInfoTest;
class ExtendTest3 extends ExtendTest2
{
}

View File

@ -0,0 +1,10 @@
<?php
namespace SilverStripe\Core\Tests\ClassInfoTest;
use SilverStripe\Core\Extension;
use SilverStripe\Dev\TestOnly;
class ExtensionTest1 extends Extension implements TestOnly
{
}

View File

@ -0,0 +1,10 @@
<?php
namespace SilverStripe\Core\Tests\ClassInfoTest;
use SilverStripe\Core\Extension;
use SilverStripe\Dev\TestOnly;
class ExtensionTest2 extends Extension implements TestOnly
{
}