mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
NEW: Allow specifying a factory to use for creating services.
A service factory can be used for creating instances where a non-trivial construction process is required. This is done by adding a `factory` key to the service definition.
This commit is contained in:
parent
b7b041b435
commit
2f817ba177
@ -1,20 +1,16 @@
|
||||
<?php
|
||||
|
||||
use SilverStripe\Framework\Injector\Factory;
|
||||
|
||||
/**
|
||||
* A class for creating new objects by the injector.
|
||||
*
|
||||
* @package framework
|
||||
* @subpackage injector
|
||||
*/
|
||||
class InjectionCreator {
|
||||
class InjectionCreator implements Factory {
|
||||
|
||||
/**
|
||||
* @param string $object
|
||||
* A string representation of the class to create
|
||||
* @param array $params
|
||||
* An array of parameters to be passed to the constructor
|
||||
*/
|
||||
public function create($class, $params = array()) {
|
||||
public function create($class, array $params = array()) {
|
||||
$reflector = new ReflectionClass($class);
|
||||
|
||||
if (count($params)) {
|
||||
@ -23,4 +19,5 @@ class InjectionCreator {
|
||||
|
||||
return $reflector->newInstance();
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +1,13 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__FILE__) . '/InjectionCreator.php';
|
||||
require_once dirname(__FILE__) . '/SilverStripeInjectionCreator.php';
|
||||
require_once dirname(__FILE__) . '/ServiceConfigurationLocator.php';
|
||||
require_once dirname(__FILE__) . '/SilverStripeServiceConfigurationLocator.php';
|
||||
require_once FRAMEWORK_PATH . '/src/SilverStripe/Framework/Injector/Factory.php';
|
||||
|
||||
require_once __DIR__ . '/InjectionCreator.php';
|
||||
require_once __DIR__ . '/SilverStripeInjectionCreator.php';
|
||||
require_once __DIR__ . '/ServiceConfigurationLocator.php';
|
||||
require_once __DIR__ . '/SilverStripeServiceConfigurationLocator.php';
|
||||
|
||||
use SilverStripe\Framework\Injector\Factory;
|
||||
|
||||
/**
|
||||
* A simple injection manager that manages creating objects and injecting
|
||||
@ -71,6 +75,7 @@ require_once dirname(__FILE__) . '/SilverStripeServiceConfigurationLocator.php';
|
||||
* // type
|
||||
* // By default, singleton is assumed
|
||||
*
|
||||
* 'factory' => 'FactoryService' // A factory service to use to create instances.
|
||||
* 'construct' => array( // properties to set at construction
|
||||
* 'scalar',
|
||||
* '%$BeanId',
|
||||
@ -163,14 +168,16 @@ class Injector {
|
||||
private $autoScanProperties = false;
|
||||
|
||||
/**
|
||||
* The object used to create new class instances
|
||||
* The default factory used to create new instances.
|
||||
*
|
||||
* Use a custom class here to change the way classes are created to use
|
||||
* a custom creation method. By default the InjectionCreator class is used,
|
||||
* which simply creates a new class via 'new', however this could be overridden
|
||||
* to use, for example, SilverStripe's Object::create() method.
|
||||
* The {@link InjectionCreator} is used by default, which simply directly
|
||||
* creates objects. This can be changed to use a different default creation
|
||||
* method if desired.
|
||||
*
|
||||
* @var InjectionCreator
|
||||
* Each individual component can also specify a custom factory to use by
|
||||
* using the `factory` parameter.
|
||||
*
|
||||
* @var Factory
|
||||
*/
|
||||
protected $objectCreator;
|
||||
|
||||
@ -216,6 +223,15 @@ class Injector {
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default global injector instance.
|
||||
*
|
||||
* @param Injector $instance
|
||||
*/
|
||||
public static function set_inst(Injector $instance) {
|
||||
self::$instance = $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether we auto scan injected objects for properties to set.
|
||||
*
|
||||
@ -226,17 +242,16 @@ class Injector {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the object to use for creating new objects
|
||||
* Sets the default factory to use for creating new objects.
|
||||
*
|
||||
* @param InjectionCreator $obj
|
||||
* @param Factory $obj
|
||||
*/
|
||||
public function setObjectCreator($obj) {
|
||||
public function setObjectCreator(Factory $obj) {
|
||||
$this->objectCreator = $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor (for testing purposes)
|
||||
* @return InjectionCreator
|
||||
* @return Factory
|
||||
*/
|
||||
public function getObjectCreator() {
|
||||
return $this->objectCreator;
|
||||
@ -486,7 +501,8 @@ class Injector {
|
||||
$constructorParams = $spec['constructor'];
|
||||
}
|
||||
|
||||
$object = $this->objectCreator->create($class, $constructorParams);
|
||||
$factory = isset($spec['factory']) ? $this->get($spec['factory']) : $this->getObjectCreator();
|
||||
$object = $factory->create($class, $constructorParams);
|
||||
|
||||
// figure out if we have a specific id set or not. In some cases, we might be instantiating objects
|
||||
// that we don't manage directly; we don't want to store these in the service cache below
|
||||
|
@ -1,22 +1,18 @@
|
||||
<?php
|
||||
|
||||
use SilverStripe\Framework\Injector\Factory;
|
||||
|
||||
/**
|
||||
* @package framework
|
||||
* @subpackage injector
|
||||
*/
|
||||
class SilverStripeInjectionCreator implements Factory {
|
||||
|
||||
class SilverStripeInjectionCreator {
|
||||
/**
|
||||
*
|
||||
* @param string $object
|
||||
* A string representation of the class to create
|
||||
* @param array $params
|
||||
* An array of parameters to be passed to the constructor
|
||||
*/
|
||||
public function create($class, $params = array()) {
|
||||
public function create($class, array $params = array()) {
|
||||
$class = Object::getCustomClass($class);
|
||||
$reflector = new ReflectionClass($class);
|
||||
|
||||
return $reflector->newInstanceArgs($params);
|
||||
return $params ? $reflector->newInstanceArgs($params) : $reflector->newInstance();
|
||||
}
|
||||
|
||||
}
|
@ -78,7 +78,6 @@ In this case, on creation of the MyController object, the injector will
|
||||
automatically instantiate the PermissionService object and set it as
|
||||
the **permissions** property.
|
||||
|
||||
|
||||
## Configuring objects managed by the dependency injector
|
||||
|
||||
The above declarative style of dependency management would cover a large
|
||||
@ -90,6 +89,31 @@ Configuration can be specified for two areas of dependency management
|
||||
* Defining dependency overrides for individual classes
|
||||
* Injector managed 'services'
|
||||
|
||||
### Factories
|
||||
|
||||
Some services require non-trivial construction which means they must be created by a factory class. To do this, create
|
||||
a factory class which implements the `[api:SilverStripe\Framework\Injector\Factory]` interface. You can then specify
|
||||
the `factory` key in the service definition, and the factory service will be used.
|
||||
|
||||
An example using the `MyFactory` service to create instances of the `MyService` service is shown below:
|
||||
|
||||
:::yml
|
||||
Injector:
|
||||
MyService:
|
||||
factory: MyFactory
|
||||
MyFactory:
|
||||
class: MyFactoryImplementation
|
||||
|
||||
:::php
|
||||
class MyFactoryImplementation implements SilverStripe\Framework\Injector\Factory {
|
||||
public function create($service, array $params = array()) {
|
||||
return new MyServiceImplementation();
|
||||
}
|
||||
}
|
||||
|
||||
// Will use MyFactoryImplementation::create() to create the service instance.
|
||||
$instance = Injector::inst()->get('MyService');
|
||||
|
||||
### Dependency overrides
|
||||
|
||||
To override the **static $dependency;** declaration for a class, you could
|
||||
|
19
src/SilverStripe/Framework/Injector/Factory.php
Normal file
19
src/SilverStripe/Framework/Injector/Factory.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Framework\Injector;
|
||||
|
||||
/**
|
||||
* A factory which is used for creating service instances.
|
||||
*/
|
||||
interface Factory {
|
||||
|
||||
/**
|
||||
* Creates a new service instance.
|
||||
*
|
||||
* @param string $service The class name of the service.
|
||||
* @param array $params The constructor parameters.
|
||||
* @return object The created service instances.
|
||||
*/
|
||||
public function create($service, array $params = array());
|
||||
|
||||
}
|
@ -541,6 +541,28 @@ class InjectorTest extends SapphireTest {
|
||||
$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\\Framework\\Injector\\Factory');
|
||||
$factory
|
||||
->expects($this->once())
|
||||
->method('create')
|
||||
->with($this->equalTo('service'), $this->equalTo(array(1, 2, 3)))
|
||||
->will($this->returnCallback(function($args) {
|
||||
return new TestObject();
|
||||
}));
|
||||
|
||||
$injector->registerService($factory, 'factory');
|
||||
|
||||
$this->assertInstanceOf('TestObject', $injector->get('service'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class InjectorTestConfigLocator extends SilverStripeServiceConfigurationLocator implements TestOnly {
|
||||
@ -667,7 +689,7 @@ class SSObjectCreator extends InjectionCreator {
|
||||
$this->injector = $injector;
|
||||
}
|
||||
|
||||
public function create($class, $params = array()) {
|
||||
public function create($class, array $params = array()) {
|
||||
if (strpos($class, '(') === false) {
|
||||
return parent::create($class, $params);
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user