PageRenderTime 30ms CodeModel.GetById 13ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/framework/vendor/swift/lib/classes/Swift/DependencyContainer.php

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