class Injector (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

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

public
__construct(array $config = null)

Create a new injector.

public static 
inst(array $config = null)

If a user wants to use the injector as a static reference

public static 
set_inst(Injector $instance)

Sets the default global injector instance.

public static 
nest()

Make the newly active Injector be a copy of the current active Injector instance.

public static 
unnest()

Change the active Injector back to the Injector instance the current active Injector object was copied from.

public
setAutoScanProperties(bool $val)

Indicate whether we auto scan injected objects for properties to set.

public
setObjectCreator(Factory $obj)

Sets the default factory to use for creating new objects.

public
getObjectCreator()

No description

public
setConfigLocator(ServiceConfigurationLocator $configLocator)

Set the configuration locator

public
getConfigLocator()

Retrieve the configuration locator

public
setInjectMapping(string $class, string $property, string $toInject, string $injectVia = 'property')

Add in a specific mapping that should be catered for on a type.

public
addAutoProperty(string $property, object $object)

Add an object that should be automatically set on managed objects

public
load(array $config = array())

Load services using the passed in configuration for those services

public
updateSpec(string $id, string $property, mixed $value, bool $append = true)

Update the configuration of an already defined service

protected
updateSpecConstructor(array $spec)

Update a class specification to convert constructor configuration information if needed

public
convertServiceProperty(string $value)

Recursively convert a value into its proper representation with service references resolved to actual objects

protected
instantiate(array $spec, string $id = null, string $type = null)

Instantiate a managed object

public
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

public
string
hasService($name)

Does the given service exist, and if so, what's the stored name for it?

public
registerService(stdClass $service, string $replace = null)

Register a service object with an optional name to register it as the service for

public
registerNamedService($name, $service) deprecated

Register a service with an explicit name

public
unregisterNamedObject(string $name)

Removes a named object from the cached list of objects managed by the inject

public
unregisterAllObjects()

Clear out all objects that are managed by the injetor.

public
mixed
get(string $name, bool $asSingleton = true, array $constructorArgs = null)

Get a named managed object

public
mixed
__get(string $name)

Magic method to return an item directly

public
mixed
create(string $name)

Similar to get() but always returns a new object of the given type

public
mixed
createWithArgs(string $name, $constructorArgs)

Creates an object with the supplied argument array

Details

__construct(array $config = null)

Create a new injector.

Parameters

array $config

Service configuration

static Injector inst(array $config = null)

If a user wants to use the injector as a static reference

Parameters

array $config

Return Value

Injector

static Injector set_inst(Injector $instance)

Sets the default global injector instance.

Parameters

Injector $instance

Return Value

Injector

Reference to new active Injector instance

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()

Return Value

Injector

Reference to new active Injector instance

static Injector unnest()

Change the active Injector back to the Injector instance the current active Injector object was copied from.

Return Value

Injector

Reference to restored active Injector instance

setAutoScanProperties(bool $val)

Indicate whether we auto scan injected objects for properties to set.

Parameters

bool $val

setObjectCreator(Factory $obj)

Sets the default factory to use for creating new objects.

Parameters

Factory $obj

Factory getObjectCreator()

No description

Return Value

Factory

setConfigLocator(ServiceConfigurationLocator $configLocator)

Set the configuration locator

Parameters

ServiceConfigurationLocator $configLocator

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.

Parameters

string $class

The class to set a mapping for

string $property

The property to set the mapping for

string $toInject

The registered type that will be injected

string $injectVia

Whether to inject by setting a property or calling a setter

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());

Parameters

string $property

the name of the property

object $object

the object to be set

load(array $config = array())

Load services using the passed in configuration for those services

Parameters

array $config

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')

Parameters

string $id

The name of the service to update the definition for

string $property

The name of the property to update.

mixed $value

The value to set

bool $append

Whether to append (the default) when the property is an array

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

Parameters

array $spec

The class specification to update

convertServiceProperty(string $value)

Recursively convert a value into its proper representation with service references resolved to actual objects

Parameters

string $value

protected 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.

Parameters

array $spec

The specification of the class to instantiate

string $id

The name of the object being created. If not supplied, then the id will be inferred from the object being created

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

inject(object $object, string $asType = null)

Inject $object with available objects from the service cache

Track all the existing objects that have had a service bound into them, so we can update that binding at a later point if needbe (ie if the managed service changes)

Parameters

object $object

The object to inject

string $asType

The ID this item was loaded as. This is so that the property configuration for a type is referenced correctly in case $object is no longer the same type as the loaded config specification had it as.

protected setObjectProperty(object $object, string $name, mixed $value)

Helper to set a property's value

Parameters

object $object

Set an object's property to a specific value

string $name

The name of the property to set

mixed $value

The value to set

string hasService($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 hasService for each depth of dotting

Parameters

$name

Return Value

string

The name of the service (as it might be different from the one passed in)

registerService(stdClass $service, string $replace = null)

Register a service object with an optional name to register it as the service for

Parameters

stdClass $service

The object to register

string $replace

The name of the object to replace (if different to the class name of the object to register)

registerNamedService($name, $service) deprecated

deprecated since 4.0

Register a service with an explicit name

Parameters

$name
$service

unregisterNamedObject(string $name)

Removes a named object from the cached list of objects managed by the inject

Parameters

string $name

The name to unregister

unregisterAllObjects()

Clear out all objects that are managed by the injetor.

mixed get(string $name, bool $asSingleton = true, array $constructorArgs = null)

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 specificied object.

Parameters

string $name

the name of the service to retrieve. If not a registered service, then a class of the given name is instantiated

bool $asSingleton

Whether to register the created object as a singleton if no other configuration is found

array $constructorArgs

Optional set of arguments to pass as constructor arguments if this object is to be created from scratch (ie asSingleton = false)

Return Value

mixed

the instance of the specified object

mixed __get(string $name)

Magic method to return an item directly

Parameters

string $name

The named object to retrieve

Return Value

mixed

mixed create(string $name)

Similar to get() but always returns a new object of the given type

Additional parameters are passed through as

Parameters

string $name

Return Value

mixed

A new instance of the specified object

mixed createWithArgs(string $name, $constructorArgs)

Creates an object with the supplied argument array

Parameters

string $name

Name of the class to create an object of

$constructorArgs

Return Value

mixed