Created
January 14, 2015 05:16
-
-
Save Bellardia/09a69565a8d363577ff9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use \Phalcon\DI\Exception as Exception, | |
\Phalcon\DI\FactoryDefault as DefaultInjector, | |
\Phalcon\DI\InjectionAwareInterface, | |
\Phalcon\Config\Adapter\Json as JsonConfig; | |
/** | |
* DependencyInjector class | |
* Override the default DI class, due to an inability to update shared services | |
* | |
* @extends DefaultInjector | |
*/ | |
class DependencyInjector extends DefaultInjector { | |
protected $expiredInstances = array(); | |
protected $localCache = array(); | |
/** | |
* __get function | |
* Ability to resolve services via __get(); | |
* @access public | |
* @param mixed $name | |
* @return void | |
*/ | |
public function __get($name) { | |
if ($this->has($name)) | |
return $this->get($name); | |
return null; | |
} | |
/** | |
* getServiceDefinition function | |
* Resolve a service definition by name, which contains meta-data about the services state | |
* @access public | |
* @param mixed $name The name of the service to resolve | |
* @return Phalcon\DI\Service | |
*/ | |
public function getServiceDefinition($name) { | |
// If the service exists, we can rely on getServices() containing it, so we'll return it | |
if ($this->has($name)) | |
return $this->getServices()[$name]; | |
return null; | |
} | |
/** | |
* invalidateSharedService function | |
* invalidates a shared service when its definition is changed | |
* By default, phalcon will cache a sharedservice forever as soon as its resolved once, making it impossible to change after use | |
* | |
* @access public | |
* @param mixed $name The name of the service to invalidate | |
* @return void | |
*/ | |
public function invalidateSharedService($name) { | |
// DO NOT REMOVE | |
// This is required to convince PHP to load the _sharedInstances variable from the PHP extension, otherwise it won't resolve | |
get_object_vars($this); | |
// Save the object hash that's expired | |
if (isset($this->_sharedInstances[$name])) | |
$this->expiredInstances[$name] = spl_object_hash($this->_sharedInstances[$name]); | |
// Destroy the local cache (only gets used if shared instances have already been redefined once) | |
unset($this->localCache[$name]); | |
} | |
/** | |
* setShared function | |
* A wrapper of the default setShared() function, which will send a call to invalidateSharedService() to ensure services aren't re-used | |
* | |
* @access public | |
* @param mixed $name The name of the service to invalidate | |
* @param mixed $definition The service definition | |
* @return object the created service | |
*/ | |
public function setShared($name, $definition) { | |
$this->invalidateSharedService($name); | |
return parent::setShared($name, $definition); | |
} | |
/** | |
* set function | |
* A wrapper of the default set() function, which will send a call to invalidateSharedService() to ensure services aren't re-used | |
* This function will redirect shared services defined using the "shared=true" flag to the setShared() function for consistency | |
* | |
* @access public | |
* @param mixed $name The name of the service to invalidate | |
* @param mixed $definition The service definition | |
* @return object the created service | |
*/ | |
public function set($name, $definition, $shared = null) { | |
$this->invalidateSharedService($name); | |
// If this is a shared service, use the shared initializer | |
if ($shared) | |
return $this->setShared($name, $definition); | |
// Use the default setter | |
return parent::set($name, $definition, $shared); | |
} | |
/** | |
* getShared function | |
* Returns a shared service, with an additional check to ensure that the service definition isn't out of date | |
* If this service has been re-declared, we'll return the new service definition instead | |
* | |
* @access public | |
* @param mixed $name The name of the service to return | |
* @param mixed $parameters (default: null) Additional paramters to pass to the constructor | |
* @return object the resolved service | |
*/ | |
public function getShared($name, $parameters = null) { | |
// We know that the shared service definition is outdated, return the new service | |
if (isset($this->expiredInstances[$name])) | |
return $this->getSaneService($name, $parameters); | |
// Grab the shared service | |
return parent::getShared($name, $parameters); | |
} | |
/** | |
* get function | |
* Returns a service, with an additional check to ensure that the service wasn't defined as a shared service | |
* If this service was declared as shared, we'll redirect the function to getShared() instead | |
* | |
* @access public | |
* @param mixed $name The name of the service to return | |
* @param mixed $parameters (default: null) Additional paramters to pass to the constructor | |
* @return object the resolved service | |
*/ | |
public function get($name, $parameters = null) { | |
// If the service is shared with a shared service configuration, return the shared instance rather than a new one | |
$definition = $this->getServiceDefinition($name); | |
// Default to getting the shared service, since that's how it was defined | |
if (isset($definition) && $definition->isShared()) | |
return $this->getShared($name, $parameters); | |
// Otherwise return a new instance | |
return parent::get($name, $parameters); | |
} | |
/** | |
* getSaneService function | |
* Return a sane shared service definition (ensures that any service returned via getShared() will match the current service definition) | |
* | |
* @access protected | |
* @param mixed $name The name of the service we want returned | |
* @param mixed $parameters (default: null) Additional paramters to pass to the constructor | |
* @return object the service | |
*/ | |
protected function getSaneService($name, $parameters = null) { | |
if (isset($this->localCache[$name])) | |
return $this->localCache[$name]; | |
// Get the service definition, so that we ca re-resolve from source | |
$definition = $this->getServiceDefinition($name); | |
// Return the newly resolved service | |
$class = $definition->resolve($parameters, $this); | |
// Inject the DI if necessary | |
if ($class instanceof InjectionAwareInterface) | |
$class->setDI($this); | |
return ($this->localCache[$name] = $class); | |
} | |
/** | |
* setRaw function. | |
* A placeholder to cause an exception if this method is used. Since this allows altering the underlying function definition of the service | |
* Consideration must be made to ensure that the function getShared() will still return a sane service after its definition has been changed | |
* It's probably best to avoid this function unless no other option exists | |
* | |
* @throws Exception | |
*/ | |
public function setRaw($rawDefinition) { | |
throw new Exception('Function is not currently defined, needs to be updated to ensure compatibility with getShared()'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment