vendor/swiftmailer/lib/classes/Swift/DependencyContainer.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of SwiftMailer.
       
     5  * (c) 2004-2009 Chris Corbyn
       
     6  *
       
     7  * For the full copyright and license information, please view the LICENSE
       
     8  * file that was distributed with this source code.
       
     9  */
       
    10 
       
    11 
       
    12 /**
       
    13  * Dependency Injection container.
       
    14  * @package Swift
       
    15  * @author Chris Corbyn
       
    16  */
       
    17 class Swift_DependencyContainer
       
    18 {
       
    19   
       
    20   /** Constant for literal value types */
       
    21   const TYPE_VALUE = 0x0001;
       
    22   
       
    23   /** Constant for new instance types */
       
    24   const TYPE_INSTANCE = 0x0010;
       
    25   
       
    26   /** Constant for shared instance types */
       
    27   const TYPE_SHARED = 0x0100;
       
    28   
       
    29   /** Constant for aliases */
       
    30   const TYPE_ALIAS = 0x1000;
       
    31   
       
    32   /** Singleton instance */
       
    33   private static $_instance = null;
       
    34   
       
    35   /** The data container */
       
    36   private $_store = array();
       
    37   
       
    38   /** The current endpoint in the data container */
       
    39   private $_endPoint;
       
    40   
       
    41   /**
       
    42    * Constructor should not be used.
       
    43    * Use {@link getInstance()} instead.
       
    44    */
       
    45   public function __construct() { }
       
    46   
       
    47   /**
       
    48    * Returns a singleton of the DependencyContainer.
       
    49    * @return Swift_DependencyContainer
       
    50    */
       
    51   public static function getInstance()
       
    52   {
       
    53     if (!isset(self::$_instance))
       
    54     {
       
    55       self::$_instance = new self();
       
    56     }
       
    57     return self::$_instance;
       
    58   }
       
    59   
       
    60   /**
       
    61    * List the names of all items stored in the Container.
       
    62    * @return array
       
    63    */
       
    64   public function listItems()
       
    65   {
       
    66     return array_keys($this->_store);
       
    67   }
       
    68   
       
    69   /**
       
    70    * Test if an item is registered in this container with the given name.
       
    71    * @param string $itemName
       
    72    * @return boolean
       
    73    * @see register()
       
    74    */
       
    75   public function has($itemName)
       
    76   {
       
    77     return array_key_exists($itemName, $this->_store)
       
    78       && isset($this->_store[$itemName]['lookupType']);
       
    79   }
       
    80   
       
    81   /**
       
    82    * Lookup the item with the given $itemName.
       
    83    * @param string $itemName
       
    84    * @return mixed
       
    85    * @throws Swift_DependencyException If the dependency is not found
       
    86    * @see register()
       
    87    */
       
    88   public function lookup($itemName)
       
    89   {
       
    90     if (!$this->has($itemName))
       
    91     {
       
    92       throw new Swift_DependencyException(
       
    93         'Cannot lookup dependency "' . $itemName . '" since it is not registered.'
       
    94         );
       
    95     }
       
    96     
       
    97     switch ($this->_store[$itemName]['lookupType'])
       
    98     {
       
    99       case self::TYPE_ALIAS:
       
   100         return $this->_createAlias($itemName);
       
   101       case self::TYPE_VALUE:
       
   102         return $this->_getValue($itemName);
       
   103       case self::TYPE_INSTANCE:
       
   104         return $this->_createNewInstance($itemName);
       
   105       case self::TYPE_SHARED:
       
   106         return $this->_createSharedInstance($itemName);
       
   107     }
       
   108   }
       
   109   
       
   110   /**
       
   111    * Create an array of arguments passed to the constructor of $itemName.
       
   112    * @param string $itemName
       
   113    * @return array
       
   114    */
       
   115   public function createDependenciesFor($itemName)
       
   116   {
       
   117     $args = array();
       
   118     if (isset($this->_store[$itemName]['args']))
       
   119     {
       
   120       $args = $this->_resolveArgs($this->_store[$itemName]['args']);
       
   121     }
       
   122     return $args;
       
   123   }
       
   124   
       
   125   /**
       
   126    * Register a new dependency with $itemName.
       
   127    * This method returns the current DependencyContainer instance because it
       
   128    * requires the use of the fluid interface to set the specific details for the
       
   129    * dependency.
       
   130    *
       
   131    * @param string $itemName
       
   132    * @return Swift_DependencyContainer
       
   133    * @see asNewInstanceOf(), asSharedInstanceOf(), asValue()
       
   134    */
       
   135   public function register($itemName)
       
   136   {
       
   137     $this->_store[$itemName] = array();
       
   138     $this->_endPoint =& $this->_store[$itemName];
       
   139     return $this;
       
   140   }
       
   141   
       
   142   /**
       
   143    * Specify the previously registered item as a literal value.
       
   144    * {@link register()} must be called before this will work.
       
   145    *
       
   146    * @param mixed $value
       
   147    * @return Swift_DependencyContainer
       
   148    */
       
   149   public function asValue($value)
       
   150   {
       
   151     $endPoint =& $this->_getEndPoint();
       
   152     $endPoint['lookupType'] = self::TYPE_VALUE;
       
   153     $endPoint['value'] = $value;
       
   154     return $this;
       
   155   }
       
   156   
       
   157   /**
       
   158    * Specify the previously registered item as an alias of another item.
       
   159    * @param string $lookup
       
   160    * @return Swift_DependencyContainer
       
   161    */
       
   162   public function asAliasOf($lookup)
       
   163   {
       
   164     $endPoint =& $this->_getEndPoint();
       
   165     $endPoint['lookupType'] = self::TYPE_ALIAS;
       
   166     $endPoint['ref'] = $lookup;
       
   167     return $this;
       
   168   }
       
   169   
       
   170   /**
       
   171    * Specify the previously registered item as a new instance of $className.
       
   172    * {@link register()} must be called before this will work.
       
   173    * Any arguments can be set with {@link withDependencies()},
       
   174    * {@link addConstructorValue()} or {@link addConstructorLookup()}.
       
   175    *
       
   176    * @param string $className
       
   177    * @return Swift_DependencyContainer
       
   178    * @see withDependencies(), addConstructorValue(), addConstructorLookup()
       
   179    */
       
   180   public function asNewInstanceOf($className)
       
   181   {
       
   182     $endPoint =& $this->_getEndPoint();
       
   183     $endPoint['lookupType'] = self::TYPE_INSTANCE;
       
   184     $endPoint['className'] = $className;
       
   185     return $this;
       
   186   }
       
   187   
       
   188   /**
       
   189    * Specify the previously registered item as a shared instance of $className.
       
   190    * {@link register()} must be called before this will work.
       
   191    * @param string $className
       
   192    * @return Swift_DependencyContainer
       
   193    */
       
   194   public function asSharedInstanceOf($className)
       
   195   {
       
   196     $endPoint =& $this->_getEndPoint();
       
   197     $endPoint['lookupType'] = self::TYPE_SHARED;
       
   198     $endPoint['className'] = $className;
       
   199     return $this;
       
   200   }
       
   201   
       
   202   /**
       
   203    * Specify a list of injected dependencies for the previously registered item.
       
   204    * This method takes an array of lookup names.
       
   205    * 
       
   206    * @param array $lookups
       
   207    * @return Swift_DependencyContainer
       
   208    * @see addConstructorValue(), addConstructorLookup()
       
   209    */
       
   210   public function withDependencies(array $lookups)
       
   211   {
       
   212     $endPoint =& $this->_getEndPoint();
       
   213     $endPoint['args'] = array();
       
   214     foreach ($lookups as $lookup)
       
   215     {
       
   216       $this->addConstructorLookup($lookup);
       
   217     }
       
   218     return $this;
       
   219   }
       
   220   
       
   221   /**
       
   222    * Specify a literal (non looked up) value for the constructor of the
       
   223    * previously registered item.
       
   224    * 
       
   225    * @param mixed $value
       
   226    * @return Swift_DependencyContainer
       
   227    * @see withDependencies(), addConstructorLookup()
       
   228    */
       
   229   public function addConstructorValue($value)
       
   230   {
       
   231     $endPoint =& $this->_getEndPoint();
       
   232     if (!isset($endPoint['args']))
       
   233     {
       
   234       $endPoint['args'] = array();
       
   235     }
       
   236     $endPoint['args'][] = array('type' => 'value', 'item' => $value);
       
   237     return $this;
       
   238   }
       
   239   
       
   240   /**
       
   241    * Specify a dependency lookup for the constructor of the previously
       
   242    * registered item.
       
   243    * 
       
   244    * @param string $lookup
       
   245    * @return Swift_DependencyContainer
       
   246    * @see withDependencies(), addConstructorValue()
       
   247    */
       
   248   public function addConstructorLookup($lookup)
       
   249   {
       
   250     $endPoint =& $this->_getEndPoint();
       
   251     if (!isset($this->_endPoint['args']))
       
   252     {
       
   253       $endPoint['args'] = array();
       
   254     }
       
   255     $endPoint['args'][] = array('type' => 'lookup', 'item' => $lookup);
       
   256     return $this;
       
   257   }
       
   258   
       
   259   // -- Private methods
       
   260   
       
   261   /** Get the literal value with $itemName */
       
   262   private function _getValue($itemName)
       
   263   {
       
   264     return $this->_store[$itemName]['value'];
       
   265   }
       
   266   
       
   267   /** Resolve an alias to another item */
       
   268   private function _createAlias($itemName)
       
   269   {
       
   270     return $this->lookup($this->_store[$itemName]['ref']);
       
   271   }
       
   272   
       
   273   /** Create a fresh instance of $itemName */
       
   274   private function _createNewInstance($itemName)
       
   275   {
       
   276     $reflector = new ReflectionClass($this->_store[$itemName]['className']);
       
   277     if ($reflector->getConstructor())
       
   278     {
       
   279       return $reflector->newInstanceArgs(
       
   280         $this->createDependenciesFor($itemName)
       
   281         );
       
   282     }
       
   283     else
       
   284     {
       
   285       return $reflector->newInstance();
       
   286     }
       
   287   }
       
   288   
       
   289   /** Create and register a shared instance of $itemName */
       
   290   private function _createSharedInstance($itemName)
       
   291   {
       
   292     if (!isset($this->_store[$itemName]['instance']))
       
   293     {
       
   294       $this->_store[$itemName]['instance'] = $this->_createNewInstance($itemName);
       
   295     }
       
   296     return $this->_store[$itemName]['instance'];
       
   297   }
       
   298   
       
   299   /** Get the current endpoint in the store */
       
   300   private function &_getEndPoint()
       
   301   {
       
   302     if (!isset($this->_endPoint))
       
   303     {
       
   304       throw new BadMethodCallException(
       
   305         'Component must first be registered by calling register()'
       
   306         );
       
   307     }
       
   308     return $this->_endPoint;
       
   309   }
       
   310   
       
   311   /** Get an argument list with dependencies resolved */
       
   312   private function _resolveArgs(array $args)
       
   313   {
       
   314     $resolved = array();
       
   315     foreach ($args as $argDefinition)
       
   316     {
       
   317       switch ($argDefinition['type'])
       
   318       {
       
   319         case 'lookup':
       
   320           $resolved[] = $this->_lookupRecursive($argDefinition['item']);
       
   321           break;
       
   322         case 'value':
       
   323           $resolved[] = $argDefinition['item'];
       
   324           break;
       
   325       }
       
   326     }
       
   327     return $resolved;
       
   328   }
       
   329   
       
   330   /** Resolve a single dependency with an collections */
       
   331   private function _lookupRecursive($item)
       
   332   {
       
   333     if (is_array($item))
       
   334     {
       
   335       $collection = array();
       
   336       foreach ($item as $k => $v)
       
   337       {
       
   338         $collection[$k] = $this->_lookupRecursive($v);
       
   339       }
       
   340       return $collection;
       
   341     }
       
   342     else
       
   343     {
       
   344       return $this->lookup($item);
       
   345     }
       
   346   }
       
   347   
       
   348 }