From e3a6cad8a8314f08572013e77a2316fb7626e18b Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Wed, 19 Oct 2022 18:04:48 +1300 Subject: [PATCH] FIX Allow passing objects to InjectionCreator::create() Co-authored-by: Nate Devereux --- src/Core/Injector/InjectionCreator.php | 22 ++++++++++++++++++++-- tests/php/Core/Injector/InjectorTest.php | 23 +++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/Core/Injector/InjectionCreator.php b/src/Core/Injector/InjectionCreator.php index 0c70e3b23..ad91f11d2 100644 --- a/src/Core/Injector/InjectionCreator.php +++ b/src/Core/Injector/InjectionCreator.php @@ -2,18 +2,36 @@ namespace SilverStripe\Core\Injector; +use InvalidArgumentException; + /** * A class for creating new objects by the injector. */ class InjectionCreator implements Factory { + /** + * Create a new instance of a class + * + * Passing an object for $class will result from using an anonymous class in unit testing, e.g. + * Injector::inst()->load([SomeClass::class => ['class' => new class { ... }]]); + * + * @param string|object $class - string: The FQCN of the class, object: A class instance + */ public function create($class, array $params = []) { - if (!class_exists($class ?? '')) { + if (is_object($class ?? '')) { + $class = get_class($class); + } + if (!is_string($class ?? '')) { + throw new InvalidArgumentException('$class parameter must be a string or an object'); + } + if (!class_exists($class)) { throw new InjectorNotFoundException("Class {$class} does not exist"); } + // Ensure there are no string keys as they cannot be unpacked with the `...` operator - $values = array_values($params ?? []); + $values = array_values($params); + return new $class(...$values); } } diff --git a/tests/php/Core/Injector/InjectorTest.php b/tests/php/Core/Injector/InjectorTest.php index 3b8cd1850..66f21d3c1 100644 --- a/tests/php/Core/Injector/InjectorTest.php +++ b/tests/php/Core/Injector/InjectorTest.php @@ -1065,4 +1065,27 @@ class InjectorTest extends SapphireTest Injector::unnest(); $this->nestingLevel--; } + + public function testAnonymousClass() + { + Injector::inst()->load([ + 'Some\\Project\\Class' => [ + // the php anonymous class syntax will instantiate a new anonymous class object, with ('abc') + // passed to the constructor + 'class' => new class ('abc') { + private string $property; + public function __construct(string $value) + { + $this->property = $value; + } + public function foo(): string + { + return $this->property; + } + } + ], + ]); + // assert that Injector creates a new instance of the anonymous class, with ('def') passed to the constructor + $this->assertSame('def', Injector::inst()->create('Some\\Project\\Class', 'def')->foo()); + } }