Skip to content

Instantly share code, notes, and snippets.

@Bellardia
Created January 14, 2015 05:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Bellardia/09a69565a8d363577ff9 to your computer and use it in GitHub Desktop.
Save Bellardia/09a69565a8d363577ff9 to your computer and use it in GitHub Desktop.
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