mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
Merge pull request #530 from nyeholt/injector_updates
A resubmission of a previous pull request. Contains a couple of bugfixes (including ticket #7448) and minor usage enhancements
This commit is contained in:
commit
dda9683758
@ -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';
|
||||
@ -224,6 +230,30 @@ class Injector {
|
||||
$this->objectCreator = $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor (for testing purposes)
|
||||
* @return InjectionCreator
|
||||
*/
|
||||
public function getObjectCreator() {
|
||||
return $this->objectCreator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the configuration locator
|
||||
* @param ServiceConfigurationLocator $configLocator
|
||||
*/
|
||||
public function setConfigLocator($configLocator) {
|
||||
$this->configLocator = $configLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the configuration locator
|
||||
* @return ServiceConfigurationLocator
|
||||
*/
|
||||
public function getConfigLocator() {
|
||||
return $this->configLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add in a specific mapping that should be catered for on a type.
|
||||
* This allows configuration of what should occur when an object
|
||||
@ -418,8 +448,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 +477,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 +695,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 +730,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 +765,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
|
||||
|
@ -249,6 +249,12 @@ require_once 'core/manifest/ManifestFileFinder.php';
|
||||
require_once 'core/manifest/TemplateLoader.php';
|
||||
require_once 'core/manifest/TemplateManifest.php';
|
||||
require_once 'core/manifest/TokenisedRegularExpression.php';
|
||||
require_once 'control/injector/Injector.php';
|
||||
|
||||
// Initialise the dependency injector as soon as possible, as it is
|
||||
// subsequently used by some of the following code
|
||||
$default_options = array('locator' => 'SilverStripeServiceConfigurationLocator');
|
||||
Injector::inst($default_options);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MANIFEST
|
||||
@ -286,9 +292,6 @@ if(Director::isLive()) {
|
||||
*/
|
||||
Debug::loadErrorHandlers();
|
||||
|
||||
// initialise the dependency injector
|
||||
$default_options = array('locator' => 'SilverStripeServiceConfigurationLocator');
|
||||
Injector::inst($default_options);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// HELPER FUNCTIONS
|
||||
|
@ -12,6 +12,12 @@ define('TEST_SERVICES', dirname(__FILE__) . '/testservices');
|
||||
*/
|
||||
class InjectorTest extends SapphireTest {
|
||||
|
||||
public function testCorrectlyInitialised() {
|
||||
$injector = Injector::inst();
|
||||
$this->assertTrue($injector->getConfigLocator() instanceof SilverStripeServiceConfigurationLocator,
|
||||
'If this fails, it is likely because the injector has been referenced BEFORE being initialised in Core.php');
|
||||
}
|
||||
|
||||
public function testBasicInjector() {
|
||||
$injector = new Injector();
|
||||
$injector->setAutoScanProperties(true);
|
||||
@ -209,6 +215,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 +463,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…
x
Reference in New Issue
Block a user