mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #4450 from sminnee/injector-method-calls
NEW: Add ‘calls’ section to Injector configs.
This commit is contained in:
commit
60f7c660d0
@ -585,15 +585,52 @@ class Injector {
|
|||||||
$objtype = $asType ? $asType : get_class($object);
|
$objtype = $asType ? $asType : get_class($object);
|
||||||
$mapping = isset($this->injectMap[$objtype]) ? $this->injectMap[$objtype] : null;
|
$mapping = isset($this->injectMap[$objtype]) ? $this->injectMap[$objtype] : null;
|
||||||
|
|
||||||
|
$spec = empty($this->specs[$objtype]) ? array() : $this->specs[$objtype];
|
||||||
|
|
||||||
// first off, set any properties defined in the service specification for this
|
// first off, set any properties defined in the service specification for this
|
||||||
// object type
|
// object type
|
||||||
if (isset($this->specs[$objtype]) && isset($this->specs[$objtype]['properties'])) {
|
if(!empty($spec['properties']) && is_array($spec['properties'])) {
|
||||||
foreach ($this->specs[$objtype]['properties'] as $key => $value) {
|
foreach ($this->specs[$objtype]['properties'] as $key => $value) {
|
||||||
$val = $this->convertServiceProperty($value);
|
$val = $this->convertServiceProperty($value);
|
||||||
$this->setObjectProperty($object, $key, $val);
|
$this->setObjectProperty($object, $key, $val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Populate named methods
|
||||||
|
if (!empty($spec['calls']) && is_array($spec['calls'])) {
|
||||||
|
foreach ($spec['calls'] as $method) {
|
||||||
|
// Ignore any blank entries from the array; these may be left in due to config system limitations
|
||||||
|
if(!$method) continue;
|
||||||
|
|
||||||
|
// Format validation
|
||||||
|
if(!is_array($method) || !isset($method[0]) || isset($method[2])) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
"'calls' entries in service definition should be 1 or 2 element arrays."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if(!is_string($method[0])) {
|
||||||
|
throw new \InvalidArgumentException("1st element of a 'calls' entry should be a string");
|
||||||
|
}
|
||||||
|
if(isset($method[1]) && !is_array($method[1])) {
|
||||||
|
throw new \InvalidArgumentException("2nd element of a 'calls' entry should an arguments array");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the method exists and is callable
|
||||||
|
$objectMethod = array($object, $method[0]);
|
||||||
|
if (!is_callable($objectMethod)) {
|
||||||
|
throw new \InvalidArgumentException("'$method[0]' in 'calls' entry is not a public method");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call it
|
||||||
|
call_user_func_array(
|
||||||
|
$objectMethod,
|
||||||
|
$this->convertServiceProperty(
|
||||||
|
isset($method[1]) ? $method[1] : array()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// now, use any cached information about what properties this object type has
|
// now, use any cached information about what properties this object type has
|
||||||
// and set based on name resolution
|
// and set based on name resolution
|
||||||
if (!$mapping) {
|
if (!$mapping) {
|
||||||
|
@ -111,6 +111,16 @@ Now the dependencies will be replaced with our configuration.
|
|||||||
echo ($object->textProperty == 'My Text Value');
|
echo ($object->textProperty == 'My Text Value');
|
||||||
// returns true;
|
// returns true;
|
||||||
|
|
||||||
|
As well as properties, method calls can also be specified:
|
||||||
|
|
||||||
|
:::yml
|
||||||
|
Injector:
|
||||||
|
Logger:
|
||||||
|
class: Monolog\Logger
|
||||||
|
calls:
|
||||||
|
- [ pushHandler, [ %$DefaultHandler ] ]
|
||||||
|
|
||||||
|
|
||||||
## Factories
|
## Factories
|
||||||
|
|
||||||
Some services require non-trivial construction which means they must be created by a factory class. To do this, create
|
Some services require non-trivial construction which means they must be created by a factory class. To do this, create
|
||||||
|
@ -619,6 +619,91 @@ class InjectorTest extends SapphireTest {
|
|||||||
$this->assertInstanceOf('TestObject', $injector->get('service'));
|
$this->assertInstanceOf('TestObject', $injector->get('service'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testMethods() {
|
||||||
|
// do it again but have test object configured as a constructor dependency
|
||||||
|
$injector = new Injector();
|
||||||
|
$config = array(
|
||||||
|
'A' => array(
|
||||||
|
'class' => 'TestObject',
|
||||||
|
),
|
||||||
|
'B' => array(
|
||||||
|
'class' => 'TestObject',
|
||||||
|
),
|
||||||
|
'TestService' => array(
|
||||||
|
'class' => 'TestObject',
|
||||||
|
'calls' => array(
|
||||||
|
array('myMethod', array('%$A')),
|
||||||
|
array('myMethod', array('%$B')),
|
||||||
|
array('noArgMethod')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$injector->load($config);
|
||||||
|
$item = $injector->get('TestService');
|
||||||
|
$this->assertTrue($item instanceof 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(
|
||||||
|
'class' => 'TestObject',
|
||||||
|
'calls' => array(
|
||||||
|
array('thisDoesntExist')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$injector->load($config);
|
||||||
|
$item = $injector->get('TestService');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testProtectedMethods() {
|
||||||
|
$injector = new Injector();
|
||||||
|
$config = array(
|
||||||
|
'TestService' => array(
|
||||||
|
'class' => 'TestObject',
|
||||||
|
'calls' => array(
|
||||||
|
array('protectedMethod')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$injector->load($config);
|
||||||
|
$item = $injector->get('TestService');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testTooManyArrayValues() {
|
||||||
|
$injector = new Injector();
|
||||||
|
$config = array(
|
||||||
|
'TestService' => array(
|
||||||
|
'class' => 'TestObject',
|
||||||
|
'calls' => array(
|
||||||
|
array('method', array('args'), 'what is this?')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$injector->load($config);
|
||||||
|
$item = $injector->get('TestService');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test nesting of injector
|
* Test nesting of injector
|
||||||
*/
|
*/
|
||||||
@ -713,10 +798,23 @@ class TestObject implements TestOnly {
|
|||||||
|
|
||||||
public $sampleService;
|
public $sampleService;
|
||||||
|
|
||||||
|
public $methodCalls = array();
|
||||||
|
|
||||||
public function setSomething($v) {
|
public function setSomething($v) {
|
||||||
$this->sampleService = $v;
|
$this->sampleService = $v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function myMethod($arg) {
|
||||||
|
$this->methodCalls[] = $arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function noArgMethod() {
|
||||||
|
$this->methodCalls[] = 'noArgMethod called';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function protectedMethod() {
|
||||||
|
$this->methodCalls[] = 'protectedMethod called';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class OtherTestObject implements TestOnly {
|
class OtherTestObject implements TestOnly {
|
||||||
|
Loading…
Reference in New Issue
Block a user