| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 | <?php/* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. *//** * Dependency Injection container. * * @author  Chris Corbyn */class Swift_DependencyContainer{    /** Constant for literal value types */    const TYPE_VALUE = 0x0001;    /** Constant for new instance types */    const TYPE_INSTANCE = 0x0010;    /** Constant for shared instance types */    const TYPE_SHARED = 0x0100;    /** Constant for aliases */    const TYPE_ALIAS = 0x1000;    /** Singleton instance */    private static $_instance = null;    /** The data container */    private $_store = array();    /** The current endpoint in the data container */    private $_endPoint;    /**     * Constructor should not be used.     *     * Use {@link getInstance()} instead.     */    public function __construct() { }    /**     * Returns a singleton of the DependencyContainer.     *     * @return Swift_DependencyContainer     */    public static function getInstance()    {        if (!isset(self::$_instance)) {            self::$_instance = new self();        }        return self::$_instance;    }    /**     * List the names of all items stored in the Container.     *     * @return array     */    public function listItems()    {        return array_keys($this->_store);    }    /**     * Test if an item is registered in this container with the given name.     *     * @see register()     *     * @param string $itemName     *     * @return bool     */    public function has($itemName)    {        return array_key_exists($itemName, $this->_store)            && isset($this->_store[$itemName]['lookupType']);    }    /**     * Lookup the item with the given $itemName.     *     * @see register()     *     * @param string $itemName     *     * @return mixed     *     * @throws Swift_DependencyException If the dependency is not found     */    public function lookup($itemName)    {        if (!$this->has($itemName)) {            throw new Swift_DependencyException(                'Cannot lookup dependency "' . $itemName . '" since it is not registered.'                );        }        switch ($this->_store[$itemName]['lookupType']) {            case self::TYPE_ALIAS:                return $this->_createAlias($itemName);            case self::TYPE_VALUE:                return $this->_getValue($itemName);            case self::TYPE_INSTANCE:                return $this->_createNewInstance($itemName);            case self::TYPE_SHARED:                return $this->_createSharedInstance($itemName);        }    }    /**     * Create an array of arguments passed to the constructor of $itemName.     *     * @param string $itemName     *     * @return array     */    public function createDependenciesFor($itemName)    {        $args = array();        if (isset($this->_store[$itemName]['args'])) {            $args = $this->_resolveArgs($this->_store[$itemName]['args']);        }        return $args;    }    /**     * Register a new dependency with $itemName.     *     * This method returns the current DependencyContainer instance because it     * requires the use of the fluid interface to set the specific details for the     * dependency.     * @see asNewInstanceOf(), asSharedInstanceOf(), asValue()     *     * @param string $itemName     *     * @return Swift_DependencyContainer     */    public function register($itemName)    {        $this->_store[$itemName] = array();        $this->_endPoint =& $this->_store[$itemName];        return $this;    }    /**     * Specify the previously registered item as a literal value.     *     * {@link register()} must be called before this will work.     *     * @param mixed $value     *     * @return Swift_DependencyContainer     */    public function asValue($value)    {        $endPoint =& $this->_getEndPoint();        $endPoint['lookupType'] = self::TYPE_VALUE;        $endPoint['value'] = $value;        return $this;    }    /**     * Specify the previously registered item as an alias of another item.     *     * @param string $lookup     *     * @return Swift_DependencyContainer     */    public function asAliasOf($lookup)    {        $endPoint =& $this->_getEndPoint();        $endPoint['lookupType'] = self::TYPE_ALIAS;        $endPoint['ref'] = $lookup;        return $this;    }    /**     * Specify the previously registered item as a new instance of $className.     *     * {@link register()} must be called before this will work.     * Any arguments can be set with {@link withDependencies()},     * {@link addConstructorValue()} or {@link addConstructorLookup()}.     *     * @see withDependencies(), addConstructorValue(), addConstructorLookup()     *     * @param string $className     *     * @return Swift_DependencyContainer     */    public function asNewInstanceOf($className)    {        $endPoint =& $this->_getEndPoint();        $endPoint['lookupType'] = self::TYPE_INSTANCE;        $endPoint['className'] = $className;        return $this;    }    /**     * Specify the previously registered item as a shared instance of $className.     *     * {@link register()} must be called before this will work.     *     * @param string $className     *     * @return Swift_DependencyContainer     */    public function asSharedInstanceOf($className)    {        $endPoint =& $this->_getEndPoint();        $endPoint['lookupType'] = self::TYPE_SHARED;        $endPoint['className'] = $className;        return $this;    }    /**     * Specify a list of injected dependencies for the previously registered item.     *     * This method takes an array of lookup names.     *     * @see addConstructorValue(), addConstructorLookup()     *     * @param array $lookups     *     * @return Swift_DependencyContainer     */    public function withDependencies(array $lookups)    {        $endPoint =& $this->_getEndPoint();        $endPoint['args'] = array();        foreach ($lookups as $lookup) {            $this->addConstructorLookup($lookup);        }        return $this;    }    /**     * Specify a literal (non looked up) value for the constructor of the     * previously registered item.     *     * @see withDependencies(), addConstructorLookup()     *     * @param mixed $value     *     * @return Swift_DependencyContainer     */    public function addConstructorValue($value)    {        $endPoint =& $this->_getEndPoint();        if (!isset($endPoint['args'])) {            $endPoint['args'] = array();        }        $endPoint['args'][] = array('type' => 'value', 'item' => $value);        return $this;    }    /**     * Specify a dependency lookup for the constructor of the previously     * registered item.     *     * @see withDependencies(), addConstructorValue()     *     * @param string $lookup     *     * @return Swift_DependencyContainer     */    public function addConstructorLookup($lookup)    {        $endPoint =& $this->_getEndPoint();        if (!isset($this->_endPoint['args'])) {            $endPoint['args'] = array();        }        $endPoint['args'][] = array('type' => 'lookup', 'item' => $lookup);        return $this;    }    /** Get the literal value with $itemName */    private function _getValue($itemName)    {        return $this->_store[$itemName]['value'];    }    /** Resolve an alias to another item */    private function _createAlias($itemName)    {        return $this->lookup($this->_store[$itemName]['ref']);    }    /** Create a fresh instance of $itemName */    private function _createNewInstance($itemName)    {        $reflector = new ReflectionClass($this->_store[$itemName]['className']);        if ($reflector->getConstructor()) {            return $reflector->newInstanceArgs(                $this->createDependenciesFor($itemName)                );        } else {            return $reflector->newInstance();        }    }    /** Create and register a shared instance of $itemName */    private function _createSharedInstance($itemName)    {        if (!isset($this->_store[$itemName]['instance'])) {            $this->_store[$itemName]['instance'] = $this->_createNewInstance($itemName);        }        return $this->_store[$itemName]['instance'];    }    /** Get the current endpoint in the store */    private function &_getEndPoint()    {        if (!isset($this->_endPoint)) {            throw new BadMethodCallException(                'Component must first be registered by calling register()'                );        }        return $this->_endPoint;    }    /** Get an argument list with dependencies resolved */    private function _resolveArgs(array $args)    {        $resolved = array();        foreach ($args as $argDefinition) {            switch ($argDefinition['type']) {                case 'lookup':                    $resolved[] = $this->_lookupRecursive($argDefinition['item']);                    break;                case 'value':                    $resolved[] = $argDefinition['item'];                    break;            }        }        return $resolved;    }    /** Resolve a single dependency with an collections */    private function _lookupRecursive($item)    {        if (is_array($item)) {            $collection = array();            foreach ($item as $k => $v) {                $collection[$k] = $this->_lookupRecursive($v);            }            return $collection;        } else {            return $this->lookup($item);        }    }}
 |