mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #3982 from dhensby/pulls/safe-unnesting
Safe unnesting of Config and Injector
This commit is contained in:
commit
8e1da86bf1
@ -13,61 +13,61 @@ use SilverStripe\Framework\Injector\Factory;
|
|||||||
* A simple injection manager that manages creating objects and injecting
|
* A simple injection manager that manages creating objects and injecting
|
||||||
* dependencies between them. It borrows quite a lot from ideas taken from
|
* 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
|
* Spring's configuration, but is adapted to the stateless PHP way of doing
|
||||||
* things.
|
* things.
|
||||||
*
|
*
|
||||||
* In its simplest form, the dependency injector can be used as a mechanism to
|
* In its simplest form, the dependency injector can be used as a mechanism to
|
||||||
* instantiate objects. Simply call
|
* instantiate objects. Simply call
|
||||||
*
|
*
|
||||||
* Injector::inst()->get('ClassName')
|
* Injector::inst()->get('ClassName')
|
||||||
*
|
*
|
||||||
* and a new instance of ClassName will be created and returned to you.
|
* and a new instance of ClassName will be created and returned to you.
|
||||||
*
|
*
|
||||||
* Classes can have specific configuration defined for them to
|
* Classes can have specific configuration defined for them to
|
||||||
* indicate dependencies that should be injected. This takes the form of
|
* indicate dependencies that should be injected. This takes the form of
|
||||||
* a static variable $dependencies defined in the class (or configuration),
|
* a static variable $dependencies defined in the class (or configuration),
|
||||||
* which indicates the name of a property that should be set.
|
* which indicates the name of a property that should be set.
|
||||||
*
|
*
|
||||||
* eg
|
* eg
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* class MyController extends Controller {
|
* class MyController extends Controller {
|
||||||
*
|
*
|
||||||
* public $permissions;
|
* public $permissions;
|
||||||
* public $defaultText;
|
* public $defaultText;
|
||||||
*
|
*
|
||||||
* static $dependencies = array(
|
* static $dependencies = array(
|
||||||
* 'defaultText' => 'Override in configuration',
|
* 'defaultText' => 'Override in configuration',
|
||||||
* 'permissions' => '%$PermissionService',
|
* 'permissions' => '%$PermissionService',
|
||||||
* );
|
* );
|
||||||
* }
|
* }
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* will result in an object of type MyController having the defaultText property
|
* will result in an object of type MyController having the defaultText property
|
||||||
* set to 'Override in configuration', and an object identified
|
* set to 'Override in configuration', and an object identified
|
||||||
* as PermissionService set into the property called 'permissions'. The %$
|
* 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
|
* syntax tells the injector to look the provided name up as an item to be created
|
||||||
* by the Injector itself.
|
* by the Injector itself.
|
||||||
*
|
*
|
||||||
* A key concept of the injector is whether to manage the object as
|
* 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
|
* * 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)
|
* identifier (but the same class could be used for multiple identifiers)
|
||||||
* * A prototype, where the same configuration is used, but a new object is
|
* * A prototype, where the same configuration is used, but a new object is
|
||||||
* created each time
|
* created each time
|
||||||
* * unmanaged, in which case a new object is created and injected, but no
|
* * unmanaged, in which case a new object is created and injected, but no
|
||||||
* information about its state is managed.
|
* information about its state is managed.
|
||||||
*
|
*
|
||||||
* Additional configuration of items managed by the injector can be done by
|
* Additional configuration of items managed by the injector can be done by
|
||||||
* providing configuration for the types, either by manually loading in an
|
* providing configuration for the types, either by manually loading in an
|
||||||
* array describing the configuration, or by specifying the configuration
|
* array describing the configuration, or by specifying the configuration
|
||||||
* for a type via SilverStripe's configuration mechanism.
|
* for a type via SilverStripe's configuration mechanism.
|
||||||
*
|
*
|
||||||
* Specify a configuration array of the format
|
* Specify a configuration array of the format
|
||||||
*
|
*
|
||||||
* array(
|
* array(
|
||||||
* array(
|
* array(
|
||||||
* 'id' => 'BeanId', // the name to be used if diff from the filename
|
* 'id' => 'BeanId', // the name to be used if diff from the filename
|
||||||
* 'priority' => 1, // priority. If another bean is defined with the same ID,
|
* 'priority' => 1, // priority. If another bean is defined with the same ID,
|
||||||
* // but has a lower priority, it is NOT overridden
|
* // but has a lower priority, it is NOT overridden
|
||||||
* 'class' => 'ClassName', // the name of the PHP class
|
* 'class' => 'ClassName', // the name of the PHP class
|
||||||
* 'src' => '/path/to/file' // the location of the class
|
* 'src' => '/path/to/file' // the location of the class
|
||||||
@ -77,7 +77,7 @@ use SilverStripe\Framework\Injector\Factory;
|
|||||||
*
|
*
|
||||||
* 'factory' => 'FactoryService' // A factory service to use to create instances.
|
* 'factory' => 'FactoryService' // A factory service to use to create instances.
|
||||||
* 'construct' => array( // properties to set at construction
|
* 'construct' => array( // properties to set at construction
|
||||||
* 'scalar',
|
* 'scalar',
|
||||||
* '%$BeanId',
|
* '%$BeanId',
|
||||||
* )
|
* )
|
||||||
* 'properties' => array(
|
* 'properties' => array(
|
||||||
@ -145,9 +145,9 @@ class Injector {
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $specs;
|
private $specs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of all the properties that should be automagically set on all
|
* A map of all the properties that should be automagically set on all
|
||||||
* objects instantiated by the injector
|
* objects instantiated by the injector
|
||||||
*/
|
*/
|
||||||
private $autoProperties;
|
private $autoProperties;
|
||||||
@ -158,11 +158,11 @@ class Injector {
|
|||||||
* @var Injector
|
* @var Injector
|
||||||
*/
|
*/
|
||||||
private static $instance;
|
private static $instance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether or not to automatically scan properties in injected objects to auto inject
|
* Indicates whether or not to automatically scan properties in injected objects to auto inject
|
||||||
* stuff, similar to the way grails does things.
|
* stuff, similar to the way grails does things.
|
||||||
*
|
*
|
||||||
* @var boolean
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
private $autoScanProperties = false;
|
private $autoScanProperties = false;
|
||||||
@ -180,16 +180,16 @@ class Injector {
|
|||||||
* @var Factory
|
* @var Factory
|
||||||
*/
|
*/
|
||||||
protected $objectCreator;
|
protected $objectCreator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locator for determining Config properties for services
|
* Locator for determining Config properties for services
|
||||||
*
|
*
|
||||||
* @var ServiceConfigurationLocator
|
* @var ServiceConfigurationLocator
|
||||||
*/
|
*/
|
||||||
protected $configLocator;
|
protected $configLocator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new injector.
|
* Create a new injector.
|
||||||
*
|
*
|
||||||
* @param array $config
|
* @param array $config
|
||||||
* Service configuration
|
* Service configuration
|
||||||
@ -202,16 +202,16 @@ class Injector {
|
|||||||
$this->specs = array(
|
$this->specs = array(
|
||||||
'Injector' => array('class' => 'Injector')
|
'Injector' => array('class' => 'Injector')
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->autoProperties = array();
|
$this->autoProperties = array();
|
||||||
|
|
||||||
|
|
||||||
$creatorClass = isset($config['creator']) ? $config['creator'] : 'InjectionCreator';
|
$creatorClass = isset($config['creator']) ? $config['creator'] : 'InjectionCreator';
|
||||||
$locatorClass = isset($config['locator']) ? $config['locator'] : 'ServiceConfigurationLocator';
|
$locatorClass = isset($config['locator']) ? $config['locator'] : 'ServiceConfigurationLocator';
|
||||||
|
|
||||||
$this->objectCreator = new $creatorClass;
|
$this->objectCreator = new $creatorClass;
|
||||||
$this->configLocator = new $locatorClass;
|
$this->configLocator = new $locatorClass;
|
||||||
|
|
||||||
if ($config) {
|
if ($config) {
|
||||||
$this->load($config);
|
$this->load($config);
|
||||||
}
|
}
|
||||||
@ -219,7 +219,7 @@ class Injector {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The injector instance this one was copied from when Injector::nest() was called.
|
* The injector instance this one was copied from when Injector::nest() was called.
|
||||||
*
|
*
|
||||||
* @var Injector
|
* @var Injector
|
||||||
*/
|
*/
|
||||||
protected $nestedFrom = null;
|
protected $nestedFrom = null;
|
||||||
@ -246,15 +246,15 @@ class Injector {
|
|||||||
public static function set_inst(Injector $instance) {
|
public static function set_inst(Injector $instance) {
|
||||||
return self::$instance = $instance;
|
return self::$instance = $instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the newly active {@link Injector} be a copy of the current active
|
* Make the newly active {@link Injector} be a copy of the current active
|
||||||
* {@link Injector} instance.
|
* {@link Injector} instance.
|
||||||
*
|
*
|
||||||
* You can then make changes to the injector with methods such as
|
* You can then make changes to the injector with methods such as
|
||||||
* {@link Injector::inst()->registerService()} which will be discarded
|
* {@link Injector::inst()->registerService()} which will be discarded
|
||||||
* upon a subsequent call to {@link Injector::unnest()}
|
* upon a subsequent call to {@link Injector::unnest()}
|
||||||
*
|
*
|
||||||
* @return Injector Reference to new active Injector instance
|
* @return Injector Reference to new active Injector instance
|
||||||
*/
|
*/
|
||||||
public static function nest() {
|
public static function nest() {
|
||||||
@ -266,24 +266,33 @@ class Injector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the active Injector back to the Injector instance the current active
|
* Change the active Injector back to the Injector instance the current active
|
||||||
* Injector object was copied from.
|
* Injector object was copied from.
|
||||||
*
|
*
|
||||||
* @return Injector Reference to restored active Injector instance
|
* @return Injector Reference to restored active Injector instance
|
||||||
*/
|
*/
|
||||||
public static function unnest() {
|
public static function unnest() {
|
||||||
return self::set_inst(self::$instance->nestedFrom);
|
if (self::inst()->nestedFrom) {
|
||||||
|
self::set_inst(self::inst()->nestedFrom);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
user_error(
|
||||||
|
"Unable to unnest root Injector, please make sure you don't have mis-matched nest/unnest",
|
||||||
|
E_USER_WARNING
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return self::inst();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicate whether we auto scan injected objects for properties to set.
|
* Indicate whether we auto scan injected objects for properties to set.
|
||||||
*
|
*
|
||||||
* @param boolean $val
|
* @param boolean $val
|
||||||
*/
|
*/
|
||||||
public function setAutoScanProperties($val) {
|
public function setAutoScanProperties($val) {
|
||||||
$this->autoScanProperties = $val;
|
$this->autoScanProperties = $val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the default factory to use for creating new objects.
|
* Sets the default factory to use for creating new objects.
|
||||||
*
|
*
|
||||||
@ -292,32 +301,32 @@ class Injector {
|
|||||||
public function setObjectCreator(Factory $obj) {
|
public function setObjectCreator(Factory $obj) {
|
||||||
$this->objectCreator = $obj;
|
$this->objectCreator = $obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Factory
|
* @return Factory
|
||||||
*/
|
*/
|
||||||
public function getObjectCreator() {
|
public function getObjectCreator() {
|
||||||
return $this->objectCreator;
|
return $this->objectCreator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the configuration locator
|
* Set the configuration locator
|
||||||
* @param ServiceConfigurationLocator $configLocator
|
* @param ServiceConfigurationLocator $configLocator
|
||||||
*/
|
*/
|
||||||
public function setConfigLocator($configLocator) {
|
public function setConfigLocator($configLocator) {
|
||||||
$this->configLocator = $configLocator;
|
$this->configLocator = $configLocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the configuration locator
|
* Retrieve the configuration locator
|
||||||
* @return ServiceConfigurationLocator
|
* @return ServiceConfigurationLocator
|
||||||
*/
|
*/
|
||||||
public function getConfigLocator() {
|
public function getConfigLocator() {
|
||||||
return $this->configLocator;
|
return $this->configLocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add in a specific mapping that should be catered for on a type.
|
* Add in a specific mapping that should be catered for on a type.
|
||||||
* This allows configuration of what should occur when an object
|
* This allows configuration of what should occur when an object
|
||||||
* of a particular type is injected, and what items should be injected
|
* of a particular type is injected, and what items should be injected
|
||||||
* for those properties / methods.
|
* for those properties / methods.
|
||||||
@ -326,19 +335,19 @@ class Injector {
|
|||||||
* The class to set a mapping for
|
* The class to set a mapping for
|
||||||
* @param type $property
|
* @param type $property
|
||||||
* The property to set the mapping for
|
* The property to set the mapping for
|
||||||
* @param type $injectType
|
* @param type $injectType
|
||||||
* The registered type that will be injected
|
* The registered type that will be injected
|
||||||
* @param string $injectVia
|
* @param string $injectVia
|
||||||
* Whether to inject by setting a property or calling a setter
|
* Whether to inject by setting a property or calling a setter
|
||||||
*/
|
*/
|
||||||
public function setInjectMapping($class, $property, $toInject, $injectVia = 'property') {
|
public function setInjectMapping($class, $property, $toInject, $injectVia = 'property') {
|
||||||
$mapping = isset($this->injectMap[$class]) ? $this->injectMap[$class] : array();
|
$mapping = isset($this->injectMap[$class]) ? $this->injectMap[$class] : array();
|
||||||
|
|
||||||
$mapping[$property] = array('name' => $toInject, 'type' => $injectVia);
|
$mapping[$property] = array('name' => $toInject, 'type' => $injectVia);
|
||||||
|
|
||||||
$this->injectMap[$class] = $mapping;
|
$this->injectMap[$class] = $mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an object that should be automatically set on managed objects
|
* Add an object that should be automatically set on managed objects
|
||||||
*
|
*
|
||||||
@ -370,7 +379,7 @@ class Injector {
|
|||||||
$spec = array('class' => $spec);
|
$spec = array('class' => $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = isset($spec['src']) ? $spec['src'] : null;
|
$file = isset($spec['src']) ? $spec['src'] : null;
|
||||||
$name = null;
|
$name = null;
|
||||||
|
|
||||||
if (file_exists($file)) {
|
if (file_exists($file)) {
|
||||||
@ -378,21 +387,21 @@ class Injector {
|
|||||||
$name = substr($filename, 0, strrpos($filename, '.'));
|
$name = substr($filename, 0, strrpos($filename, '.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// class is whatever's explicitly set,
|
// class is whatever's explicitly set,
|
||||||
$class = isset($spec['class']) ? $spec['class'] : $name;
|
$class = isset($spec['class']) ? $spec['class'] : $name;
|
||||||
|
|
||||||
// or the specid if nothing else available.
|
// or the specid if nothing else available.
|
||||||
if (!$class && is_string($specId)) {
|
if (!$class && is_string($specId)) {
|
||||||
$class = $specId;
|
$class = $specId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the class is set...
|
// make sure the class is set...
|
||||||
$spec['class'] = $class;
|
$spec['class'] = $class;
|
||||||
|
|
||||||
$id = is_string($specId) ? $specId : (isset($spec['id']) ? $spec['id'] : $class);
|
$id = is_string($specId) ? $specId : (isset($spec['id']) ? $spec['id'] : $class);
|
||||||
|
|
||||||
$priority = isset($spec['priority']) ? $spec['priority'] : 1;
|
$priority = isset($spec['priority']) ? $spec['priority'] : 1;
|
||||||
|
|
||||||
// see if we already have this defined. If so, check priority weighting
|
// see if we already have this defined. If so, check priority weighting
|
||||||
if (isset($this->specs[$id]) && isset($this->specs[$id]['priority'])) {
|
if (isset($this->specs[$id]) && isset($this->specs[$id]['priority'])) {
|
||||||
if ($this->specs[$id]['priority'] > $priority) {
|
if ($this->specs[$id]['priority'] > $priority) {
|
||||||
@ -412,12 +421,12 @@ class Injector {
|
|||||||
// We've removed this check because new functionality means that the 'class' field doesn't need to refer
|
// We've removed this check because new functionality means that the 'class' field doesn't need to refer
|
||||||
// specifically to a class anymore - it could be a compound statement, ala SilverStripe's old Object::create
|
// specifically to a class anymore - it could be a compound statement, ala SilverStripe's old Object::create
|
||||||
// functionality
|
// functionality
|
||||||
//
|
//
|
||||||
// if (!class_exists($class)) {
|
// if (!class_exists($class)) {
|
||||||
// throw new Exception("Failed to load '$class' from $file");
|
// throw new Exception("Failed to load '$class' from $file");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// store the specs for now - we lazy load on demand later on.
|
// store the specs for now - we lazy load on demand later on.
|
||||||
$this->specs[$id] = $spec;
|
$this->specs[$id] = $spec;
|
||||||
|
|
||||||
// EXCEPT when there's already an existing instance at this id.
|
// EXCEPT when there's already an existing instance at this id.
|
||||||
@ -430,20 +439,20 @@ class Injector {
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the configuration of an already defined service
|
* Update the configuration of an already defined service
|
||||||
*
|
*
|
||||||
* Use this if you don't want to register a complete new config, just append
|
* 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
|
* to an existing configuration. Helpful to avoid overwriting someone else's changes
|
||||||
*
|
*
|
||||||
* updateSpec('RequestProcessor', 'filters', '%$MyFilter')
|
* updateSpec('RequestProcessor', 'filters', '%$MyFilter')
|
||||||
*
|
*
|
||||||
* @param string $id
|
* @param string $id
|
||||||
* The name of the service to update the definition for
|
* The name of the service to update the definition for
|
||||||
* @param string $property
|
* @param string $property
|
||||||
* The name of the property to update.
|
* The name of the property to update.
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* The value to set
|
* The value to set
|
||||||
* @param boolean $append
|
* @param boolean $append
|
||||||
* Whether to append (the default) when the property is an array
|
* Whether to append (the default) when the property is an array
|
||||||
@ -457,20 +466,20 @@ class Injector {
|
|||||||
} else {
|
} else {
|
||||||
$this->specs[$id]['properties'][$property] = $value;
|
$this->specs[$id]['properties'][$property] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// and reload the object; existing bindings don't get
|
// and reload the object; existing bindings don't get
|
||||||
// updated though! (for now...)
|
// updated though! (for now...)
|
||||||
if (isset($this->serviceCache[$id])) {
|
if (isset($this->serviceCache[$id])) {
|
||||||
$this->instantiate(array('class'=>$id), $id);
|
$this->instantiate(array('class'=>$id), $id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a class specification to convert constructor configuration information if needed
|
* Update a class specification to convert constructor configuration information if needed
|
||||||
*
|
*
|
||||||
* We do this as a separate process to avoid unneeded calls to convertServiceProperty
|
* We do this as a separate process to avoid unneeded calls to convertServiceProperty
|
||||||
*
|
*
|
||||||
* @param array $spec
|
* @param array $spec
|
||||||
* The class specification to update
|
* The class specification to update
|
||||||
*/
|
*/
|
||||||
@ -484,7 +493,7 @@ class Injector {
|
|||||||
* Recursively convert a value into its proper representation with service references
|
* Recursively convert a value into its proper representation with service references
|
||||||
* resolved to actual objects
|
* resolved to actual objects
|
||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*/
|
*/
|
||||||
public function convertServiceProperty($value) {
|
public function convertServiceProperty($value) {
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
@ -494,7 +503,7 @@ class Injector {
|
|||||||
}
|
}
|
||||||
return $newVal;
|
return $newVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_string($value) && strpos($value, '%$') === 0) {
|
if (is_string($value) && strpos($value, '%$') === 0) {
|
||||||
$id = substr($value, 2);
|
$id = substr($value, 2);
|
||||||
return $this->get($id);
|
return $this->get($id);
|
||||||
@ -518,10 +527,10 @@ class Injector {
|
|||||||
* set any relevant properties
|
* set any relevant properties
|
||||||
*
|
*
|
||||||
* Optionally, you can pass a class name directly for creation
|
* Optionally, you can pass a class name directly for creation
|
||||||
*
|
*
|
||||||
* To access this from the outside, you should call ->get('Name') to ensure
|
* To access this from the outside, you should call ->get('Name') to ensure
|
||||||
* the appropriate checks are made on the specific type.
|
* the appropriate checks are made on the specific type.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param array $spec
|
* @param array $spec
|
||||||
* The specification of the class to instantiate
|
* The specification of the class to instantiate
|
||||||
@ -556,9 +565,9 @@ class Injector {
|
|||||||
// now set the service in place if needbe. This is NOT done for prototype beans, as they're
|
// now set the service in place if needbe. This is NOT done for prototype beans, as they're
|
||||||
// created anew each time
|
// created anew each time
|
||||||
if (!$type) {
|
if (!$type) {
|
||||||
$type = isset($spec['type']) ? $spec['type'] : null;
|
$type = isset($spec['type']) ? $spec['type'] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($id && (!$type || $type != 'prototype')) {
|
if ($id && (!$type || $type != 'prototype')) {
|
||||||
// this ABSOLUTELY must be set before the object is injected.
|
// this ABSOLUTELY must be set before the object is injected.
|
||||||
// This prevents circular reference errors down the line
|
// This prevents circular reference errors down the line
|
||||||
@ -573,7 +582,7 @@ class Injector {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Inject $object with available objects from the service cache
|
* Inject $object with available objects from the service cache
|
||||||
*
|
*
|
||||||
* @todo Track all the existing objects that have had a service bound
|
* @todo 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
|
* into them, so we can update that binding at a later point if needbe (ie
|
||||||
* if the managed service changes)
|
* if the managed service changes)
|
||||||
@ -583,12 +592,12 @@ class Injector {
|
|||||||
* @param string $asType
|
* @param string $asType
|
||||||
* The ID this item was loaded as. This is so that the property configuration
|
* 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
|
* for a type is referenced correctly in case $object is no longer the same
|
||||||
* type as the loaded config specification had it as.
|
* type as the loaded config specification had it as.
|
||||||
*/
|
*/
|
||||||
public function inject($object, $asType=null) {
|
public function inject($object, $asType=null) {
|
||||||
$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;
|
||||||
|
|
||||||
// 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 (isset($this->specs[$objtype]) && isset($this->specs[$objtype]['properties'])) {
|
||||||
@ -662,8 +671,8 @@ class Injector {
|
|||||||
if ($injections && count($injections)) {
|
if ($injections && count($injections)) {
|
||||||
foreach ($injections as $property => $value) {
|
foreach ($injections as $property => $value) {
|
||||||
// we're checking empty in case it already has a property at this name
|
// we're checking empty in case it already has a property at this name
|
||||||
// this doesn't catch privately set things, but they will only be set by a setter method,
|
// this doesn't catch privately set things, but they will only be set by a setter method,
|
||||||
// which should be responsible for preventing further setting if it doesn't want it.
|
// which should be responsible for preventing further setting if it doesn't want it.
|
||||||
if (empty($object->$property)) {
|
if (empty($object->$property)) {
|
||||||
$value = $this->convertServiceProperty($value);
|
$value = $this->convertServiceProperty($value);
|
||||||
$this->setObjectProperty($object, $property, $value);
|
$this->setObjectProperty($object, $property, $value);
|
||||||
@ -691,7 +700,7 @@ class Injector {
|
|||||||
* Set an object's property to a specific value
|
* Set an object's property to a specific value
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* The name of the property to set
|
* The name of the property to set
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* The value to set
|
* The value to set
|
||||||
*/
|
*/
|
||||||
protected function setObjectProperty($object, $name, $value) {
|
protected function setObjectProperty($object, $name, $value) {
|
||||||
@ -704,14 +713,14 @@ class Injector {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Does the given service exist, and if so, what's the stored name for it?
|
* 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 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,
|
* 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.
|
* but have only registered a 'Log' service, we'll instead return that.
|
||||||
*
|
*
|
||||||
* Will recursively call hasService for each depth of dotting
|
* Will recursively call hasService for each depth of dotting
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
* The name of the service (as it might be different from the one passed in)
|
* The name of the service (as it might be different from the one passed in)
|
||||||
*/
|
*/
|
||||||
public function hasService($name) {
|
public function hasService($name) {
|
||||||
@ -719,52 +728,52 @@ class Injector {
|
|||||||
if (isset($this->specs[$name])) {
|
if (isset($this->specs[$name])) {
|
||||||
return $name;
|
return $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// okay, check whether we've got a compound name - don't worry about 0 index, cause that's an
|
// okay, check whether we've got a compound name - don't worry about 0 index, cause that's an
|
||||||
// invalid name
|
// invalid name
|
||||||
if (!strpos($name, '.')) {
|
if (!strpos($name, '.')) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->hasService(substr($name, 0, strrpos($name, '.')));
|
return $this->hasService(substr($name, 0, strrpos($name, '.')));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a service object with an optional name to register it as the
|
* Register a service object with an optional name to register it as the
|
||||||
* service for
|
* service for
|
||||||
*
|
*
|
||||||
* @param stdClass $service
|
* @param stdClass $service
|
||||||
* The object to register
|
* The object to register
|
||||||
* @param string $replace
|
* @param string $replace
|
||||||
* The name of the object to replace (if different to the
|
* The name of the object to replace (if different to the
|
||||||
* class name of the object to register)
|
* class name of the object to register)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function registerService($service, $replace = null) {
|
public function registerService($service, $replace = null) {
|
||||||
$registerAt = get_class($service);
|
$registerAt = get_class($service);
|
||||||
if ($replace != null) {
|
if ($replace != null) {
|
||||||
$registerAt = $replace;
|
$registerAt = $replace;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->specs[$registerAt] = array('class' => get_class($service));
|
$this->specs[$registerAt] = array('class' => get_class($service));
|
||||||
$this->serviceCache[$registerAt] = $service;
|
$this->serviceCache[$registerAt] = $service;
|
||||||
$this->inject($service);
|
$this->inject($service);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a service with an explicit name
|
* Register a service with an explicit name
|
||||||
*
|
*
|
||||||
* @deprecated since 3.1.1
|
* @deprecated since 3.1.1
|
||||||
*/
|
*/
|
||||||
public function registerNamedService($name, $service) {
|
public function registerNamedService($name, $service) {
|
||||||
return $this->registerService($service, $name);
|
return $this->registerService($service, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a named object from the cached list of objects managed
|
* Removes a named object from the cached list of objects managed
|
||||||
* by the inject
|
* by the inject
|
||||||
*
|
*
|
||||||
* @param type $name
|
* @param type $name
|
||||||
* The name to unregister
|
* The name to unregister
|
||||||
*/
|
*/
|
||||||
public function unregisterNamedObject($name) {
|
public function unregisterNamedObject($name) {
|
||||||
@ -772,35 +781,35 @@ class Injector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear out all objects that are managed by the injetor.
|
* Clear out all objects that are managed by the injetor.
|
||||||
*/
|
*/
|
||||||
public function unregisterAllObjects() {
|
public function unregisterAllObjects() {
|
||||||
$this->serviceCache = array('Injector' => $this);
|
$this->serviceCache = array('Injector' => $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a named managed object
|
* Get a named managed object
|
||||||
*
|
*
|
||||||
* Will first check to see if the item has been registered as a configured service/bean
|
* Will first check to see if the item has been registered as a configured service/bean
|
||||||
* and return that if so.
|
* and return that if so.
|
||||||
*
|
*
|
||||||
* Next, will check to see if there's any registered configuration for the given type
|
* Next, will check to see if there's any registered configuration for the given type
|
||||||
* and will then try and load that
|
* and will then try and load that
|
||||||
*
|
*
|
||||||
* Failing all of that, will just return a new instance of the
|
* Failing all of that, will just return a new instance of the
|
||||||
* specificied object.
|
* specificied object.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* the name of the service to retrieve. If not a registered
|
* the name of the service to retrieve. If not a registered
|
||||||
* service, then a class of the given name is instantiated
|
* service, then a class of the given name is instantiated
|
||||||
* @param boolean $asSingleton
|
* @param boolean $asSingleton
|
||||||
* Whether to register the created object as a singleton
|
* Whether to register the created object as a singleton
|
||||||
* if no other configuration is found
|
* if no other configuration is found
|
||||||
* @param array $constructorArgs
|
* @param array $constructorArgs
|
||||||
* Optional set of arguments to pass as constructor arguments
|
* Optional set of arguments to pass as constructor arguments
|
||||||
* if this object is to be created from scratch
|
* if this object is to be created from scratch
|
||||||
* (ie asSingleton = false)
|
* (ie asSingleton = false)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function get($name, $asSingleton = true, $constructorArgs = null) {
|
public function get($name, $asSingleton = true, $constructorArgs = null) {
|
||||||
// reassign the name as it might actually be a compound name
|
// reassign the name as it might actually be a compound name
|
||||||
@ -809,14 +818,14 @@ class Injector {
|
|||||||
// we don't want to return the singleton version of it.
|
// we don't want to return the singleton version of it.
|
||||||
$spec = $this->specs[$serviceName];
|
$spec = $this->specs[$serviceName];
|
||||||
$type = isset($spec['type']) ? $spec['type'] : null;
|
$type = isset($spec['type']) ? $spec['type'] : null;
|
||||||
|
|
||||||
// if we're explicitly a prototype OR we're not wanting a singleton
|
// if we're explicitly a prototype OR we're not wanting a singleton
|
||||||
if (($type && $type == 'prototype') || !$asSingleton) {
|
if (($type && $type == 'prototype') || !$asSingleton) {
|
||||||
if ($spec && $constructorArgs) {
|
if ($spec && $constructorArgs) {
|
||||||
$spec['constructor'] = $constructorArgs;
|
$spec['constructor'] = $constructorArgs;
|
||||||
} else {
|
} else {
|
||||||
// convert any _configured_ constructor args.
|
// convert any _configured_ constructor args.
|
||||||
// we don't call this for get() calls where someone passes in
|
// we don't call this for get() calls where someone passes in
|
||||||
// constructor args, otherwise we end up calling convertServiceParams
|
// constructor args, otherwise we end up calling convertServiceParams
|
||||||
// way too often
|
// way too often
|
||||||
$this->updateSpecConstructor($spec);
|
$this->updateSpecConstructor($spec);
|
||||||
@ -830,7 +839,7 @@ class Injector {
|
|||||||
return $this->serviceCache[$serviceName];
|
return $this->serviceCache[$serviceName];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$config = $this->configLocator->locateConfigFor($name);
|
$config = $this->configLocator->locateConfigFor($name);
|
||||||
if ($config) {
|
if ($config) {
|
||||||
$this->load(array($name => $config));
|
$this->load(array($name => $config));
|
||||||
@ -844,7 +853,7 @@ class Injector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we've got this far, we're dealing with a case of a user wanting
|
// If we've got this far, we're dealing with a case of a user wanting
|
||||||
// to create an object based on its name. So, we need to fake its config
|
// to create an object based on its name. So, we need to fake its config
|
||||||
// if the user wants it managed as a singleton service style object
|
// if the user wants it managed as a singleton service style object
|
||||||
$spec = array('class' => $name, 'constructor' => $constructorArgs);
|
$spec = array('class' => $name, 'constructor' => $constructorArgs);
|
||||||
@ -856,10 +865,10 @@ class Injector {
|
|||||||
|
|
||||||
return $this->instantiate($spec);
|
return $this->instantiate($spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Magic method to return an item directly
|
* Magic method to return an item directly
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* The named object to retrieve
|
* The named object to retrieve
|
||||||
* @return mixed
|
* @return mixed
|
||||||
@ -870,20 +879,20 @@ class Injector {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to get() but always returns a new object of the given type
|
* Similar to get() but always returns a new object of the given type
|
||||||
*
|
*
|
||||||
* Additional parameters are passed through as
|
* Additional parameters are passed through as
|
||||||
*
|
*
|
||||||
* @param type $name
|
* @param type $name
|
||||||
*/
|
*/
|
||||||
public function create($name) {
|
public function create($name) {
|
||||||
$constructorArgs = func_get_args();
|
$constructorArgs = func_get_args();
|
||||||
array_shift($constructorArgs);
|
array_shift($constructorArgs);
|
||||||
return $this->get($name, false, count($constructorArgs) ? $constructorArgs : null);
|
return $this->get($name, false, count($constructorArgs) ? $constructorArgs : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an object with the supplied argument array
|
* Creates an object with the supplied argument array
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* Name of the class to create an object of
|
* Name of the class to create an object of
|
||||||
* @param array $args
|
* @param array $args
|
||||||
@ -893,4 +902,4 @@ class Injector {
|
|||||||
public function createWithArgs($name, $constructorArgs) {
|
public function createWithArgs($name, $constructorArgs) {
|
||||||
return $this->get($name, false, $constructorArgs);
|
return $this->get($name, false, $constructorArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
123
core/Config.php
123
core/Config.php
@ -10,62 +10,62 @@
|
|||||||
* - An array
|
* - An array
|
||||||
* - A non-array value
|
* - A non-array value
|
||||||
*
|
*
|
||||||
* If the value is an array, each value in the array may also be one of those
|
* If the value is an array, each value in the array may also be one of those
|
||||||
* three types.
|
* three types.
|
||||||
*
|
*
|
||||||
* A property can have a value specified in multiple locations, each of which
|
* A property can have a value specified in multiple locations, each of which
|
||||||
* have a hard coded or explicit priority. We combine all these values together
|
* have a hard coded or explicit priority. We combine all these values together
|
||||||
* into a "composite" value using rules that depend on the priority order of
|
* into a "composite" value using rules that depend on the priority order of
|
||||||
* the locations to give the final value, using these rules:
|
* the locations to give the final value, using these rules:
|
||||||
*
|
*
|
||||||
* - If the value is an array, each array is added to the _beginning_ of the
|
* - If the value is an array, each array is added to the _beginning_ of the
|
||||||
* composite array in ascending priority order. If a higher priority item has
|
* composite array in ascending priority order. If a higher priority item has
|
||||||
* a non-integer key which is the same as a lower priority item, the value of
|
* a non-integer key which is the same as a lower priority item, the value of
|
||||||
* those items is merged using these same rules, and the result of the merge
|
* those items is merged using these same rules, and the result of the merge
|
||||||
* is located in the same location the higher priority item would be if there
|
* is located in the same location the higher priority item would be if there
|
||||||
* was no key clash. Other than in this key-clash situation, within the
|
* was no key clash. Other than in this key-clash situation, within the
|
||||||
* particular array, order is preserved.
|
* particular array, order is preserved.
|
||||||
*
|
*
|
||||||
* - If the value is not an array, the highest priority value is used without
|
* - If the value is not an array, the highest priority value is used without
|
||||||
* any attempt to merge.
|
* any attempt to merge.
|
||||||
*
|
*
|
||||||
* It is an error to have mixed types of the same named property in different
|
* It is an error to have mixed types of the same named property in different
|
||||||
* locations (but an error will not necessarily be raised due to optimizations
|
* locations (but an error will not necessarily be raised due to optimizations
|
||||||
* in the lookup code).
|
* in the lookup code).
|
||||||
*
|
*
|
||||||
* The exception to this is "false-ish" values - empty arrays, empty strings,
|
* The exception to this is "false-ish" values - empty arrays, empty strings,
|
||||||
* etc. When merging a non-false-ish value with a false-ish value, the result
|
* etc. When merging a non-false-ish value with a false-ish value, the result
|
||||||
* will be the non-false-ish value regardless of priority. When merging two
|
* will be the non-false-ish value regardless of priority. When merging two
|
||||||
* false-ish values the result will be the higher priority false-ish value.
|
* false-ish values the result will be the higher priority false-ish value.
|
||||||
*
|
*
|
||||||
* The locations that configuration values are taken from in highest -> lowest
|
* The locations that configuration values are taken from in highest -> lowest
|
||||||
* priority order.
|
* priority order.
|
||||||
*
|
*
|
||||||
* - Any values set via a call to Config#update.
|
* - Any values set via a call to Config#update.
|
||||||
*
|
*
|
||||||
* - The configuration values taken from the YAML files in _config directories
|
* - The configuration values taken from the YAML files in _config directories
|
||||||
* (internally sorted in before / after order, where the item that is latest
|
* (internally sorted in before / after order, where the item that is latest
|
||||||
* is highest priority).
|
* is highest priority).
|
||||||
*
|
*
|
||||||
* - Any static set on an "additional static source" class (such as an
|
* - Any static set on an "additional static source" class (such as an
|
||||||
* extension) named the same as the name of the property.
|
* extension) named the same as the name of the property.
|
||||||
*
|
*
|
||||||
* - Any static set on the class named the same as the name of the property.
|
* - Any static set on the class named the same as the name of the property.
|
||||||
*
|
*
|
||||||
* - The composite configuration value of the parent class of this class.
|
* - The composite configuration value of the parent class of this class.
|
||||||
*
|
*
|
||||||
* At some of these levels you can also set masks. These remove values from the
|
* At some of these levels you can also set masks. These remove values from the
|
||||||
* composite value at their priority point rather than add. They are much
|
* composite value at their priority point rather than add. They are much
|
||||||
* simpler. They consist of a list of key / value pairs. When applied against
|
* simpler. They consist of a list of key / value pairs. When applied against
|
||||||
* the current composite value:
|
* the current composite value:
|
||||||
*
|
*
|
||||||
* - If the composite value is a sequential array, any member of that array
|
* - If the composite value is a sequential array, any member of that array
|
||||||
* that matches any value in the mask is removed.
|
* that matches any value in the mask is removed.
|
||||||
*
|
*
|
||||||
* - If the composite value is an associative array, any member of that array
|
* - If the composite value is an associative array, any member of that array
|
||||||
* that matches both the key and value of any pair in the mask is removed.
|
* that matches both the key and value of any pair in the mask is removed.
|
||||||
*
|
*
|
||||||
* - If the composite value is not an array, if that value matches any value
|
* - If the composite value is not an array, if that value matches any value
|
||||||
* in the mask it is removed.
|
* in the mask it is removed.
|
||||||
*
|
*
|
||||||
* @package framework
|
* @package framework
|
||||||
@ -74,7 +74,7 @@
|
|||||||
class Config {
|
class Config {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A marker instance for the "anything" singleton value. Don't access
|
* A marker instance for the "anything" singleton value. Don't access
|
||||||
* directly, even in-class, always use self::anything()
|
* directly, even in-class, always use self::anything()
|
||||||
*
|
*
|
||||||
* @var Object
|
* @var Object
|
||||||
@ -82,9 +82,9 @@ class Config {
|
|||||||
private static $_anything = null;
|
private static $_anything = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a marker class instance that is used to do a "remove anything with
|
* Get a marker class instance that is used to do a "remove anything with
|
||||||
* this key" by adding $key => Config::anything() to the suppress array
|
* this key" by adding $key => Config::anything() to the suppress array
|
||||||
*
|
*
|
||||||
* @return Object
|
* @return Object
|
||||||
*/
|
*/
|
||||||
public static function anything() {
|
public static function anything() {
|
||||||
@ -98,7 +98,7 @@ class Config {
|
|||||||
// -- Source options bitmask --
|
// -- Source options bitmask --
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* source options bitmask value - merge all parent configuration in as
|
* source options bitmask value - merge all parent configuration in as
|
||||||
* lowest priority.
|
* lowest priority.
|
||||||
*
|
*
|
||||||
* @const
|
* @const
|
||||||
@ -106,7 +106,7 @@ class Config {
|
|||||||
const INHERITED = 0;
|
const INHERITED = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* source options bitmask value - only get configuration set for this
|
* source options bitmask value - only get configuration set for this
|
||||||
* specific class, not any of it's parents.
|
* specific class, not any of it's parents.
|
||||||
*
|
*
|
||||||
* @const
|
* @const
|
||||||
@ -114,23 +114,23 @@ class Config {
|
|||||||
const UNINHERITED = 1;
|
const UNINHERITED = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* source options bitmask value - inherit, but stop on the first class
|
* source options bitmask value - inherit, but stop on the first class
|
||||||
* that actually provides a value (event an empty value).
|
* that actually provides a value (event an empty value).
|
||||||
*
|
*
|
||||||
* @const
|
* @const
|
||||||
*/
|
*/
|
||||||
const FIRST_SET = 2;
|
const FIRST_SET = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @const source options bitmask value - do not use additional statics
|
* @const source options bitmask value - do not use additional statics
|
||||||
* sources (such as extension)
|
* sources (such as extension)
|
||||||
*/
|
*/
|
||||||
const EXCLUDE_EXTRA_SOURCES = 4;
|
const EXCLUDE_EXTRA_SOURCES = 4;
|
||||||
|
|
||||||
// -- get_value_type response enum --
|
// -- get_value_type response enum --
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return flag for get_value_type indicating value is a scalar (or really
|
* Return flag for get_value_type indicating value is a scalar (or really
|
||||||
* just not-an-array, at least ATM)
|
* just not-an-array, at least ATM)
|
||||||
*
|
*
|
||||||
* @const
|
* @const
|
||||||
@ -144,7 +144,7 @@ class Config {
|
|||||||
const IS_ARRAY = 2;
|
const IS_ARRAY = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get whether the value is an array or not. Used to be more complicated,
|
* Get whether the value is an array or not. Used to be more complicated,
|
||||||
* but still nice sugar to have an enum to compare and not just a true /
|
* but still nice sugar to have an enum to compare and not just a true /
|
||||||
* false value.
|
* false value.
|
||||||
*
|
*
|
||||||
@ -171,7 +171,7 @@ class Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo If we can, replace next static & static methods with DI once that's in
|
* @todo If we can, replace next static & static methods with DI once that's in
|
||||||
*/
|
*/
|
||||||
protected static $instance;
|
protected static $instance;
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ class Config {
|
|||||||
*
|
*
|
||||||
* Configs should not normally be manually created.
|
* Configs should not normally be manually created.
|
||||||
*
|
*
|
||||||
* In general use you will use this method to obtain the current Config
|
* In general use you will use this method to obtain the current Config
|
||||||
* instance.
|
* instance.
|
||||||
*
|
*
|
||||||
* @return Config
|
* @return Config
|
||||||
@ -198,7 +198,7 @@ class Config {
|
|||||||
*
|
*
|
||||||
* {@link Config} objects should not normally be manually created.
|
* {@link Config} objects should not normally be manually created.
|
||||||
*
|
*
|
||||||
* A use case for replacing the active configuration set would be for
|
* A use case for replacing the active configuration set would be for
|
||||||
* creating an isolated environment for unit tests.
|
* creating an isolated environment for unit tests.
|
||||||
*
|
*
|
||||||
* @param Config $instance New instance of Config to assign
|
* @param Config $instance New instance of Config to assign
|
||||||
@ -213,13 +213,13 @@ class Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the newly active {@link Config} be a copy of the current active
|
* Make the newly active {@link Config} be a copy of the current active
|
||||||
* {@link Config} instance.
|
* {@link Config} instance.
|
||||||
*
|
*
|
||||||
* You can then make changes to the configuration by calling update and
|
* You can then make changes to the configuration by calling update and
|
||||||
* remove on the new value returned by {@link Config::inst()}, and then discard
|
* remove on the new value returned by {@link Config::inst()}, and then discard
|
||||||
* those changes later by calling unnest.
|
* those changes later by calling unnest.
|
||||||
*
|
*
|
||||||
* @return Config Reference to new active Config instance
|
* @return Config Reference to new active Config instance
|
||||||
*/
|
*/
|
||||||
public static function nest() {
|
public static function nest() {
|
||||||
@ -231,13 +231,22 @@ class Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the active Config back to the Config instance the current active
|
* Change the active Config back to the Config instance the current active
|
||||||
* Config object was copied from.
|
* Config object was copied from.
|
||||||
*
|
*
|
||||||
* @return Config Reference to new active Config instance
|
* @return Config Reference to new active Config instance
|
||||||
*/
|
*/
|
||||||
public static function unnest() {
|
public static function unnest() {
|
||||||
return self::set_instance(self::$instance->nestedFrom);
|
if (self::inst()->nestedFrom) {
|
||||||
|
self::set_instance(self::inst()->nestedFrom);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
user_error(
|
||||||
|
"Unable to unnest root Config, please make sure you don't have mis-matched nest/unnest",
|
||||||
|
E_USER_WARNING
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return self::inst();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -246,7 +255,7 @@ class Config {
|
|||||||
protected $cache;
|
protected $cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Each copy of the Config object need's it's own cache, so changes don't
|
* Each copy of the Config object need's it's own cache, so changes don't
|
||||||
* leak through to other instances.
|
* leak through to other instances.
|
||||||
*/
|
*/
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
@ -257,22 +266,22 @@ class Config {
|
|||||||
$this->cache = clone $this->cache;
|
$this->cache = clone $this->cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Config - The config instance this one was copied from when
|
* @var Config - The config instance this one was copied from when
|
||||||
* Config::nest() was called.
|
* Config::nest() was called.
|
||||||
*/
|
*/
|
||||||
protected $nestedFrom = null;
|
protected $nestedFrom = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array - Array of arrays. Each member is an nested array keyed as
|
* @var array - Array of arrays. Each member is an nested array keyed as
|
||||||
* $class => $name => $value, where value is a config value to treat as
|
* $class => $name => $value, where value is a config value to treat as
|
||||||
* the highest priority item.
|
* the highest priority item.
|
||||||
*/
|
*/
|
||||||
protected $overrides = array();
|
protected $overrides = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array $suppresses Array of arrays. Each member is an nested array
|
* @var array $suppresses Array of arrays. Each member is an nested array
|
||||||
* keyed as $class => $name => $value, where value is a config value suppress
|
* keyed as $class => $name => $value, where value is a config value suppress
|
||||||
* from any lower priority item.
|
* from any lower priority item.
|
||||||
*/
|
*/
|
||||||
protected $suppresses = array();
|
protected $suppresses = array();
|
||||||
@ -287,7 +296,7 @@ class Config {
|
|||||||
*/
|
*/
|
||||||
public function pushConfigStaticManifest(SS_ConfigStaticManifest $manifest) {
|
public function pushConfigStaticManifest(SS_ConfigStaticManifest $manifest) {
|
||||||
array_unshift($this->staticManifests, $manifest);
|
array_unshift($this->staticManifests, $manifest);
|
||||||
|
|
||||||
$this->cache->clean();
|
$this->cache->clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,8 +492,8 @@ class Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($this->suppresses[$k][$class][$name])) {
|
if (isset($this->suppresses[$k][$class][$name])) {
|
||||||
$suppress = $suppress
|
$suppress = $suppress
|
||||||
? array_merge($suppress, $this->suppresses[$k][$class][$name])
|
? array_merge($suppress, $this->suppresses[$k][$class][$name])
|
||||||
: $this->suppresses[$k][$class][$name];
|
: $this->suppresses[$k][$class][$name];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -730,7 +739,7 @@ class Config_LRU {
|
|||||||
// Target count - not always the lowest, but guaranteed to exist (or hit an empty item)
|
// Target count - not always the lowest, but guaranteed to exist (or hit an empty item)
|
||||||
$target = $this->c - self::SIZE + 1;
|
$target = $this->c - self::SIZE + 1;
|
||||||
$i = $stop = $this->i;
|
$i = $stop = $this->i;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!($i--)) $i = self::SIZE-1;
|
if (!($i--)) $i = self::SIZE-1;
|
||||||
$item = $this->cache[$i];
|
$item = $this->cache[$i];
|
||||||
|
Loading…
Reference in New Issue
Block a user