Injector
class Injector implements ContainerInterface (View source)
A simple injection manager that manages creating objects and injecting dependencies between them. It borrows quite a lot from ideas taken from Spring's configuration, but is adapted to the stateless PHP way of doing things.
In its simplest form, the dependency injector can be used as a mechanism to instantiate objects. Simply call
Injector::inst()->get('ClassName')
and a new instance of ClassName will be created and returned to you.
Classes can have specific configuration defined for them to indicate dependencies that should be injected. This takes the form of a static variable $dependencies defined in the class (or configuration), which indicates the name of a property that should be set.
eg
class MyController extends Controller {
public $permissions;
public $defaultText;
static $dependencies = array(
'defaultText' => 'Override in configuration',
'permissions' => '%$PermissionService',
);
}
will result in an object of type MyController having the defaultText property set to 'Override in configuration', and an object identified as PermissionService set into the property called 'permissions'. The %$ syntax tells the injector to look the provided name up as an item to be created by the Injector itself.
A key concept of the injector is whether to manage the object as
- A pseudo-singleton, in that only one item will be created for a particular identifier (but the same class could be used for multiple identifiers)
- A prototype, where the same configuration is used, but a new object is created each time
- unmanaged, in which case a new object is created and injected, but no information about its state is managed.
Additional configuration of items managed by the injector can be done by providing configuration for the types, either by manually loading in an array describing the configuration, or by specifying the configuration for a type via SilverStripe's configuration mechanism.
Specify a configuration array of the format
array(
array(
'id' => 'BeanId', // the name to be used if diff from the filename
'priority' => 1, // priority. If another bean is defined with the same ID,
// but has a lower priority, it is NOT overridden
'class' => 'ClassName', // the name of the PHP class
'src' => '/path/to/file' // the location of the class
'type' => 'singleton|prototype' // if you want prototype object generation, set it as the
// 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',
)
'properties' => array(
'name' => 'value' // scalar value
'name' => '%$BeanId', // a reference to another bean
'name' => array(
'scalar',
'%$BeanId'
)
)
)
// alternatively
'MyBean' => array(
'class' => 'ClassName',
)
// or simply
'OtherBean' => 'SomeClass',
)
In addition to specifying the bindings directly in the configuration, you can simply create a publicly accessible property on the target class which will automatically be injected if the autoScanProperties option is set to true. This means a class defined as
class MyController extends Controller {
private $permissionService;
public setPermissionService($p) {
$this->permissionService = $p;
}
}
will have setPermissionService called if
- Injector::inst()->setAutoScanProperties(true) is called and
- A service named 'PermissionService' has been configured
Constants
SINGLETON |
Specify a service type singleton |
PROTOTYPE |
Specify a service type prototype |
Properties
protected | Factory | $objectCreator | The default factory used to create new instances. |
|
protected | ServiceConfigurationLocator | $configLocator | Locator for determining Config properties for services |
|
protected | Injector | $nestedFrom | The injector instance this one was copied from when Injector::nest() was called. |
Methods
Make the newly active Injector be a copy of the current active Injector instance.
Change the active Injector back to the Injector instance the current active Injector object was copied from.
Indicate whether we auto scan injected objects for properties to set.
Add in a specific mapping that should be catered for on a type.
Add an object that should be automatically set on managed objects
Load services using the passed in configuration for those services
Update the configuration of an already defined service
Update a class specification to convert constructor configuration information if needed
Recursively convert a value into its proper representation with service references resolved to actual objects
Instantiate a managed object
Inject $object with available objects from the service cache
Helper to set a property's value
Does the given service exist, and if so, what's the stored name for it?
Register a service object with an optional name to register it as the service for
Removes a named object from the cached list of objects managed by the inject
Clear out objects of one or more types that are managed by the injetor.
Get a named managed object
Returns the service, or null
if it doesnt' exist. See get() for main usage.
Detect service references with constructor arguments included.
Get or build a named service and specification
Search for spec, lazy-loading in from config locator.
Similar to get() but always returns a new object of the given type
Creates an object with the supplied argument array
Details
__construct(array $config = null)
Create a new injector.
static Injector
inst()
No description
static Injector
nest()
Make the newly active Injector be a copy of the current active Injector instance.
You can then make changes to the injector with methods such as Injector::inst()->registerService() which will be discarded upon a subsequent call to Injector::unnest()
static Injector
unnest()
Change the active Injector back to the Injector instance the current active Injector object was copied from.
setAutoScanProperties(bool $val)
Indicate whether we auto scan injected objects for properties to set.
setObjectCreator(Factory $obj)
Sets the default factory to use for creating new objects.
Factory
getObjectCreator()
No description
setConfigLocator(ServiceConfigurationLocator $configLocator)
Set the configuration locator
ServiceConfigurationLocator
getConfigLocator()
Retrieve the configuration locator
setInjectMapping(string $class, string $property, string $toInject, string $injectVia = 'property')
Add in a specific mapping that should be catered for on a type.
This allows configuration of what should occur when an object of a particular type is injected, and what items should be injected for those properties / methods.
$this
addAutoProperty(string $property, object $object)
Add an object that should be automatically set on managed objects
This allows you to specify, for example, that EVERY managed object will be automatically inject with a log object by the following
$injector->addAutoProperty('log', new Logger());
$this
load(array $config = [])
Load services using the passed in configuration for those services
updateSpec(string $id, string $property, mixed $value, bool $append = true)
Update the configuration of an already defined service
Use this if you don't want to register a complete new config, just append to an existing configuration. Helpful to avoid overwriting someone else's changes
updateSpec('RequestProcessor', 'filters', '%$MyFilter')
protected
updateSpecConstructor(array $spec)
Update a class specification to convert constructor configuration information if needed
We do this as a separate process to avoid unneeded calls to convertServiceProperty
array|mixed|string
convertServiceProperty(string $value)
Recursively convert a value into its proper representation with service references resolved to actual objects
protected object
instantiate(array $spec, string $id = null, string $type = null)
Instantiate a managed object
Given a specification of the form
array( 'class' => 'ClassName', 'properties' => array('property' => 'scalar', 'other' => '%$BeanRef') 'id' => 'ServiceId', 'type' => 'singleton|prototype' )
will create a new object, store it in the service registry, and set any relevant properties
Optionally, you can pass a class name directly for creation
To access this from the outside, you should call ->get('Name') to ensure the appropriate checks are made on the specific type.
inject(object $object, string $asType = null)
Inject $object with available objects from the service cache
protected
setObjectProperty(object $object, string $name, mixed $value)
Helper to set a property's value
string
hasService($name)
deprecated
deprecated
No description
bool
has(string $name)
Does the given service exist?
We do a special check here for services that are using compound names. For example, we might want to say that a property should be injected with Log.File or Log.Memory, but have only registered a 'Log' service, we'll instead return that.
Will recursively call itself for each depth of dotting.
string|null
getServiceName(string $name)
Does the given service exist, and if so, what's the stored name for it?
We do a special check here for services that are using compound names. For example, we might want to say that a property should be injected with Log.File or Log.Memory, but have only registered a 'Log' service, we'll instead return that.
Will recursively call itself for each depth of dotting.
$this
registerService(object $service, string $replace = null)
Register a service object with an optional name to register it as the service for
$this
unregisterNamedObject(string $name)
Removes a named object from the cached list of objects managed by the inject
$this
unregisterObjects(array|string $types)
Clear out objects of one or more types that are managed by the injetor.
mixed
get(string $name, bool $asSingleton = true, array $constructorArgs = [])
Get a named managed object
Will first check to see if the item has been registered as a configured service/bean and return that if so.
Next, will check to see if there's any registered configuration for the given type and will then try and load that
Failing all of that, will just return a new instance of the specified object.
protected mixed
getNamedService(string $name, bool $asSingleton = true, array $constructorArgs = [])
Returns the service, or null
if it doesnt' exist. See get() for main usage.
protected array
normaliseArguments(string $name, array $args = [])
Detect service references with constructor arguments included.
These will be split out of the service name reference and appended to the $args
protected array
getServiceNamedSpec(string $name, array $constructorArgs = [])
Get or build a named service and specification
mixed|object
getServiceSpec(string $name, bool $inherit = true)
Search for spec, lazy-loading in from config locator.
Falls back to parent service name if unloaded
mixed
__get(string $name)
Magic method to return an item directly
mixed
create(string $name, mixed $argument = null)
Similar to get() but always returns a new object of the given type
Additional parameters are passed through as
mixed
createWithArgs(string $name, array $constructorArgs)
Creates an object with the supplied argument array