You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
4.9 KiB
158 lines
4.9 KiB
<?php |
|
/** |
|
* @link http://www.yiiframework.com/ |
|
* @copyright Copyright (c) 2008 Yii Software LLC |
|
* @license http://www.yiiframework.com/license/ |
|
*/ |
|
|
|
namespace yii\di; |
|
|
|
use Yii; |
|
use yii\base\InvalidConfigException; |
|
|
|
/** |
|
* Instance is a reference to a named component in a container. |
|
* |
|
* You may use [[get()]] to obtain the actual component. |
|
* |
|
* Instance is mainly used in two places: |
|
* |
|
* - When configuring a dependency injection container, you use Instance to reference a component |
|
* - In classes which use external dependent objects. |
|
* |
|
* For example, the following configuration specifies that the "db" property should be |
|
* a component referenced by the "db" component: |
|
* |
|
* ```php |
|
* [ |
|
* 'class' => 'app\components\UserFinder', |
|
* 'db' => Instance::of('db'), |
|
* ] |
|
* ``` |
|
* |
|
* And in `UserFinder`, you may use `Instance` to make sure the "db" property is properly configured: |
|
* |
|
* ```php |
|
* namespace app\components; |
|
* |
|
* use yii\base\Object; |
|
* use yii\di\Instance; |
|
* |
|
* class UserFinder extends \yii\db\Object |
|
* { |
|
* public $db; |
|
* |
|
* public function init() |
|
* { |
|
* $this->db = Instance::ensure($this->db, 'yii\db\Connection'); |
|
* } |
|
* } |
|
* ``` |
|
* |
|
* @author Qiang Xue <qiang.xue@gmail.com> |
|
* @since 2.0 |
|
*/ |
|
class Instance |
|
{ |
|
/** |
|
* @var ContainerInterface the container |
|
*/ |
|
public $container; |
|
/** |
|
* @var string the component ID |
|
*/ |
|
public $id; |
|
|
|
/** |
|
* Constructor. |
|
* @param string $id the component ID |
|
* @param ContainerInterface $container the container. If null, the application instance will be used. |
|
*/ |
|
protected function __construct($id, ContainerInterface $container = null) |
|
{ |
|
$this->id = $id; |
|
$this->container = $container; |
|
} |
|
|
|
/** |
|
* Creates a new Instance object. |
|
* @param string $id the component ID |
|
* @param ContainerInterface $container the container. If null, the application instance will be used. |
|
* @return Instance the new Instance object. |
|
*/ |
|
public static function of($id, ContainerInterface $container = null) |
|
{ |
|
return new self($id, $container); |
|
} |
|
|
|
/** |
|
* Ensures that `$value` is an object or a reference to the object of the specified type. |
|
* |
|
* An exception will be thrown if the type is not matched. |
|
* |
|
* Upon success, the method will return the object itself or the object referenced by `$value`. |
|
* |
|
* For example, |
|
* |
|
* ```php |
|
* use yii\db\Connection; |
|
* |
|
* // returns Yii::$app->db |
|
* $db = Instance::ensure('db', Connection::className()); |
|
* // or |
|
* $instance = Instance::of('db'); |
|
* $db = Instance::ensure($instance, Connection::className()); |
|
* ``` |
|
* |
|
* @param object|string|static $value an object or a reference to the desired object. |
|
* You may specify a reference in terms of a component ID or an Instance object. |
|
* @param string $type the class name to be checked |
|
* @param ContainerInterface $container the container. If null, the application instance will be used. |
|
* @return null|\yii\base\Component|Instance |
|
* @throws \yii\base\InvalidConfigException |
|
*/ |
|
public static function ensure($value, $type, $container = null) |
|
{ |
|
if (empty($value)) { |
|
throw new InvalidConfigException('The required component is not specified.'); |
|
} |
|
if ($value instanceof $type) { |
|
return $value; |
|
} elseif (is_string($value)) { |
|
$value = new self($value, $container); |
|
} |
|
|
|
if ($value instanceof self) { |
|
$component = $value->get(); |
|
if ($component instanceof $type) { |
|
return $component; |
|
} else { |
|
$container = $value->container ? : Yii::$app; |
|
if ($component === null) { |
|
throw new InvalidConfigException('"' . $value->id . '" is not a valid component ID of ' . get_class($container)); |
|
} else { |
|
throw new InvalidConfigException('"' . $value->id . '" refers to a ' . get_class($component) . " component. $type is expected."); |
|
} |
|
} |
|
} else { |
|
$valueType = is_object($value) ? get_class($value) : gettype($value); |
|
throw new InvalidConfigException("Invalid data type: $valueType. $type is expected."); |
|
} |
|
} |
|
|
|
/** |
|
* Returns the actual component referenced by this Instance object. |
|
* @return object the actual component referenced by this Instance object. |
|
* @throws InvalidConfigException there is no container available |
|
*/ |
|
public function get() |
|
{ |
|
/** @var ContainerInterface $container */ |
|
$container = $this->container ? : Yii::$app; |
|
if ($container !== null) { |
|
return $container->get($this->id); |
|
} else { |
|
throw new InvalidConfigException("Unable to locate a container for component \"{$this->id}\"."); |
|
} |
|
} |
|
}
|
|
|