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

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