silverstripe-framework/tests/php/Core/Injector/InjectorTest.php

902 lines
26 KiB
PHP
Raw Normal View History

<?php
2016-10-14 03:30:05 +02:00
namespace SilverStripe\Core\Tests\Injector;
use InvalidArgumentException;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Injector\SilverStripeServiceConfigurationLocator;
2016-10-14 03:30:05 +02:00
use SilverStripe\Core\Tests\Injector\AopProxyServiceTest\AnotherService;
use SilverStripe\Core\Tests\Injector\AopProxyServiceTest\SampleService;
use SilverStripe\Core\Tests\Injector\InjectorTest\CircularOne;
use SilverStripe\Core\Tests\Injector\InjectorTest\CircularTwo;
use SilverStripe\Core\Tests\Injector\InjectorTest\ConstructableObject;
use SilverStripe\Core\Tests\Injector\InjectorTest\DummyRequirements;
use SilverStripe\Core\Tests\Injector\InjectorTest\MyChildClass;
use SilverStripe\Core\Tests\Injector\InjectorTest\MyParentClass;
use SilverStripe\Core\Tests\Injector\InjectorTest\NeedsBothCirculars;
use SilverStripe\Core\Tests\Injector\InjectorTest\NewRequirementsBackend;
use SilverStripe\Core\Tests\Injector\InjectorTest\OriginalRequirementsBackend;
use SilverStripe\Core\Tests\Injector\InjectorTest\OtherTestObject;
use SilverStripe\Core\Tests\Injector\InjectorTest\TestObject;
use SilverStripe\Core\Tests\Injector\InjectorTest\TestSetterInjections;
use SilverStripe\Core\Tests\Injector\InjectorTest\TestStaticInjections;
use SilverStripe\Dev\SapphireTest;
2016-10-14 03:30:05 +02:00
use stdClass;
2016-10-14 03:30:05 +02:00
define('TEST_SERVICES', __DIR__ . '/AopProxyServiceTest');
/**
* Tests for the dependency injector
2014-08-15 08:53:05 +02:00
*
* Note that these are SS conversions of the existing Simpletest unit tests
*
* @author marcus@silverstripe.com.au
* @license BSD License http://silverstripe.org/bsd-license/
2016-10-14 03:30:05 +02:00
* @skipUpgrade
*/
class InjectorTest extends SapphireTest {
2014-08-15 08:53:05 +02:00
protected $nestingLevel = 0;
2014-08-15 08:53:05 +02:00
public function setUp() {
parent::setUp();
2014-08-15 08:53:05 +02:00
$this->nestingLevel = 0;
}
2014-08-15 08:53:05 +02:00
public function tearDown() {
2014-08-15 08:53:05 +02:00
while($this->nestingLevel > 0) {
$this->nestingLevel--;
Config::unnest();
}
2014-08-15 08:53:05 +02:00
parent::tearDown();
}
2014-08-15 08:53:05 +02:00
public function testCorrectlyInitialised() {
$injector = Injector::inst();
$this->assertTrue($injector->getConfigLocator() instanceof SilverStripeServiceConfigurationLocator,
'Failure most likely because the injector has been referenced BEFORE being initialised in Core.php');
}
2014-08-15 08:53:05 +02:00
public function testBasicInjector() {
$injector = new Injector();
$injector->setAutoScanProperties(true);
2016-10-14 03:30:05 +02:00
$config = array(
'SampleService' => array(
'src' => TEST_SERVICES . '/SampleService.php',
'class' => SampleService::class,
)
);
$injector->load($config);
2016-10-14 03:30:05 +02:00
$this->assertEquals(
'SampleService',
$injector->hasService('SampleService')
);
$myObject = new TestObject();
$injector->inject($myObject);
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(
SampleService::class,
$myObject->sampleService
);
}
public function testConfiguredInjector() {
$injector = new Injector();
$services = array(
2016-10-14 03:30:05 +02:00
'AnotherService' => array(
'class' => AnotherService::class,
'src' => TEST_SERVICES . '/AnotherService.php',
'properties' => array('config_property' => 'Value'),
),
2016-10-14 03:30:05 +02:00
'SampleService' => array(
'class' => SampleService::class,
'src' => TEST_SERVICES . '/SampleService.php',
)
);
$injector->load($services);
2016-10-14 03:30:05 +02:00
$this->assertEquals(
'SampleService',
$injector->hasService('SampleService')
);
// We expect a false because the AnotherService::class is actually
// just a replacement of the SilverStripe\Core\Tests\Injector\AopProxyServiceTest\SampleService
$this->assertEquals(
'AnotherService',
$injector->hasService('AnotherService')
);
$item = $injector->get('AnotherService');
$this->assertEquals('Value', $item->config_property);
}
public function testIdToNameMap() {
$injector = new Injector();
$services = array(
2016-10-14 03:30:05 +02:00
'FirstId' => AnotherService::class,
'SecondId' => SampleService::class,
);
$injector->load($services);
$this->assertTrue($injector->hasService('FirstId') == 'FirstId');
$this->assertTrue($injector->hasService('SecondId') == 'SecondId');
$this->assertTrue($injector->get('FirstId') instanceof AnotherService);
$this->assertTrue($injector->get('SecondId') instanceof SampleService);
}
public function testReplaceService() {
$injector = new Injector();
$injector->setAutoScanProperties(true);
2016-10-14 03:30:05 +02:00
$config = array(
'SampleService' => array(
'src' => TEST_SERVICES . '/SampleService.php',
'class' => SampleService::class,
)
);
// load
$injector->load($config);
// inject
$myObject = new TestObject();
$injector->inject($myObject);
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(
SampleService::class,
$myObject->sampleService
);
// also tests that ID can be the key in the array
2016-10-14 03:30:05 +02:00
$config = array(
'SampleService' => array(
'src' => TEST_SERVICES . '/AnotherService.php',
'class' => AnotherService::class,
)
);
// , 'id' => SampleService::class));
// load
$injector->load($config);
$injector->inject($myObject);
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(
AnotherService::class,
$myObject->sampleService
);
}
2014-08-15 08:53:05 +02:00
public function testUpdateSpec() {
$injector = new Injector();
$services = array(
2016-10-14 03:30:05 +02:00
AnotherService::class => array(
'src' => TEST_SERVICES . '/AnotherService.php',
'properties' => array(
'filters' => array(
'One',
'Two',
)
),
)
);
$injector->load($services);
2014-08-15 08:53:05 +02:00
2016-10-14 03:30:05 +02:00
$injector->updateSpec(AnotherService::class, 'filters', 'Three');
$another = $injector->get(AnotherService::class);
2014-08-15 08:53:05 +02:00
$this->assertEquals(3, count($another->filters));
$this->assertEquals('Three', $another->filters[2]);
}
public function testAutoSetInjector() {
$injector = new Injector();
$injector->setAutoScanProperties(true);
$injector->addAutoProperty('auto', 'somevalue');
2016-10-14 03:30:05 +02:00
$config = array(
'SampleService' => array(
'src' => TEST_SERVICES . '/SampleService.php',
'class' => SampleService::class
)
);
$injector->load($config);
2016-10-14 03:30:05 +02:00
$this->assertEquals(
'SampleService',
$injector->hasService('SampleService')
);
// We expect a false because the AnotherService::class is actually
// just a replacement of the SilverStripe\Core\Tests\Injector\AopProxyServiceTest\SampleService
2016-10-14 03:30:05 +02:00
$myObject = new InjectorTest\TestObject();
$injector->inject($myObject);
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(
SampleService::class,
$myObject->sampleService
);
$this->assertEquals($myObject->auto, 'somevalue');
}
public function testSettingSpecificProperty() {
$injector = new Injector();
2016-10-14 03:30:05 +02:00
$config = array(AnotherService::class);
$injector->load($config);
2016-10-14 03:30:05 +02:00
$injector->setInjectMapping(TestObject::class, 'sampleService', AnotherService::class);
$testObject = $injector->get(TestObject::class);
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(
AnotherService::class,
$testObject->sampleService
);
}
public function testSettingSpecificMethod() {
$injector = new Injector();
2016-10-14 03:30:05 +02:00
$config = array(AnotherService::class);
$injector->load($config);
2016-10-14 03:30:05 +02:00
$injector->setInjectMapping(TestObject::class, 'setSomething', AnotherService::class, 'method');
2016-10-14 03:30:05 +02:00
$testObject = $injector->get(TestObject::class);
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(
AnotherService::class,
$testObject->sampleService
);
}
2014-08-15 08:53:05 +02:00
public function testInjectingScopedService() {
$injector = new Injector();
2014-08-15 08:53:05 +02:00
$config = array(
2016-10-14 03:30:05 +02:00
AnotherService::class,
'SilverStripe\Core\Tests\Injector\AopProxyServiceTest\AnotherService.DottedChild' => SampleService::class,
);
2014-08-15 08:53:05 +02:00
$injector->load($config);
2014-08-15 08:53:05 +02:00
2016-10-14 03:30:05 +02:00
$service = $injector->get('SilverStripe\Core\Tests\Injector\AopProxyServiceTest\AnotherService.DottedChild');
$this->assertInstanceOf(SampleService::class, $service);
2014-08-15 08:53:05 +02:00
2016-10-14 03:30:05 +02:00
$service = $injector->get('SilverStripe\Core\Tests\Injector\AopProxyServiceTest\AnotherService.Subset');
$this->assertInstanceOf(AnotherService::class, $service);
2014-08-15 08:53:05 +02:00
2016-10-14 03:30:05 +02:00
$injector->setInjectMapping(TestObject::class, 'sampleService', 'SilverStripe\Core\Tests\Injector\AopProxyServiceTest\AnotherService.Geronimo');
$testObject = $injector->create(TestObject::class);
$this->assertEquals(get_class($testObject->sampleService), AnotherService::class);
2014-08-15 08:53:05 +02:00
2016-10-14 03:30:05 +02:00
$injector->setInjectMapping(TestObject::class, 'sampleService', 'SilverStripe\Core\Tests\Injector\AopProxyServiceTest\AnotherService.DottedChild.AnotherDown');
$testObject = $injector->create(TestObject::class);
$this->assertEquals(get_class($testObject->sampleService), SampleService::class);
2014-08-15 08:53:05 +02:00
}
public function testInjectUsingConstructor() {
$injector = new Injector();
2016-10-14 03:30:05 +02:00
$config = array(
'SampleService' => array(
'src' => TEST_SERVICES . '/SampleService.php',
2016-10-14 03:30:05 +02:00
'class' => SampleService::class,
'constructor' => array(
'val1',
'val2',
)
2016-10-14 03:30:05 +02:00
)
);
$injector->load($config);
$sample = $injector->get('SampleService');
$this->assertEquals($sample->constructorVarOne, 'val1');
$this->assertEquals($sample->constructorVarTwo, 'val2');
$injector = new Injector();
$config = array(
2016-10-14 03:30:05 +02:00
'AnotherService' => AnotherService::class,
'SampleService' => array(
'src' => TEST_SERVICES . '/SampleService.php',
2016-10-14 03:30:05 +02:00
'class' => SampleService::class,
'constructor' => array(
'val1',
'%$AnotherService',
)
)
);
$injector->load($config);
$sample = $injector->get('SampleService');
$this->assertEquals($sample->constructorVarOne, 'val1');
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(
AnotherService::class,
$sample->constructorVarTwo
);
2014-08-15 08:53:05 +02:00
$injector = new Injector();
2016-10-14 03:30:05 +02:00
$config = array(
'SampleService' => array(
'src' => TEST_SERVICES . '/SampleService.php',
2016-10-14 03:30:05 +02:00
'class' => SampleService::class,
'constructor' => array(
'val1',
'val2',
)
2016-10-14 03:30:05 +02:00
)
);
$injector->load($config);
$sample = $injector->get('SampleService');
$this->assertEquals($sample->constructorVarOne, 'val1');
$this->assertEquals($sample->constructorVarTwo, 'val2');
2014-08-15 08:53:05 +02:00
// test constructors on prototype
$injector = new Injector();
2016-10-14 03:30:05 +02:00
$config = array(
'SampleService' => array(
'type' => 'prototype',
'src' => TEST_SERVICES . '/SampleService.php',
'class' => SampleService::class,
'constructor' => array(
'val1',
'val2',
)
)
2016-10-14 03:30:05 +02:00
);
$injector->load($config);
$sample = $injector->get('SampleService');
$this->assertEquals($sample->constructorVarOne, 'val1');
$this->assertEquals($sample->constructorVarTwo, 'val2');
2014-08-15 08:53:05 +02:00
$again = $injector->get('SampleService');
$this->assertFalse($sample === $again);
2014-08-15 08:53:05 +02:00
$this->assertEquals($sample->constructorVarOne, 'val1');
$this->assertEquals($sample->constructorVarTwo, 'val2');
}
public function testInjectUsingSetter() {
$injector = new Injector();
$injector->setAutoScanProperties(true);
2016-10-14 03:30:05 +02:00
$config = array(
'SampleService' => array(
'src' => TEST_SERVICES . '/SampleService.php',
'class' => SampleService::class,
)
);
$injector->load($config);
2016-10-14 03:30:05 +02:00
$this->assertEquals('SampleService', $injector->hasService('SampleService'));
2016-10-14 03:30:05 +02:00
$myObject = new InjectorTest\OtherTestObject();
$injector->inject($myObject);
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(
SampleService::class,
$myObject->s()
);
// and again because it goes down a different code path when setting things
// based on the inject map
2016-10-14 03:30:05 +02:00
$myObject = new InjectorTest\OtherTestObject();
$injector->inject($myObject);
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(
SampleService::class,
$myObject->s()
);
}
// make sure we can just get any arbitrary object - it should be created for us
public function testInstantiateAnObjectViaGet() {
$injector = new Injector();
$injector->setAutoScanProperties(true);
2016-10-14 03:30:05 +02:00
$config = array(
'SampleService' => array(
'src' => TEST_SERVICES . '/SampleService.php',
'class' => SampleService::class,
)
);
$injector->load($config);
2016-10-14 03:30:05 +02:00
$this->assertEquals('SampleService', $injector->hasService('SampleService'));
2016-10-14 03:30:05 +02:00
$myObject = $injector->get(OtherTestObject::class);
$this->assertInstanceOf(
SampleService::class,
$myObject->s()
);
// and again because it goes down a different code path when setting things
// based on the inject map
2016-10-14 03:30:05 +02:00
$myObject = $injector->get(OtherTestObject::class);
$this->assertInstanceOf(SampleService::class, $myObject->s());
}
public function testCircularReference() {
2016-10-14 03:30:05 +02:00
$services = array(
'CircularOne' => CircularOne::class,
'CircularTwo' => CircularTwo::class
);
$injector = new Injector($services);
$injector->setAutoScanProperties(true);
2016-10-14 03:30:05 +02:00
$obj = $injector->get(NeedsBothCirculars::class);
2016-10-14 03:30:05 +02:00
$this->assertTrue($obj->circularOne instanceof InjectorTest\CircularOne);
$this->assertTrue($obj->circularTwo instanceof InjectorTest\CircularTwo);
}
public function testPrototypeObjects() {
2016-10-14 03:30:05 +02:00
$services = array(
'CircularOne' => CircularOne::class,
'CircularTwo' => CircularTwo::class,
'NeedsBothCirculars' => array(
'class' => NeedsBothCirculars::class,
'type' => 'prototype'
)
);
$injector = new Injector($services);
$injector->setAutoScanProperties(true);
$obj1 = $injector->get('NeedsBothCirculars');
$obj2 = $injector->get('NeedsBothCirculars');
// if this was the same object, then $obj1->var would now be two
$obj1->var = 'one';
$obj2->var = 'two';
2016-10-14 03:30:05 +02:00
$this->assertTrue($obj1->circularOne instanceof InjectorTest\CircularOne);
$this->assertTrue($obj1->circularTwo instanceof InjectorTest\CircularTwo);
$this->assertEquals($obj1->circularOne, $obj2->circularOne);
$this->assertNotEquals($obj1, $obj2);
}
public function testSimpleInstantiation() {
2016-10-14 03:30:05 +02:00
$services = array(
'CircularOne' => CircularOne::class,
'CircularTwo' => CircularTwo::class
);
$injector = new Injector($services);
// similar to the above, but explicitly instantiating this object here
2016-10-14 03:30:05 +02:00
$obj1 = $injector->create(NeedsBothCirculars::class);
$obj2 = $injector->create(NeedsBothCirculars::class);
// if this was the same object, then $obj1->var would now be two
$obj1->var = 'one';
$obj2->var = 'two';
$this->assertEquals($obj1->circularOne, $obj2->circularOne);
$this->assertNotEquals($obj1, $obj2);
}
2014-08-15 08:53:05 +02:00
public function testCreateWithConstructor() {
$injector = new Injector();
2016-10-14 03:30:05 +02:00
$obj = $injector->create(CircularTwo::class, 'param');
$this->assertEquals($obj->otherVar, 'param');
}
2014-08-15 08:53:05 +02:00
public function testSimpleSingleton() {
$injector = new Injector();
2014-08-15 08:53:05 +02:00
2016-10-14 03:30:05 +02:00
$one = $injector->create(CircularOne::class);
$two = $injector->create(CircularOne::class);
$this->assertFalse($one === $two);
2014-08-15 08:53:05 +02:00
2016-10-14 03:30:05 +02:00
$one = $injector->get(CircularTwo::class);
$two = $injector->get(CircularTwo::class);
2014-08-15 08:53:05 +02:00
$this->assertTrue($one === $two);
}
public function testOverridePriority() {
$injector = new Injector();
$injector->setAutoScanProperties(true);
$config = array(
2016-10-14 03:30:05 +02:00
'SampleService' => array(
'src' => TEST_SERVICES . '/SampleService.php',
2016-10-14 03:30:05 +02:00
'class' => SampleService::class,
'priority' => 10,
)
);
// load
$injector->load($config);
// inject
2016-10-14 03:30:05 +02:00
$myObject = new InjectorTest\TestObject();
$injector->inject($myObject);
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(SampleService::class, $myObject->sampleService);
$config = array(
array(
'src' => TEST_SERVICES . '/AnotherService.php',
2016-10-14 03:30:05 +02:00
'class' => AnotherService::class,
'id' => 'SampleService',
'priority' => 1,
)
);
// load
$injector->load($config);
$injector->inject($myObject);
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(
SampleService::class,
$myObject->sampleService
);
}
/**
* Specific test method to illustrate various ways of setting a requirements backend
*/
public function testRequirementsSettingOptions() {
$injector = new Injector();
$config = array(
2016-10-14 03:30:05 +02:00
OriginalRequirementsBackend::class,
NewRequirementsBackend::class,
DummyRequirements::class => array(
'constructor' => array(
2016-10-14 03:30:05 +02:00
'%$'.OriginalRequirementsBackend::class
)
)
);
$injector->load($config);
2016-10-14 03:30:05 +02:00
$requirements = $injector->get(DummyRequirements::class);
$this->assertInstanceOf(
OriginalRequirementsBackend::class,
$requirements->backend
);
// just overriding the definition here
$injector->load(array(
2016-10-14 03:30:05 +02:00
DummyRequirements::class => array(
'constructor' => array(
2016-10-14 03:30:05 +02:00
'%$'.NewRequirementsBackend::class
)
)
));
// requirements should have been reinstantiated with the new bean setting
2016-10-14 03:30:05 +02:00
$requirements = $injector->get(DummyRequirements::class);
$this->assertInstanceOf(
NewRequirementsBackend::class,
$requirements->backend
);
}
/**
* disabled for now
*/
public function testStaticInjections() {
$injector = new Injector();
$config = array(
2016-10-14 03:30:05 +02:00
NewRequirementsBackend::class,
);
$injector->load($config);
2016-10-14 03:30:05 +02:00
$si = $injector->get(TestStaticInjections::class);
$this->assertInstanceOf(
NewRequirementsBackend::class,
$si->backend
);
}
2014-08-15 08:53:05 +02:00
public function testSetterInjections() {
$injector = new Injector();
$config = array(
2016-10-14 03:30:05 +02:00
NewRequirementsBackend::class,
);
$injector->load($config);
2016-10-14 03:30:05 +02:00
$si = $injector->get(TestSetterInjections::class);
$this->assertInstanceOf(
NewRequirementsBackend::class,
$si->getBackend()
);
}
public function testCustomObjectCreator() {
$injector = new Injector();
2016-10-14 03:30:05 +02:00
$injector->setObjectCreator(new InjectorTest\SSObjectCreator($injector));
$config = array(
2016-10-14 03:30:05 +02:00
OriginalRequirementsBackend::class,
DummyRequirements::class => array(
'class' => DummyRequirements::class.'(\'%$'.OriginalRequirementsBackend::class.'\')'
)
);
$injector->load($config);
2016-10-14 03:30:05 +02:00
$requirements = $injector->get(DummyRequirements::class);
$this->assertEquals(OriginalRequirementsBackend::class, get_class($requirements->backend));
}
public function testInheritedConfig() {
// Test that child class does not automatically inherit config
2016-10-14 03:30:05 +02:00
$injector = new Injector(array('locator' => SilverStripeServiceConfigurationLocator::class));
Config::inst()->update(Injector::class, MyParentClass::class, [
'properties' => ['one' => 'the one'],
2016-10-14 03:30:05 +02:00
'class' => MyParentClass::class,
]);
2016-10-14 03:30:05 +02:00
$obj = $injector->get(MyParentClass::class);
$this->assertInstanceOf(MyParentClass::class, $obj);
$this->assertEquals($obj->one, 'the one');
2014-08-15 08:53:05 +02:00
// Class isn't inherited and parent properties are ignored
2016-10-14 03:30:05 +02:00
$obj = $injector->get(MyChildClass::class);
$this->assertInstanceOf(MyChildClass::class, $obj);
$this->assertNotEquals($obj->one, 'the one');
// Set child class as alias
2016-10-14 03:30:05 +02:00
$injector = new Injector(array(
'locator' => SilverStripeServiceConfigurationLocator::class
));
Config::inst()->update(
Injector::class,
MyChildClass::class,
'%$'.MyParentClass::class
);
// Class isn't inherited and parent properties are ignored
2016-10-14 03:30:05 +02:00
$obj = $injector->get(MyChildClass::class);
$this->assertInstanceOf(MyParentClass::class, $obj);
$this->assertEquals($obj->one, 'the one');
}
2014-08-15 08:53:05 +02:00
public function testSameNamedSingeltonPrototype() {
$injector = new Injector();
2014-08-15 08:53:05 +02:00
// get a singleton object
2016-10-14 03:30:05 +02:00
$object = $injector->get(NeedsBothCirculars::class);
$object->var = 'One';
2014-08-15 08:53:05 +02:00
2016-10-14 03:30:05 +02:00
$again = $injector->get(NeedsBothCirculars::class);
$this->assertEquals($again->var, 'One');
2014-08-15 08:53:05 +02:00
// create a NEW instance object
2016-10-14 03:30:05 +02:00
$new = $injector->create(NeedsBothCirculars::class);
$this->assertNull($new->var);
2014-08-15 08:53:05 +02:00
// this will trigger a problem below
$new->var = 'Two';
2014-08-15 08:53:05 +02:00
2016-10-14 03:30:05 +02:00
$again = $injector->get(NeedsBothCirculars::class);
$this->assertEquals($again->var, 'One');
}
2014-08-15 08:53:05 +02:00
public function testConvertServicePropertyOnCreate() {
2014-08-15 08:53:05 +02:00
// make sure convert service property is not called on direct calls to create, only on configured
// declarations to avoid un-needed function calls
$injector = new Injector();
2016-10-14 03:30:05 +02:00
$item = $injector->create(ConstructableObject::class, '%$'.TestObject::class);
$this->assertEquals('%$'.TestObject::class, $item->property);
2014-08-15 08:53:05 +02:00
// do it again but have test object configured as a constructor dependency
$injector = new Injector();
$config = array(
2016-10-14 03:30:05 +02:00
ConstructableObject::class => array(
'constructor' => array(
2016-10-14 03:30:05 +02:00
'%$'.TestObject::class
)
)
);
$injector->load($config);
2016-10-14 03:30:05 +02:00
$item = $injector->get(ConstructableObject::class);
$this->assertTrue($item->property instanceof InjectorTest\TestObject);
2014-08-15 08:53:05 +02:00
// and with a configured object defining TestObject to be something else!
2016-10-14 03:30:05 +02:00
$injector = new Injector(array('locator' => InjectorTest\InjectorTestConfigLocator::class));
$config = array(
2016-10-14 03:30:05 +02:00
ConstructableObject::class => array(
'constructor' => array(
2016-10-14 03:30:05 +02:00
'%$'.TestObject::class
)
),
);
$injector->load($config);
2016-10-14 03:30:05 +02:00
$item = $injector->get(ConstructableObject::class);
$this->assertTrue($item->property instanceof InjectorTest\ConstructableObject);
2014-08-15 08:53:05 +02:00
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(OtherTestObject::class, $item->property->property);
}
public function testNamedServices() {
$injector = new Injector();
$service = new stdClass();
$injector->registerService($service, 'NamedService');
$this->assertEquals($service, $injector->get('NamedService'));
}
2014-08-15 08:53:05 +02:00
public function testCreateConfiggedObjectWithCustomConstructorArgs() {
2014-08-15 08:53:05 +02:00
// need to make sure that even if the config defines some constructor params,
// that we take our passed in constructor args instead
2016-10-14 03:30:05 +02:00
$injector = new Injector(array('locator' => InjectorTest\InjectorTestConfigLocator::class));
2014-08-15 08:53:05 +02:00
$item = $injector->create('ConfigConstructor', 'othervalue');
$this->assertEquals($item->property, 'othervalue');
}
/**
* Tests creating a service with a custom factory.
*/
public function testCustomFactory() {
$injector = new Injector(array(
'service' => array('factory' => 'factory', 'constructor' => array(1, 2, 3))
));
$factory = $this->getMock('SilverStripe\\Core\\Injector\\Factory');
$factory
->expects($this->once())
->method('create')
->with($this->equalTo('service'), $this->equalTo(array(1, 2, 3)))
->will($this->returnCallback(function($args) {
2016-10-14 03:30:05 +02:00
return new InjectorTest\TestObject();
}));
$injector->registerService($factory, 'factory');
2016-10-14 03:30:05 +02:00
$this->assertInstanceOf(TestObject::class, $injector->get('service'));
}
2014-08-15 08:53:05 +02:00
public function testMethods() {
// do it again but have test object configured as a constructor dependency
$injector = new Injector();
$config = array(
'A' => array(
2016-10-14 03:30:05 +02:00
'class' => TestObject::class,
),
'B' => array(
2016-10-14 03:30:05 +02:00
'class' => TestObject::class,
),
'TestService' => array(
2016-10-14 03:30:05 +02:00
'class' => TestObject::class,
'calls' => array(
array('myMethod', array('%$A')),
array('myMethod', array('%$B')),
array('noArgMethod')
)
)
);
$injector->load($config);
$item = $injector->get('TestService');
2016-10-14 03:30:05 +02:00
$this->assertTrue($item instanceof InjectorTest\TestObject);
$this->assertEquals(
array($injector->get('A'), $injector->get('B'), 'noArgMethod called'),
$item->methodCalls
);
}
/**
* @expectedException InvalidArgumentException
*/
public function testNonExistentMethods() {
$injector = new Injector();
$config = array(
'TestService' => array(
2016-10-14 03:30:05 +02:00
'class' => TestObject::class,
'calls' => array(
array('thisDoesntExist')
)
)
);
$injector->load($config);
$item = $injector->get('TestService');
}
/**
* @expectedException InvalidArgumentException
*/
public function testProtectedMethods() {
$injector = new Injector();
$config = array(
'TestService' => array(
2016-10-14 03:30:05 +02:00
'class' => TestObject::class,
'calls' => array(
array('protectedMethod')
)
)
);
$injector->load($config);
$item = $injector->get('TestService');
}
/**
* @expectedException InvalidArgumentException
*/
public function testTooManyArrayValues() {
$injector = new Injector();
$config = array(
'TestService' => array(
2016-10-14 03:30:05 +02:00
'class' => TestObject::class,
'calls' => array(
array('method', array('args'), 'what is this?')
)
)
);
$injector->load($config);
$item = $injector->get('TestService');
}
/**
* Test nesting of injector
*/
public function testNest() {
2014-08-15 08:53:05 +02:00
// Outer nest to avoid interference with other
Injector::nest();
$this->nestingLevel++;
2014-08-15 08:53:05 +02:00
// Test services
$config = array(
2016-10-14 03:30:05 +02:00
NewRequirementsBackend::class,
);
Injector::inst()->load($config);
2016-10-14 03:30:05 +02:00
$si = Injector::inst()->get(TestStaticInjections::class);
$this->assertInstanceOf(TestStaticInjections::class, $si);
$this->assertInstanceOf(NewRequirementsBackend::class, $si->backend);
$this->assertInstanceOf(MyParentClass::class, Injector::inst()->get(MyParentClass::class));
$this->assertInstanceOf(MyChildClass::class, Injector::inst()->get(MyChildClass::class));
2014-08-15 08:53:05 +02:00
// Test that nested injector values can be overridden
Injector::nest();
$this->nestingLevel++;
Injector::inst()->unregisterAllObjects();
2016-10-14 03:30:05 +02:00
$newsi = Injector::inst()->get(TestStaticInjections::class);
$newsi->backend = new InjectorTest\OriginalRequirementsBackend();
Injector::inst()->registerService($newsi, TestStaticInjections::class);
Injector::inst()->registerService(new InjectorTest\MyChildClass(), MyParentClass::class);
2014-08-15 08:53:05 +02:00
// Check that these overridden values are retrievable
2016-10-14 03:30:05 +02:00
$si = Injector::inst()->get(TestStaticInjections::class);
$this->assertInstanceOf(TestStaticInjections::class, $si);
$this->assertInstanceOf(OriginalRequirementsBackend::class, $si->backend);
$this->assertInstanceOf(MyParentClass::class, Injector::inst()->get(MyParentClass::class));
$this->assertInstanceOf(MyParentClass::class, Injector::inst()->get(MyChildClass::class));
2014-08-15 08:53:05 +02:00
// Test that unnesting restores expected behaviour
Injector::unnest();
$this->nestingLevel--;
2016-10-14 03:30:05 +02:00
$si = Injector::inst()->get(TestStaticInjections::class);
$this->assertInstanceOf(TestStaticInjections::class, $si);
$this->assertInstanceOf(NewRequirementsBackend::class, $si->backend);
$this->assertInstanceOf(MyParentClass::class, Injector::inst()->get(MyParentClass::class));
$this->assertInstanceOf(MyChildClass::class, Injector::inst()->get(MyChildClass::class));
2014-08-15 08:53:05 +02:00
// Test reset of cache
Injector::inst()->unregisterAllObjects();
2016-10-14 03:30:05 +02:00
$si = Injector::inst()->get(TestStaticInjections::class);
$this->assertInstanceOf(TestStaticInjections::class, $si);
$this->assertInstanceOf(NewRequirementsBackend::class, $si->backend);
$this->assertInstanceOf(MyParentClass::class, Injector::inst()->get(MyParentClass::class));
$this->assertInstanceOf(MyChildClass::class, Injector::inst()->get(MyChildClass::class));
2014-08-15 08:53:05 +02:00
// Return to nestingLevel 0
Injector::unnest();
$this->nestingLevel--;
}
}