mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
BUGFIX Make sure to only construct args for prototype object creation if
there are actually args passed through to prevent overwriting with null args if they're passed MINOR Added __get alias to remove need for explicit ->get() call MINOR Added the injector instance as an object that can be injected into other classes BUGFIX Fixed issue described in http://open.silverstripe.org/ticket/7448 whereby using the injector to create an object of a type already registered as a singleton would actually overwrite the stored singleton object
This commit is contained in:
parent
e23a7585a7
commit
56388ef1d8
@ -176,9 +176,15 @@ class Injector {
|
||||
*/
|
||||
public function __construct($config = null) {
|
||||
$this->injectMap = array();
|
||||
$this->serviceCache = array();
|
||||
$this->serviceCache = array(
|
||||
'Injector' => $this,
|
||||
);
|
||||
$this->specs = array(
|
||||
'Injector' => array('class' => 'Injector')
|
||||
);
|
||||
|
||||
$this->autoProperties = array();
|
||||
$this->specs = array();
|
||||
|
||||
|
||||
$creatorClass = isset($config['creator']) ? $config['creator'] : 'InjectionCreator';
|
||||
$locatorClass = isset($config['locator']) ? $config['locator'] : 'ServiceConfigurationLocator';
|
||||
@ -418,8 +424,14 @@ class Injector {
|
||||
*
|
||||
* @param array $spec
|
||||
* The specification of the class to instantiate
|
||||
* @param string $id
|
||||
* The name of the object being created. If not supplied, then the id will be inferred from the
|
||||
* object being created
|
||||
* @param string $type
|
||||
* Whether to create as a singleton or prototype object. Allows code to be explicit as to how it
|
||||
* wants the object to be returned
|
||||
*/
|
||||
protected function instantiate($spec, $id=null) {
|
||||
protected function instantiate($spec, $id=null, $type = null) {
|
||||
if (is_string($spec)) {
|
||||
$spec = array('class' => $spec);
|
||||
}
|
||||
@ -441,7 +453,10 @@ class Injector {
|
||||
|
||||
// now set the service in place if needbe. This is NOT done for prototype beans, as they're
|
||||
// created anew each time
|
||||
$type = isset($spec['type']) ? $spec['type'] : null;
|
||||
if (!$type) {
|
||||
$type = isset($spec['type']) ? $spec['type'] : null;
|
||||
}
|
||||
|
||||
if ($id && (!$type || $type != 'prototype')) {
|
||||
// this ABSOLUTELY must be set before the object is injected.
|
||||
// This prevents circular reference errors down the line
|
||||
@ -656,7 +671,7 @@ class Injector {
|
||||
* Clear out all objects that are managed by the injetor.
|
||||
*/
|
||||
public function unregisterAllObjects() {
|
||||
$this->serviceCache = array();
|
||||
$this->serviceCache = array('Injector' => $this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -691,12 +706,12 @@ class Injector {
|
||||
$spec = $this->specs[$serviceName];
|
||||
$type = isset($spec['type']) ? $spec['type'] : null;
|
||||
|
||||
// if we're a prototype OR we're not wanting a singleton
|
||||
// if we're explicitly a prototype OR we're not wanting a singleton
|
||||
if (($type && $type == 'prototype') || !$asSingleton) {
|
||||
if ($spec) {
|
||||
if ($spec && $constructorArgs) {
|
||||
$spec['constructor'] = $constructorArgs;
|
||||
}
|
||||
return $this->instantiate($spec, $serviceName);
|
||||
return $this->instantiate($spec, $serviceName, !$type ? 'prototype' : $type);
|
||||
} else {
|
||||
if (!isset($this->serviceCache[$serviceName])) {
|
||||
$this->instantiate($spec, $serviceName);
|
||||
@ -726,6 +741,17 @@ class Injector {
|
||||
|
||||
return $this->instantiate($spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to return an item directly
|
||||
*
|
||||
* @param string $name
|
||||
* The named object to retrieve
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name) {
|
||||
return $this->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to get() but always returns a new object of the given type
|
||||
|
@ -209,6 +209,42 @@ class InjectorTest extends SapphireTest {
|
||||
$sample = $injector->get('SampleService');
|
||||
$this->assertEquals($sample->constructorVarOne, 'val1');
|
||||
$this->assertEquals(get_class($sample->constructorVarTwo), 'AnotherService');
|
||||
|
||||
$injector = new Injector();
|
||||
$config = array(array(
|
||||
'src' => TEST_SERVICES . '/SampleService.php',
|
||||
'constructor' => array(
|
||||
'val1',
|
||||
'val2',
|
||||
)
|
||||
));
|
||||
|
||||
$injector->load($config);
|
||||
$sample = $injector->get('SampleService');
|
||||
$this->assertEquals($sample->constructorVarOne, 'val1');
|
||||
$this->assertEquals($sample->constructorVarTwo, 'val2');
|
||||
|
||||
// test constructors on prototype
|
||||
$injector = new Injector();
|
||||
$config = array(array(
|
||||
'type' => 'prototype',
|
||||
'src' => TEST_SERVICES . '/SampleService.php',
|
||||
'constructor' => array(
|
||||
'val1',
|
||||
'val2',
|
||||
)
|
||||
));
|
||||
|
||||
$injector->load($config);
|
||||
$sample = $injector->get('SampleService');
|
||||
$this->assertEquals($sample->constructorVarOne, 'val1');
|
||||
$this->assertEquals($sample->constructorVarTwo, 'val2');
|
||||
|
||||
$again = $injector->get('SampleService');
|
||||
$this->assertFalse($sample === $again);
|
||||
|
||||
$this->assertEquals($sample->constructorVarOne, 'val1');
|
||||
$this->assertEquals($sample->constructorVarTwo, 'val2');
|
||||
}
|
||||
|
||||
public function testInjectUsingSetter() {
|
||||
@ -421,6 +457,27 @@ class InjectorTest extends SapphireTest {
|
||||
$obj = $injector->get('MyChildClass');
|
||||
$this->assertEquals($obj->one, 'the one');
|
||||
}
|
||||
|
||||
public function testSameNamedSingeltonPrototype() {
|
||||
$injector = new Injector();
|
||||
|
||||
// get a singleton object
|
||||
$object = $injector->get('NeedsBothCirculars');
|
||||
$object->var = 'One';
|
||||
|
||||
$again = $injector->get('NeedsBothCirculars');
|
||||
$this->assertEquals($again->var, 'One');
|
||||
|
||||
// create a NEW instance object
|
||||
$new = $injector->create('NeedsBothCirculars');
|
||||
$this->assertNull($new->var);
|
||||
|
||||
// this will trigger a problem below
|
||||
$new->var = 'Two';
|
||||
|
||||
$again = $injector->get('NeedsBothCirculars');
|
||||
$this->assertEquals($again->var, 'One');
|
||||
}
|
||||
}
|
||||
|
||||
class TestObject {
|
||||
|
Loading…
Reference in New Issue
Block a user