vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php line 114

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