Commit 3d0a266a by Qiang Xue

Merge pull request #2788 from yiisoft/feature-container

DI container
parents f605508b b1c44162
...@@ -55,7 +55,7 @@ $object = Yii::createObject([ ...@@ -55,7 +55,7 @@ $object = Yii::createObject([
'class' => 'MyClass', 'class' => 'MyClass',
'property1' => 'abc', 'property1' => 'abc',
'property2' => 'cde', 'property2' => 'cde',
], $param1, $param2); ], [$param1, $param2]);
``` ```
......
...@@ -93,26 +93,24 @@ In the above code, four components are configured: `cache`, `user`, `errorHandle ...@@ -93,26 +93,24 @@ In the above code, four components are configured: `cache`, `user`, `errorHandle
The configuration array has one special key named `class` that identifies the component's base class. The rest of the keys and values are used The configuration array has one special key named `class` that identifies the component's base class. The rest of the keys and values are used
to configure component properties in the same way as top-level keys are used to configure the application's properties. to configure component properties in the same way as top-level keys are used to configure the application's properties.
Each application has a predefined set of components. To configure one of these, the `class` key can be omitted to use the default Yii class for that component. You can check the `registerCoreComponents()` method of the application you are using Each application has a predefined set of components. To configure one of these, the `class` key can be omitted to use the default Yii class for that component. You can check the `coreComponents()` method of the application you are using
to get a list of component IDs and corresponding classes. to get a list of component IDs and corresponding classes.
Note that Yii is smart enough to only configure the component when it's actually being used: for example, if you configure the `cache` component in your configuration file but never use the `cache` component in your code, no instance of that component will be created and no time is wasted configuring it. Note that Yii is smart enough to only configure the component when it's actually being used: for example, if you configure the `cache` component in your configuration file but never use the `cache` component in your code, no instance of that component will be created and no time is wasted configuring it.
Setting component defaults classwide Setting component defaults class-wide
------------------------------------ ------------------------------------
For each component you can specifiy classwide defaults. For example, if you want to change the class used for all `LinkPager` For each component you can specify class-wide defaults. For example, if you want to change the class used for all `LinkPager`
widgets without specifying the class for every widget usage, you can do the following: widgets without specifying the class for every widget usage, you can do the following:
```php ```php
\Yii::$objectConfig = [ \Yii::$container->set('yii\widgets\LinkPager', [
'yii\widgets\LinkPager' => [ 'options' => [
'options' => [ 'class' => 'pagination',
'class' => 'pagination', ],
], ]);
],
];
``` ```
The code above should be executed once before `LinkPager` widget is used. It can be done in `index.php`, the application The code above should be executed once before `LinkPager` widget is used. It can be done in `index.php`, the application
configuration file, or anywhere else. configuration file, or anywhere else.
\ No newline at end of file
...@@ -71,7 +71,7 @@ $object = Yii::createObject([ ...@@ -71,7 +71,7 @@ $object = Yii::createObject([
'class' => 'MyClass', 'class' => 'MyClass',
'property1' => 'abc', 'property1' => 'abc',
'property2' => 'cde', 'property2' => 'cde',
], $param1, $param2); ], [$param1, $param2]);
``` ```
More on configuration can be found in the [Basic concepts section](basics.md). More on configuration can be found in the [Basic concepts section](basics.md).
......
...@@ -164,7 +164,7 @@ class AuthAction extends Action ...@@ -164,7 +164,7 @@ class AuthAction extends Action
if (!empty($_GET[$this->clientIdGetParamName])) { if (!empty($_GET[$this->clientIdGetParamName])) {
$clientId = $_GET[$this->clientIdGetParamName]; $clientId = $_GET[$this->clientIdGetParamName];
/** @var \yii\authclient\Collection $collection */ /** @var \yii\authclient\Collection $collection */
$collection = Yii::$app->getComponent($this->clientCollection); $collection = Yii::$app->get($this->clientCollection);
if (!$collection->hasClient($clientId)) { if (!$collection->hasClient($clientId)) {
throw new NotFoundHttpException("Unknown auth client '{$clientId}'"); throw new NotFoundHttpException("Unknown auth client '{$clientId}'");
} }
......
...@@ -143,7 +143,7 @@ class Choice extends Widget ...@@ -143,7 +143,7 @@ class Choice extends Widget
protected function defaultClients() protected function defaultClients()
{ {
/** @var $collection \yii\authclient\Collection */ /** @var $collection \yii\authclient\Collection */
$collection = Yii::$app->getComponent($this->clientCollection); $collection = Yii::$app->get($this->clientCollection);
return $collection->getClients(); return $collection->getClients();
} }
......
...@@ -86,7 +86,7 @@ class RequestPanel extends Panel ...@@ -86,7 +86,7 @@ class RequestPanel extends Panel
$action = null; $action = null;
} }
/** @var \yii\web\Session $session */ /** @var \yii\web\Session $session */
$session = Yii::$app->getComponent('session', false); $session = Yii::$app->has('session', true) ? Yii::$app->get('session') : null;
return [ return [
'flashes' => $session ? $session->getAllFlashes() : [], 'flashes' => $session ? $session->getAllFlashes() : [],
......
...@@ -59,7 +59,7 @@ class ActiveRecord extends BaseActiveRecord ...@@ -59,7 +59,7 @@ class ActiveRecord extends BaseActiveRecord
*/ */
public static function getDb() public static function getDb()
{ {
return \Yii::$app->getComponent('elasticsearch'); return \Yii::$app->get('elasticsearch');
} }
/** /**
......
...@@ -55,7 +55,7 @@ class DebugAction extends Action ...@@ -55,7 +55,7 @@ class DebugAction extends Action
$options = ['pretty' => true]; $options = ['pretty' => true];
/** @var Connection $db */ /** @var Connection $db */
$db = \Yii::$app->getComponent($this->db); $db = \Yii::$app->get($this->db);
$time = microtime(true); $time = microtime(true);
switch ($method) { switch ($method) {
case 'GET': $result = $db->get($url, $options, $body, true); break; case 'GET': $result = $db->get($url, $options, $body, true); break;
......
...@@ -115,7 +115,7 @@ class Query extends Component implements QueryInterface ...@@ -115,7 +115,7 @@ class Query extends Component implements QueryInterface
public function createCommand($db = null) public function createCommand($db = null)
{ {
if ($db === null) { if ($db === null) {
$db = Yii::$app->getComponent('elasticsearch'); $db = Yii::$app->get('elasticsearch');
} }
$commandConfig = $db->getQueryBuilder()->build($this); $commandConfig = $db->getQueryBuilder()->build($this);
......
...@@ -437,9 +437,9 @@ class Generator extends \yii\gii\Generator ...@@ -437,9 +437,9 @@ class Generator extends \yii\gii\Generator
*/ */
public function validateDb() public function validateDb()
{ {
if (Yii::$app->hasComponent($this->db) === false) { if (!Yii::$app->has($this->db)) {
$this->addError('db', 'There is no application component named "db".'); $this->addError('db', 'There is no application component named "db".');
} elseif (!Yii::$app->getComponent($this->db) instanceof Connection) { } elseif (!Yii::$app->get($this->db) instanceof Connection) {
$this->addError('db', 'The "db" application component must be a DB connection instance.'); $this->addError('db', 'The "db" application component must be a DB connection instance.');
} }
} }
......
...@@ -29,7 +29,7 @@ abstract class ActiveRecord extends BaseActiveRecord ...@@ -29,7 +29,7 @@ abstract class ActiveRecord extends BaseActiveRecord
*/ */
public static function getDb() public static function getDb()
{ {
return \Yii::$app->getComponent('mongodb'); return \Yii::$app->get('mongodb');
} }
/** /**
......
...@@ -9,6 +9,7 @@ namespace yii\mongodb; ...@@ -9,6 +9,7 @@ namespace yii\mongodb;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\di\Instance;
/** /**
* Cache implements a cache application component by storing cached data in a MongoDB. * Cache implements a cache application component by storing cached data in a MongoDB.
...@@ -61,12 +62,7 @@ class Cache extends \yii\caching\Cache ...@@ -61,12 +62,7 @@ class Cache extends \yii\caching\Cache
public function init() public function init()
{ {
parent::init(); parent::init();
if (is_string($this->db)) { $this->db = Instance::ensure($this->db, Connection::className());
$this->db = Yii::$app->getComponent($this->db);
}
if (!$this->db instanceof Connection) {
throw new InvalidConfigException($this->className() . "::db must be either a MongoDB connection instance or the application component ID of a MongoDB connection.");
}
} }
/** /**
......
...@@ -62,7 +62,7 @@ class Query extends Component implements QueryInterface ...@@ -62,7 +62,7 @@ class Query extends Component implements QueryInterface
public function getCollection($db = null) public function getCollection($db = null)
{ {
if ($db === null) { if ($db === null) {
$db = Yii::$app->getComponent('mongodb'); $db = Yii::$app->get('mongodb');
} }
return $db->getCollection($this->from); return $db->getCollection($this->from);
......
...@@ -9,6 +9,7 @@ namespace yii\mongodb; ...@@ -9,6 +9,7 @@ namespace yii\mongodb;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\di\Instance;
/** /**
* Session extends [[\yii\web\Session]] by using MongoDB as session data storage. * Session extends [[\yii\web\Session]] by using MongoDB as session data storage.
...@@ -55,13 +56,8 @@ class Session extends \yii\web\Session ...@@ -55,13 +56,8 @@ class Session extends \yii\web\Session
*/ */
public function init() public function init()
{ {
if (is_string($this->db)) {
$this->db = Yii::$app->getComponent($this->db);
}
if (!$this->db instanceof Connection) {
throw new InvalidConfigException($this->className() . "::db must be either a MongoDB connection instance or the application component ID of a MongoDB connection.");
}
parent::init(); parent::init();
$this->db = Instance::ensure($this->db, Connection::className());
} }
/** /**
......
...@@ -31,7 +31,7 @@ class Query extends \yii\mongodb\Query ...@@ -31,7 +31,7 @@ class Query extends \yii\mongodb\Query
public function getCollection($db = null) public function getCollection($db = null)
{ {
if ($db === null) { if ($db === null) {
$db = Yii::$app->getComponent('mongodb'); $db = Yii::$app->get('mongodb');
} }
return $db->getFileCollection($this->from); return $db->getFileCollection($this->from);
......
...@@ -45,7 +45,7 @@ class ActiveRecord extends BaseActiveRecord ...@@ -45,7 +45,7 @@ class ActiveRecord extends BaseActiveRecord
*/ */
public static function getDb() public static function getDb()
{ {
return \Yii::$app->getComponent('redis'); return \Yii::$app->get('redis');
} }
/** /**
......
...@@ -76,7 +76,7 @@ class Cache extends \yii\caching\Cache ...@@ -76,7 +76,7 @@ class Cache extends \yii\caching\Cache
{ {
parent::init(); parent::init();
if (is_string($this->redis)) { if (is_string($this->redis)) {
$this->redis = Yii::$app->getComponent($this->redis); $this->redis = Yii::$app->get($this->redis);
} elseif (is_array($this->redis)) { } elseif (is_array($this->redis)) {
if (!isset($this->redis['class'])) { if (!isset($this->redis['class'])) {
$this->redis['class'] = Connection::className(); $this->redis['class'] = Connection::className();
......
...@@ -80,7 +80,7 @@ class Session extends \yii\web\Session ...@@ -80,7 +80,7 @@ class Session extends \yii\web\Session
public function init() public function init()
{ {
if (is_string($this->redis)) { if (is_string($this->redis)) {
$this->redis = Yii::$app->getComponent($this->redis); $this->redis = Yii::$app->get($this->redis);
} elseif (is_array($this->redis)) { } elseif (is_array($this->redis)) {
if (!isset($this->redis['class'])) { if (!isset($this->redis['class'])) {
$this->redis['class'] = Connection::className(); $this->redis['class'] = Connection::className();
......
...@@ -62,7 +62,7 @@ abstract class ActiveRecord extends BaseActiveRecord ...@@ -62,7 +62,7 @@ abstract class ActiveRecord extends BaseActiveRecord
*/ */
public static function getDb() public static function getDb()
{ {
return \Yii::$app->getComponent('sphinx'); return \Yii::$app->get('sphinx');
} }
/** /**
......
...@@ -155,7 +155,7 @@ class Query extends Component implements QueryInterface ...@@ -155,7 +155,7 @@ class Query extends Component implements QueryInterface
*/ */
protected function defaultConnection() protected function defaultConnection()
{ {
return Yii::$app->getComponent('sphinx'); return Yii::$app->get('sphinx');
} }
/** /**
......
...@@ -132,7 +132,7 @@ class Schema extends Object ...@@ -132,7 +132,7 @@ class Schema extends Object
if ($db->enableSchemaCache && !in_array($name, $db->schemaCacheExclude, true)) { if ($db->enableSchemaCache && !in_array($name, $db->schemaCacheExclude, true)) {
/** @var $cache Cache */ /** @var $cache Cache */
$cache = is_string($db->schemaCache) ? Yii::$app->getComponent($db->schemaCache) : $db->schemaCache; $cache = is_string($db->schemaCache) ? Yii::$app->get($db->schemaCache, false) : $db->schemaCache;
if ($cache instanceof Cache) { if ($cache instanceof Cache) {
$key = $this->getCacheKey($name); $key = $this->getCacheKey($name);
if ($refresh || ($index = $cache->get($key)) === false) { if ($refresh || ($index = $cache->get($key)) === false) {
...@@ -296,7 +296,7 @@ class Schema extends Object ...@@ -296,7 +296,7 @@ class Schema extends Object
public function refresh() public function refresh()
{ {
/** @var $cache Cache */ /** @var $cache Cache */
$cache = is_string($this->db->schemaCache) ? Yii::$app->getComponent($this->db->schemaCache) : $this->db->schemaCache; $cache = is_string($this->db->schemaCache) ? Yii::$app->get($this->db->schemaCache, false) : $this->db->schemaCache;
if ($this->db->enableSchemaCache && $cache instanceof Cache) { if ($this->db->enableSchemaCache && $cache instanceof Cache) {
GroupDependency::invalidate($cache, $this->getCacheGroup()); GroupDependency::invalidate($cache, $this->getCacheGroup());
} }
......
...@@ -200,10 +200,9 @@ class Mailer extends BaseMailer ...@@ -200,10 +200,9 @@ class Mailer extends BaseMailer
} }
} }
unset($config['constructArgs']); unset($config['constructArgs']);
array_unshift($args, $className); $object = Yii::createObject($className, $args);
$object = call_user_func_array(['Yii', 'createObject'], $args);
} else { } else {
$object = new $className; $object = Yii::createObject($className);
} }
if (!empty($config)) { if (!empty($config)) {
foreach ($config as $name => $value) { foreach ($config as $name => $value) {
......
...@@ -10,6 +10,7 @@ use yii\base\InvalidConfigException; ...@@ -10,6 +10,7 @@ use yii\base\InvalidConfigException;
use yii\base\InvalidParamException; use yii\base\InvalidParamException;
use yii\base\UnknownClassException; use yii\base\UnknownClassException;
use yii\log\Logger; use yii\log\Logger;
use yii\di\Container;
/** /**
* Gets the application start timestamp. * Gets the application start timestamp.
...@@ -76,26 +77,13 @@ class BaseYii ...@@ -76,26 +77,13 @@ class BaseYii
*/ */
public static $aliases = ['@yii' => __DIR__]; public static $aliases = ['@yii' => __DIR__];
/** /**
* @var array initial property values that will be applied to objects newly created via [[createObject]]. * @var Container the dependency injection (DI) container used by [[createObject()]].
* The array keys are class names without leading backslashes "\", and the array values are the corresponding * You may use [[Container::set()]] to set up the needed dependencies of classes and
* name-value pairs for initializing the created class instances. For example, * their initial property values.
*
* ~~~
* [
* 'Bar' => [
* 'prop1' => 'value1',
* 'prop2' => 'value2',
* ],
* 'mycompany\foo\Car' => [
* 'prop1' => 'value1',
* 'prop2' => 'value2',
* ],
* ]
* ~~~
*
* @see createObject() * @see createObject()
* @see Container
*/ */
public static $objectConfig = []; public static $container;
/** /**
...@@ -304,74 +292,59 @@ class BaseYii ...@@ -304,74 +292,59 @@ class BaseYii
/** /**
* Creates a new object using the given configuration. * Creates a new object using the given configuration.
* *
* The configuration can be either a string or an array. * You may view this method as an enhanced version of the `new` operator.
* If a string, it is treated as the *object class*; if an array, * The method supports creating an object based on a class name, a configuration array or
* it must contain a `class` element specifying the *object class*, and * an anonymous function.
* the rest of the name-value pairs in the array will be used to initialize
* the corresponding object properties.
* *
* Below are some usage examples: * Below are some usage examples:
* *
* ~~~ * ```php
* $object = \Yii::createObject('app\components\GoogleMap'); * // create an object using a class name
* $object = \Yii::createObject([ * $object = Yii::createObject('yii\db\Connection');
* 'class' => 'app\components\GoogleMap', *
* 'apiKey' => 'xyz', * // create an object using a configuration array
* $object = Yii::createObject([
* 'class' => 'yii\db\Connection',
* 'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
* 'username' => 'root',
* 'password' => '',
* 'charset' => 'utf8',
* ]); * ]);
* ~~~
* *
* This method can be used to create any object as long as the object's constructor is * // create an object with two constructor parameters
* defined like the following: * $object = \Yii::createObject('MyClass', [$param1, $param2]);
* ```
* *
* ~~~ * Using [[\yii\di\Container|dependency injection container]], this method can also identify
* public function __construct(..., $config = []) { * dependent objects, instantiate them and inject them into the newly created object.
* } *
* ~~~ * @param string|array|callable $type the object type. This can be specified in one of the following forms:
* *
* The method will pass the given configuration as the last parameter of the constructor, * - a string: representing the class name of the object to be created
* and any additional parameters to this method will be passed as the rest of the constructor parameters. * - a configuration array: the array must contain a `class` element which is treated as the object class,
* and the rest of the name-value pairs will be used to initialize the corresponding object properties
* - a PHP callable: either an anonymous function or an array representing a class method (`[$class or $object, $method]`).
* The callable should return a new instance of the object being created.
* *
* @param string|array $config the configuration. It can be either a string representing the class name * @param array $params the constructor parameters
* or an array representing the object configuration. * @return object the created object
* @return mixed the created object
* @throws InvalidConfigException if the configuration is invalid. * @throws InvalidConfigException if the configuration is invalid.
* @see \yii\di\Container
*/ */
public static function createObject($config) public static function createObject($type, array $params = [])
{ {
static $reflections = []; if (is_string($type)) {
return static::$container->get($type, $params);
if (is_string($config)) { } elseif (is_array($type) && isset($type['class'])) {
$class = $config; $class = $type['class'];
$config = []; unset($type['class']);
} elseif (isset($config['class'])) { return static::$container->get($class, $params, $type);
$class = $config['class']; } elseif (is_callable($type, true)) {
unset($config['class']); return call_user_func($type, $params);
} else { } elseif (is_array($type)) {
throw new InvalidConfigException('Object configuration must be an array containing a "class" element.'); throw new InvalidConfigException('Object configuration must be an array containing a "class" element.');
}
$class = ltrim($class, '\\');
if (isset(static::$objectConfig[$class])) {
$config = array_merge(static::$objectConfig[$class], $config);
}
if (func_num_args() > 1) {
/** @var \ReflectionClass $reflection */
if (isset($reflections[$class])) {
$reflection = $reflections[$class];
} else {
$reflection = $reflections[$class] = new \ReflectionClass($class);
}
$args = func_get_args();
array_shift($args); // remove $config
if (!empty($config)) {
$args[] = $config;
}
return $reflection->newInstanceArgs($args);
} else { } else {
return empty($config) ? new $class : new $class($config); throw new InvalidConfigException("Unsupported configuration type: " . gettype($type));
} }
} }
......
...@@ -248,7 +248,11 @@ Yii Framework 2 Change Log ...@@ -248,7 +248,11 @@ Yii Framework 2 Change Log
- Chg: Added `View::viewFile` and removed `ViewEvent::viewFile` (qiangxue) - Chg: Added `View::viewFile` and removed `ViewEvent::viewFile` (qiangxue)
- Chg: Changed `Controller::afterAction()`, `Module::afterAction()` and `ActionFilter::afterAction()` to pass `$result` by value instead of reference (qiangxue) - Chg: Changed `Controller::afterAction()`, `Module::afterAction()` and `ActionFilter::afterAction()` to pass `$result` by value instead of reference (qiangxue)
- Chg: `yii\base\Extension::init()` is renamed to `bootstrap()` (qiangxue) - Chg: `yii\base\Extension::init()` is renamed to `bootstrap()` (qiangxue)
- Chg: `getComponent()` and `setComponent()` in `Application` and `Module` are renamed to `get()` and `set()` respectively. (qiangxue)
- Chg: The signature of `Yii::createObject()` is changed. Constructor parameters must be passed as the second parameter. (qiangxue)
- Chg: `Yii::$objectConfig` is removed. You should use `Yii::$container->set()` to configure default settings of classes. (qiangxue)
- New #66: [Auth client library](https://github.com/yiisoft/yii2-authclient) OpenId, OAuth1, OAuth2 clients (klimov-paul) - New #66: [Auth client library](https://github.com/yiisoft/yii2-authclient) OpenId, OAuth1, OAuth2 clients (klimov-paul)
- New #503: Added `yii\di\Container` and `yii\di\ServiceLocator` (qiangxue)
- New #706: Added `yii\widgets\Pjax` and enhanced `GridView` to work with `Pjax` to support AJAX-update (qiangxue) - New #706: Added `yii\widgets\Pjax` and enhanced `GridView` to work with `Pjax` to support AJAX-update (qiangxue)
- New #1393: [Codeception testing framework integration](https://github.com/yiisoft/yii2-codeception) (Ragazzo) - New #1393: [Codeception testing framework integration](https://github.com/yiisoft/yii2-codeception) (Ragazzo)
- New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) - New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul)
......
...@@ -24,3 +24,4 @@ class Yii extends \yii\BaseYii ...@@ -24,3 +24,4 @@ class Yii extends \yii\BaseYii
spl_autoload_register(['Yii', 'autoload'], true, true); spl_autoload_register(['Yii', 'autoload'], true, true);
Yii::$classMap = include(__DIR__ . '/classes.php'); Yii::$classMap = include(__DIR__ . '/classes.php');
Yii::$container = new yii\di\Container;
...@@ -160,7 +160,6 @@ abstract class Application extends Module ...@@ -160,7 +160,6 @@ abstract class Application extends Module
$this->preInit($config); $this->preInit($config);
$this->registerErrorHandlers(); $this->registerErrorHandlers();
$this->registerCoreComponents();
Component::__construct($config); Component::__construct($config);
} }
...@@ -206,6 +205,15 @@ abstract class Application extends Module ...@@ -206,6 +205,15 @@ abstract class Application extends Module
} elseif (!ini_get('date.timezone')) { } elseif (!ini_get('date.timezone')) {
$this->setTimeZone('UTC'); $this->setTimeZone('UTC');
} }
// merge core components with custom components
foreach ($this->coreComponents() as $id => $component) {
if (!isset($config['components'][$id])) {
$config['components'][$id] = $component;
} elseif (is_array($config['components'][$id]) && !isset($config['components'][$id]['class'])) {
$config['components'][$id]['class'] = $component['class'];
}
}
} }
/** /**
...@@ -248,7 +256,7 @@ abstract class Application extends Module ...@@ -248,7 +256,7 @@ abstract class Application extends Module
*/ */
public function preloadComponents() public function preloadComponents()
{ {
$this->getComponent('log'); $this->get('log');
parent::preloadComponents(); parent::preloadComponents();
} }
...@@ -400,7 +408,7 @@ abstract class Application extends Module ...@@ -400,7 +408,7 @@ abstract class Application extends Module
*/ */
public function getDb() public function getDb()
{ {
return $this->getComponent('db'); return $this->get('db');
} }
/** /**
...@@ -409,7 +417,7 @@ abstract class Application extends Module ...@@ -409,7 +417,7 @@ abstract class Application extends Module
*/ */
public function getLog() public function getLog()
{ {
return $this->getComponent('log'); return $this->get('log');
} }
/** /**
...@@ -418,7 +426,7 @@ abstract class Application extends Module ...@@ -418,7 +426,7 @@ abstract class Application extends Module
*/ */
public function getErrorHandler() public function getErrorHandler()
{ {
return $this->getComponent('errorHandler'); return $this->get('errorHandler');
} }
/** /**
...@@ -427,7 +435,7 @@ abstract class Application extends Module ...@@ -427,7 +435,7 @@ abstract class Application extends Module
*/ */
public function getCache() public function getCache()
{ {
return $this->getComponent('cache'); return $this->get('cache');
} }
/** /**
...@@ -436,7 +444,7 @@ abstract class Application extends Module ...@@ -436,7 +444,7 @@ abstract class Application extends Module
*/ */
public function getFormatter() public function getFormatter()
{ {
return $this->getComponent('formatter'); return $this->get('formatter');
} }
/** /**
...@@ -445,7 +453,7 @@ abstract class Application extends Module ...@@ -445,7 +453,7 @@ abstract class Application extends Module
*/ */
public function getRequest() public function getRequest()
{ {
return $this->getComponent('request'); return $this->get('request');
} }
/** /**
...@@ -454,7 +462,7 @@ abstract class Application extends Module ...@@ -454,7 +462,7 @@ abstract class Application extends Module
*/ */
public function getView() public function getView()
{ {
return $this->getComponent('view'); return $this->get('view');
} }
/** /**
...@@ -463,7 +471,7 @@ abstract class Application extends Module ...@@ -463,7 +471,7 @@ abstract class Application extends Module
*/ */
public function getUrlManager() public function getUrlManager()
{ {
return $this->getComponent('urlManager'); return $this->get('urlManager');
} }
/** /**
...@@ -472,7 +480,7 @@ abstract class Application extends Module ...@@ -472,7 +480,7 @@ abstract class Application extends Module
*/ */
public function getI18n() public function getI18n()
{ {
return $this->getComponent('i18n'); return $this->get('i18n');
} }
/** /**
...@@ -481,7 +489,7 @@ abstract class Application extends Module ...@@ -481,7 +489,7 @@ abstract class Application extends Module
*/ */
public function getMail() public function getMail()
{ {
return $this->getComponent('mail'); return $this->get('mail');
} }
/** /**
...@@ -490,16 +498,16 @@ abstract class Application extends Module ...@@ -490,16 +498,16 @@ abstract class Application extends Module
*/ */
public function getAuthManager() public function getAuthManager()
{ {
return $this->getComponent('authManager'); return $this->get('authManager');
} }
/** /**
* Registers the core application components. * Returns the core application components.
* @see setComponents * @see set
*/ */
public function registerCoreComponents() public function coreComponents()
{ {
$this->setComponents([ return [
'log' => ['class' => 'yii\log\Logger'], 'log' => ['class' => 'yii\log\Logger'],
'errorHandler' => ['class' => 'yii\base\ErrorHandler'], 'errorHandler' => ['class' => 'yii\base\ErrorHandler'],
'formatter' => ['class' => 'yii\base\Formatter'], 'formatter' => ['class' => 'yii\base\Formatter'],
...@@ -507,7 +515,7 @@ abstract class Application extends Module ...@@ -507,7 +515,7 @@ abstract class Application extends Module
'mail' => ['class' => 'yii\swiftmailer\Mailer'], 'mail' => ['class' => 'yii\swiftmailer\Mailer'],
'urlManager' => ['class' => 'yii\web\UrlManager'], 'urlManager' => ['class' => 'yii\web\UrlManager'],
'view' => ['class' => 'yii\web\View'], 'view' => ['class' => 'yii\web\View'],
]); ];
} }
/** /**
......
...@@ -192,7 +192,7 @@ class Controller extends Component implements ViewContextInterface ...@@ -192,7 +192,7 @@ class Controller extends Component implements ViewContextInterface
$actionMap = $this->actions(); $actionMap = $this->actions();
if (isset($actionMap[$id])) { if (isset($actionMap[$id])) {
return Yii::createObject($actionMap[$id], $id, $this); return Yii::createObject($actionMap[$id], [$id, $this]);
} elseif (preg_match('/^[a-z0-9\\-_]+$/', $id) && strpos($id, '--') === false && trim($id, '-') === $id) { } elseif (preg_match('/^[a-z0-9\\-_]+$/', $id) && strpos($id, '--') === false && trim($id, '-') === $id) {
$methodName = 'action' . str_replace(' ', '', ucwords(implode(' ', explode('-', $id)))); $methodName = 'action' . str_replace(' ', '', ucwords(implode(' ', explode('-', $id))));
if (method_exists($this, $methodName)) { if (method_exists($this, $methodName)) {
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace yii\base; namespace yii\base;
use Yii; use Yii;
use yii\di\ServiceLocator;
/** /**
* Module is the base class for module and application classes. * Module is the base class for module and application classes.
...@@ -35,7 +36,7 @@ use Yii; ...@@ -35,7 +36,7 @@ use Yii;
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class Module extends Component class Module extends ServiceLocator
{ {
/** /**
* @var array custom module parameters (name => value). * @var array custom module parameters (name => value).
...@@ -110,10 +111,7 @@ class Module extends Component ...@@ -110,10 +111,7 @@ class Module extends Component
* @var array child modules of this module * @var array child modules of this module
*/ */
private $_modules = []; private $_modules = [];
/**
* @var array components registered under this module
*/
private $_components = [];
/** /**
* Constructor. * Constructor.
...@@ -129,38 +127,6 @@ class Module extends Component ...@@ -129,38 +127,6 @@ class Module extends Component
} }
/** /**
* Getter magic method.
* This method is overridden to support accessing components
* like reading module properties.
* @param string $name component or property name
* @return mixed the named property value
*/
public function __get($name)
{
if ($this->hasComponent($name)) {
return $this->getComponent($name);
} else {
return parent::__get($name);
}
}
/**
* Checks if a property value is null.
* This method overrides the parent implementation by checking
* if the named component is loaded.
* @param string $name the property name or the event name
* @return boolean whether the property value is null
*/
public function __isset($name)
{
if ($this->hasComponent($name)) {
return $this->getComponent($name) !== null;
} else {
return parent::__isset($name);
}
}
/**
* Initializes the module. * Initializes the module.
* This method is called after the module is created and initialized with property values * This method is called after the module is created and initialized with property values
* given in configuration. The default implementation will call [[preloadComponents()]] to * given in configuration. The default implementation will call [[preloadComponents()]] to
...@@ -350,7 +316,7 @@ class Module extends Component ...@@ -350,7 +316,7 @@ class Module extends Component
$this->_modules[$id]['class'] = 'yii\base\Module'; $this->_modules[$id]['class'] = 'yii\base\Module';
} }
return $this->_modules[$id] = Yii::createObject($this->_modules[$id], $id, $this); return $this->_modules[$id] = Yii::createObject($this->_modules[$id], [$id, $this]);
} }
} }
...@@ -432,126 +398,14 @@ class Module extends Component ...@@ -432,126 +398,14 @@ class Module extends Component
} }
/** /**
* Checks whether the named component exists.
* @param string $id component ID
* @return boolean whether the named component exists. Both loaded and unloaded components
* are considered.
*/
public function hasComponent($id)
{
return isset($this->_components[$id]);
}
/**
* Retrieves the named component.
* @param string $id component ID (case-sensitive)
* @param boolean $load whether to load the component if it is not yet loaded.
* @return Component|null the component instance, null if the component does not exist.
* @see hasComponent()
*/
public function getComponent($id, $load = true)
{
if (isset($this->_components[$id])) {
if ($this->_components[$id] instanceof Object) {
return $this->_components[$id];
} elseif ($load) {
return $this->_components[$id] = Yii::createObject($this->_components[$id]);
}
}
return null;
}
/**
* Registers a component with this module.
* @param string $id component ID
* @param Component|array|null $component the component to be registered with the module. This can
* be one of the followings:
*
* - a [[Component]] object
* - a configuration array: when [[getComponent()]] is called initially for this component, the array
* will be used to instantiate the component via [[Yii::createObject()]].
* - null: the named component will be removed from the module
*/
public function setComponent($id, $component)
{
if ($component === null) {
unset($this->_components[$id]);
} else {
$this->_components[$id] = $component;
}
}
/**
* Returns the registered components.
* @param boolean $loadedOnly whether to return the loaded components only. If this is set false,
* then all components specified in the configuration will be returned, whether they are loaded or not.
* Loaded components will be returned as objects, while unloaded components as configuration arrays.
* @return array the components (indexed by their IDs)
*/
public function getComponents($loadedOnly = false)
{
if ($loadedOnly) {
$components = [];
foreach ($this->_components as $component) {
if ($component instanceof Component) {
$components[] = $component;
}
}
return $components;
} else {
return $this->_components;
}
}
/**
* Registers a set of components in this module.
*
* Each component should be specified as a name-value pair, where
* name refers to the ID of the component and value the component or a configuration
* array that can be used to create the component. In the latter case, [[Yii::createObject()]]
* will be used to create the component.
*
* If a new component has the same ID as an existing one, the existing one will be overwritten silently.
*
* The following is an example for setting two components:
*
* ~~~
* [
* 'db' => [
* 'class' => 'yii\db\Connection',
* 'dsn' => 'sqlite:path/to/file.db',
* ],
* 'cache' => [
* 'class' => 'yii\caching\DbCache',
* 'db' => 'db',
* ],
* ]
* ~~~
*
* @param array $components components (id => component configuration or instance)
*/
public function setComponents($components)
{
foreach ($components as $id => $component) {
if (!is_object($component) && isset($this->_components[$id]['class']) && !isset($component['class'])) {
// set default component class
$component['class'] = $this->_components[$id]['class'];
}
$this->_components[$id] = $component;
}
}
/**
* Loads components that are declared in [[preload]]. * Loads components that are declared in [[preload]].
* @throws InvalidConfigException if a component or module to be preloaded is unknown * @throws InvalidConfigException if a component or module to be preloaded is unknown
*/ */
public function preloadComponents() public function preloadComponents()
{ {
foreach ($this->preload as $id) { foreach ($this->preload as $id) {
if ($this->hasComponent($id)) { if ($this->has($id)) {
$this->getComponent($id); $this->get($id);
} elseif ($this->hasModule($id)) { } elseif ($this->hasModule($id)) {
$this->getModule($id); $this->getModule($id);
} else { } else {
...@@ -635,7 +489,7 @@ class Module extends Component ...@@ -635,7 +489,7 @@ class Module extends Component
return $module->createController($route); return $module->createController($route);
} }
if (isset($this->controllerMap[$id])) { if (isset($this->controllerMap[$id])) {
$controller = Yii::createObject($this->controllerMap[$id], $id, $this); $controller = Yii::createObject($this->controllerMap[$id], [$id, $this]);
return [$controller, $route]; return [$controller, $route];
} }
......
...@@ -11,6 +11,7 @@ use Yii; ...@@ -11,6 +11,7 @@ use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\db\Connection; use yii\db\Connection;
use yii\db\Query; use yii\db\Query;
use yii\di\Instance;
/** /**
* DbCache implements a cache application component by storing cached data in a database. * DbCache implements a cache application component by storing cached data in a database.
...@@ -79,12 +80,7 @@ class DbCache extends Cache ...@@ -79,12 +80,7 @@ class DbCache extends Cache
public function init() public function init()
{ {
parent::init(); parent::init();
if (is_string($this->db)) { $this->db = Instance::ensure($this->db, Connection::className());
$this->db = Yii::$app->getComponent($this->db);
}
if (!$this->db instanceof Connection) {
throw new InvalidConfigException("DbCache::db must be either a DB connection instance or the application component ID of a DB connection.");
}
} }
/** /**
......
...@@ -10,6 +10,7 @@ namespace yii\caching; ...@@ -10,6 +10,7 @@ namespace yii\caching;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\db\Connection; use yii\db\Connection;
use yii\di\Instance;
/** /**
* DbDependency represents a dependency based on the query result of a SQL statement. * DbDependency represents a dependency based on the query result of a SQL statement.
...@@ -45,10 +46,7 @@ class DbDependency extends Dependency ...@@ -45,10 +46,7 @@ class DbDependency extends Dependency
*/ */
protected function generateDependencyData($cache) protected function generateDependencyData($cache)
{ {
$db = Yii::$app->getComponent($this->db); $db = Instance::ensure($this->db, Connection::className());
if (!$db instanceof Connection) {
throw new InvalidConfigException("DbDependency::db must be the application component ID of a DB connection.");
}
if ($this->sql === null) { if ($this->sql === null) {
throw new InvalidConfigException("DbDependency::sql must be set."); throw new InvalidConfigException("DbDependency::sql must be set.");
} }
......
...@@ -154,7 +154,7 @@ class Application extends \yii\base\Application ...@@ -154,7 +154,7 @@ class Application extends \yii\base\Application
*/ */
public function getResponse() public function getResponse()
{ {
return $this->getComponent('response'); return $this->get('response');
} }
/** /**
...@@ -193,15 +193,13 @@ class Application extends \yii\base\Application ...@@ -193,15 +193,13 @@ class Application extends \yii\base\Application
} }
/** /**
* Registers the core application components. * @inheritdoc
* @see setComponents
*/ */
public function registerCoreComponents() public function coreComponents()
{ {
parent::registerCoreComponents(); return array_merge([
$this->setComponents([
'request' => ['class' => 'yii\console\Request'], 'request' => ['class' => 'yii\console\Request'],
'response' => ['class' => 'yii\console\Response'], 'response' => ['class' => 'yii\console\Response'],
]); ], parent::coreComponents());
} }
} }
...@@ -53,7 +53,7 @@ class CacheController extends Controller ...@@ -53,7 +53,7 @@ class CacheController extends Controller
public function actionFlush($component = 'cache') public function actionFlush($component = 'cache')
{ {
/** @var Cache $cache */ /** @var Cache $cache */
$cache = Yii::$app->getComponent($component); $cache = Yii::$app->get($component, false);
if (!$cache || !$cache instanceof Cache) { if (!$cache || !$cache instanceof Cache) {
throw new Exception('Application component "'.$component.'" is not defined or not a cache.'); throw new Exception('Application component "'.$component.'" is not defined or not a cache.');
} }
......
...@@ -129,7 +129,7 @@ class MessageController extends Controller ...@@ -129,7 +129,7 @@ class MessageController extends Controller
} }
} }
} elseif ($config['format'] === 'db') { } elseif ($config['format'] === 'db') {
$db = \Yii::$app->getComponent(isset($config['db']) ? $config['db'] : 'db'); $db = \Yii::$app->get(isset($config['db']) ? $config['db'] : 'db');
if (!$db instanceof \yii\db\Connection) { if (!$db instanceof \yii\db\Connection) {
throw new Exception('The "db" option must refer to a valid database application component.'); throw new Exception('The "db" option must refer to a valid database application component.');
} }
......
...@@ -122,7 +122,7 @@ class MigrateController extends Controller ...@@ -122,7 +122,7 @@ class MigrateController extends Controller
if ($action->id !== 'create') { if ($action->id !== 'create') {
if (is_string($this->db)) { if (is_string($this->db)) {
$this->db = Yii::$app->getComponent($this->db); $this->db = Yii::$app->get($this->db);
} }
if (!$this->db instanceof Connection) { if (!$this->db instanceof Connection) {
throw new Exception("The 'db' option must refer to the application component ID of a DB connection."); throw new Exception("The 'db' option must refer to the application component ID of a DB connection.");
......
...@@ -13,6 +13,7 @@ use yii\base\InvalidConfigException; ...@@ -13,6 +13,7 @@ use yii\base\InvalidConfigException;
use yii\base\Model; use yii\base\Model;
use yii\db\Connection; use yii\db\Connection;
use yii\db\QueryInterface; use yii\db\QueryInterface;
use yii\di\Instance;
/** /**
* ActiveDataProvider implements a data provider based on [[\yii\db\Query]] and [[\yii\db\ActiveQuery]]. * ActiveDataProvider implements a data provider based on [[\yii\db\Query]] and [[\yii\db\ActiveQuery]].
...@@ -85,10 +86,7 @@ class ActiveDataProvider extends BaseDataProvider ...@@ -85,10 +86,7 @@ class ActiveDataProvider extends BaseDataProvider
{ {
parent::init(); parent::init();
if (is_string($this->db)) { if (is_string($this->db)) {
$this->db = Yii::$app->getComponent($this->db); $this->db = Instance::ensure($this->db, Connection::className());
if ($this->db === null) {
throw new InvalidConfigException('The "db" property must be a valid DB Connection application component.');
}
} }
} }
......
...@@ -10,6 +10,7 @@ namespace yii\data; ...@@ -10,6 +10,7 @@ namespace yii\data;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\db\Connection; use yii\db\Connection;
use yii\di\Instance;
/** /**
* SqlDataProvider implements a data provider based on a plain SQL statement. * SqlDataProvider implements a data provider based on a plain SQL statement.
...@@ -89,12 +90,7 @@ class SqlDataProvider extends BaseDataProvider ...@@ -89,12 +90,7 @@ class SqlDataProvider extends BaseDataProvider
public function init() public function init()
{ {
parent::init(); parent::init();
if (is_string($this->db)) { $this->db = Instance::ensure($this->db, Connection::className());
$this->db = Yii::$app->getComponent($this->db);
}
if (!$this->db instanceof Connection) {
throw new InvalidConfigException('The "db" property must be a valid DB Connection application component.');
}
if ($this->sql === null) { if ($this->sql === null) {
throw new InvalidConfigException('The "sql" property must be set.'); throw new InvalidConfigException('The "sql" property must be set.');
} }
......
...@@ -378,7 +378,7 @@ class Command extends \yii\base\Component ...@@ -378,7 +378,7 @@ class Command extends \yii\base\Component
/** @var \yii\caching\Cache $cache */ /** @var \yii\caching\Cache $cache */
if ($db->enableQueryCache && $method !== '') { if ($db->enableQueryCache && $method !== '') {
$cache = is_string($db->queryCache) ? Yii::$app->getComponent($db->queryCache) : $db->queryCache; $cache = is_string($db->queryCache) ? Yii::$app->get($db->queryCache, false) : $db->queryCache;
} }
if (isset($cache) && $cache instanceof Cache) { if (isset($cache) && $cache instanceof Cache) {
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
namespace yii\db; namespace yii\db;
use yii\di\Instance;
/** /**
* Migration is the base class for representing a database migration. * Migration is the base class for representing a database migration.
...@@ -36,10 +37,10 @@ namespace yii\db; ...@@ -36,10 +37,10 @@ namespace yii\db;
class Migration extends \yii\base\Component class Migration extends \yii\base\Component
{ {
/** /**
* @var Connection the database connection that this migration should work with. * @var Connection|string the DB connection object or the application component ID of the DB connection
* If not set, it will be initialized as the 'db' application component. * that this migration should work with.
*/ */
public $db; public $db = 'db';
/** /**
* Initializes the migration. * Initializes the migration.
...@@ -48,9 +49,7 @@ class Migration extends \yii\base\Component ...@@ -48,9 +49,7 @@ class Migration extends \yii\base\Component
public function init() public function init()
{ {
parent::init(); parent::init();
if ($this->db === null) { $this->db = Instance::ensure($this->db, Connection::className());
$this->db = \Yii::$app->getComponent('db');
}
} }
/** /**
......
...@@ -96,7 +96,7 @@ abstract class Schema extends Object ...@@ -96,7 +96,7 @@ abstract class Schema extends Object
if ($db->enableSchemaCache && !in_array($name, $db->schemaCacheExclude, true)) { if ($db->enableSchemaCache && !in_array($name, $db->schemaCacheExclude, true)) {
/** @var Cache $cache */ /** @var Cache $cache */
$cache = is_string($db->schemaCache) ? Yii::$app->getComponent($db->schemaCache) : $db->schemaCache; $cache = is_string($db->schemaCache) ? Yii::$app->get($db->schemaCache, false) : $db->schemaCache;
if ($cache instanceof Cache) { if ($cache instanceof Cache) {
$key = $this->getCacheKey($name); $key = $this->getCacheKey($name);
if ($refresh || ($table = $cache->get($key)) === false) { if ($refresh || ($table = $cache->get($key)) === false) {
...@@ -225,7 +225,7 @@ abstract class Schema extends Object ...@@ -225,7 +225,7 @@ abstract class Schema extends Object
public function refresh() public function refresh()
{ {
/** @var Cache $cache */ /** @var Cache $cache */
$cache = is_string($this->db->schemaCache) ? Yii::$app->getComponent($this->db->schemaCache) : $this->db->schemaCache; $cache = is_string($this->db->schemaCache) ? Yii::$app->get($this->db->schemaCache, false) : $this->db->schemaCache;
if ($this->db->enableSchemaCache && $cache instanceof Cache) { if ($this->db->enableSchemaCache && $cache instanceof Cache) {
GroupDependency::invalidate($cache, $this->getCacheGroup()); GroupDependency::invalidate($cache, $this->getCacheGroup());
} }
......
<?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 represents a reference to a named object in a dependency injection (DI) container or a service locator.
*
* You may use [[get()]] to obtain the actual object referenced by [[id]].
*
* Instance is mainly used in two places:
*
* - When configuring a dependency injection container, you use Instance to reference a class name, interface name
* or alias name. The reference can later be resolved into the actual object by the container.
* - In classes which use service locator to obtain dependent objects.
*
* The following example shows how to configure a DI container with Instance:
*
* ```php
* $container = new \yii\di\Container;
* $container->set('cache', 'yii\caching\DbCache', Instance::of('db'));
* $container->set('db', [
* 'class' => 'yii\db\Connection',
* 'dsn' => 'sqlite:path/to/file.db',
* ]);
* ```
*
* And the following example shows how a class retrieves a component from a service locator:
*
* ```php
* class DbCache extends Cache
* {
* public $db = 'db';
*
* public function init()
* {
* parent::init();
* $this->db = Instance::ensure($this->db, 'yii\db\Connection');
* }
* }
* ```
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Instance
{
/**
* @var string the component ID, class name, interface name or alias name
*/
public $id;
/**
* Constructor.
* @param string $id the component ID
*/
protected function __construct($id)
{
$this->id = $id;
}
/**
* Creates a new Instance object.
* @param string $id the component ID
* @return Instance the new Instance object.
*/
public static function of($id)
{
return new static($id);
}
/**
* Resolves the specified reference into the actual object and makes sure it is of the specified type.
*
* The reference may be specified as a string or an Instance object. If the former,
* it will be treated as a component ID, a class/interface name or an alias, depending on the container type.
*
* If you do not specify a container, the method will first try `Yii::$app` followed by `Yii::$container`.
*
* 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 $reference 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/interface name to be checked. If null, type check will not be performed.
* @param ServiceLocator|Container $container the container. This will be passed to [[get()]].
* @return object the object referenced by the Instance, or `$reference` itself if it is an object.
* @throws InvalidConfigException if the reference is invalid
*/
public static function ensure($reference, $type = null, $container = null)
{
if ($reference instanceof $type) {
return $reference;
} elseif (empty($reference)) {
throw new InvalidConfigException('The required component is not specified.');
}
if (is_string($reference)) {
$reference = new static($reference);
}
if ($reference instanceof self) {
$component = $reference->get($container);
if ($component instanceof $type || $type === null) {
return $component;
} else {
throw new InvalidConfigException('"' . $reference->id . '" refers to a ' . get_class($component) . " component. $type is expected.");
}
}
$valueType = is_object($reference) ? get_class($reference) : gettype($reference);
throw new InvalidConfigException("Invalid data type: $valueType. $type is expected.");
}
/**
* Returns the actual object referenced by this Instance object.
* @param ServiceLocator|Container $container the container used to locate the referenced object.
* If null, the method will first try `Yii::$app` then `Yii::$container`.
* @return object the actual object referenced by this Instance object.
*/
public function get($container = null)
{
if ($container) {
return $container->get($this->id);
}
if (Yii::$app && Yii::$app->has($this->id)) {
return Yii::$app->get($this->id);
} else {
return Yii::$container->get($this->id);
}
}
}
<?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 Closure;
use yii\base\Component;
use yii\base\InvalidConfigException;
/**
* ServiceLocator implements a [service locator](http://en.wikipedia.org/wiki/Service_locator_pattern).
*
* To use ServiceLocator, you first need to register component IDs with the corresponding component
* definitions with the locator by calling [[set()]] or [[setComponents()]].
* You can then call [[get()]] to retrieve a component with the specified ID. The locator will automatically
* instantiate and configure the component according to the definition.
*
* For example,
*
* ```php
* $locator = new \yii\di\ServiceLocator;
* $locator->setComponents([
* 'db' => [
* 'class' => 'yii\db\Connection',
* 'dsn' => 'sqlite:path/to/file.db',
* ],
* 'cache' => [
* 'class' => 'yii\caching\DbCache',
* 'db' => 'db',
* ],
* ]);
*
* $db = $locator->get('db'); // or $locator->db
* $cache = $locator->get('cache'); // or $locator->cache
* ```
*
* Because [[\yii\base\Module]] extends from ServiceLocator, modules and the application are all service locators.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ServiceLocator extends Component
{
/**
* @var array shared component instances indexed by their IDs
*/
private $_components = [];
/**
* @var array component definitions indexed by their IDs
*/
private $_definitions = [];
/**
* Getter magic method.
* This method is overridden to support accessing components like reading properties.
* @param string $name component or property name
* @return mixed the named property value
*/
public function __get($name)
{
if ($this->has($name)) {
return $this->get($name);
} else {
return parent::__get($name);
}
}
/**
* Checks if a property value is null.
* This method overrides the parent implementation by checking if the named component is loaded.
* @param string $name the property name or the event name
* @return boolean whether the property value is null
*/
public function __isset($name)
{
if ($this->has($name, true)) {
return true;
} else {
return parent::__isset($name);
}
}
/**
* Returns a value indicating whether the locator has the specified component definition or has instantiated the component.
* This method may return different results depending on the value of `$checkInstance`.
*
* - If `$checkInstance` is false (default), the method will return a value indicating whether the locator has the specified
* component definition.
* - If `$checkInstance` is true, the method will return a value indicating whether the locator has
* instantiated the specified component.
*
* @param string $id component ID (e.g. `db`).
* @param boolean $checkInstance whether the method should check if the component is shared and instantiated.
* @return boolean whether the locator has the specified component definition or has instantiated the component.
* @see set()
*/
public function has($id, $checkInstance = false)
{
return $checkInstance ? isset($this->_components[$id]) : isset($this->_definitions[$id]);
}
/**
* Returns the component instance with the specified ID.
*
* @param string $id component ID (e.g. `db`).
* @param boolean $throwException whether to throw an exception if `$id` is not registered with the locator before.
* @return object|null the component of the specified ID. If `$throwException` is false and `$id`
* is not registered before, null will be returned.
* @throws InvalidConfigException if `$id` refers to a nonexistent component ID
* @see has()
* @see set()
*/
public function get($id, $throwException = true)
{
if (isset($this->_components[$id])) {
return $this->_components[$id];
}
if (isset($this->_definitions[$id])) {
$definition = $this->_definitions[$id];
if (is_object($definition) && !$definition instanceof Closure) {
return $this->_components[$id] = $definition;
} else {
return $this->_components[$id] = Yii::createObject($definition);
}
} elseif ($throwException) {
throw new InvalidConfigException("Unknown component ID: $id");
} else {
return null;
}
}
/**
* Registers a component definition with this locator.
*
* For example,
*
* ```php
* // a class name
* $locator->set('cache', 'yii\caching\FileCache');
*
* // a configuration array
* $locator->set('db', [
* 'class' => 'yii\db\Connection',
* 'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
* 'username' => 'root',
* 'password' => '',
* 'charset' => 'utf8',
* ]);
*
* // an anonymous function
* $locator->set('cache', function ($params) {
* return new \yii\caching\FileCache;
* });
*
* // an instance
* $locator->set('cache', new \yii\caching\FileCache);
* ```
*
* If a component definition with the same ID already exists, it will be overwritten.
*
* @param string $id component ID (e.g. `db`).
* @param mixed $definition the component definition to be registered with this locator.
* It can be one of the followings:
*
* - a class name
* - a configuration array: the array contains name-value pairs that will be used to
* initialize the property values of the newly created object when [[get()]] is called.
* The `class` element is required and stands for the the class of the object to be created.
* - a PHP callable: either an anonymous function or an array representing a class method (e.g. `['Foo', 'bar']`).
* The callable will be called by [[get()]] to return an object associated with the specified component ID.
* - an object: When [[get()]] is called, this object will be returned.
*
* @throws InvalidConfigException if the definition is an invalid configuration array
*/
public function set($id, $definition)
{
if ($definition === null) {
unset($this->_components[$id], $this->_definitions[$id]);
return;
}
if (is_object($definition) || is_callable($definition, true)) {
// an object, a class name, or a PHP callable
$this->_definitions[$id] = $definition;
} elseif (is_array($definition)) {
// a configuration array
if (isset($definition['class'])) {
$this->_definitions[$id] = $definition;
} else {
throw new InvalidConfigException("The configuration for the \"$id\" component must contain a \"class\" element.");
}
} else {
throw new InvalidConfigException("Unexpected configuration type for the \"$id\" component: " . gettype($definition));
}
}
/**
* Removes the component from the locator.
* @param string $id the component ID
*/
public function clear($id)
{
unset($this->_definitions[$id], $this->_components[$id]);
}
/**
* Returns the list of the component definitions or the loaded component instances.
* @param boolean $returnDefinitions whether to return component definitions instead of the loaded component instances.
* @return array the list of the component definitions or the loaded component instances (ID => definition or instance).
*/
public function getComponents($returnDefinitions = true)
{
return $returnDefinitions ? $this->_definitions : $this->_components;
}
/**
* Registers a set of component definitions in this locator.
*
* This is the bulk version of [[set()]]. The parameter should be an array
* whose keys are component IDs and values the corresponding component definitions.
*
* For more details on how to specify component IDs and definitions, please refer to [[set()]].
*
* If a component definition with the same ID already exists, it will be overwritten.
*
* The following is an example for registering two component definitions:
*
* ```php
* [
* 'db' => [
* 'class' => 'yii\db\Connection',
* 'dsn' => 'sqlite:path/to/file.db',
* ],
* 'cache' => [
* 'class' => 'yii\caching\DbCache',
* 'db' => 'db',
* ],
* ]
* ```
*
* @param array $components component definitions or instances
*/
public function setComponents($components)
{
foreach ($components as $id => $component) {
$this->set($id, $component);
}
}
}
...@@ -9,6 +9,7 @@ namespace yii\i18n; ...@@ -9,6 +9,7 @@ namespace yii\i18n;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\di\Instance;
use yii\helpers\ArrayHelper; use yii\helpers\ArrayHelper;
use yii\caching\Cache; use yii\caching\Cache;
use yii\db\Connection; use yii\db\Connection;
...@@ -93,19 +94,9 @@ class DbMessageSource extends MessageSource ...@@ -93,19 +94,9 @@ class DbMessageSource extends MessageSource
public function init() public function init()
{ {
parent::init(); parent::init();
if (is_string($this->db)) { $this->db = Instance::ensure($this->db, Connection::className());
$this->db = Yii::$app->getComponent($this->db);
}
if (!$this->db instanceof Connection) {
throw new InvalidConfigException("DbMessageSource::db must be either a DB connection instance or the application component ID of a DB connection.");
}
if ($this->enableCaching) { if ($this->enableCaching) {
if (is_string($this->cache)) { $this->cache = Instance::ensure($this->cache, Cache::className());
$this->cache = Yii::$app->getComponent($this->cache);
}
if (!$this->cache instanceof Cache) {
throw new InvalidConfigException("DbMessageSource::cache must be either a cache object or the application component ID of the cache object.");
}
} }
} }
......
...@@ -10,6 +10,7 @@ namespace yii\log; ...@@ -10,6 +10,7 @@ namespace yii\log;
use Yii; use Yii;
use yii\db\Connection; use yii\db\Connection;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\di\Instance;
/** /**
* DbTarget stores log messages in a database table. * DbTarget stores log messages in a database table.
...@@ -62,12 +63,7 @@ class DbTarget extends Target ...@@ -62,12 +63,7 @@ class DbTarget extends Target
public function init() public function init()
{ {
parent::init(); parent::init();
if (is_string($this->db)) { $this->db = Instance::ensure($this->db, Connection::className());
$this->db = Yii::$app->getComponent($this->db);
}
if (!$this->db instanceof Connection) {
throw new InvalidConfigException("DbTarget::db must be either a DB connection instance or the application component ID of a DB connection.");
}
} }
/** /**
......
...@@ -9,6 +9,7 @@ namespace yii\log; ...@@ -9,6 +9,7 @@ namespace yii\log;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\di\Instance;
use yii\mail\MailerInterface; use yii\mail\MailerInterface;
/** /**
...@@ -43,12 +44,7 @@ class EmailTarget extends Target ...@@ -43,12 +44,7 @@ class EmailTarget extends Target
if (empty($this->message['to'])) { if (empty($this->message['to'])) {
throw new InvalidConfigException('The "to" option must be set for EmailTarget::message.'); throw new InvalidConfigException('The "to" option must be set for EmailTarget::message.');
} }
if (is_string($this->mail)) { $this->mail = Instance::ensure($this->mail, 'yii\mail\MailerInterface');
$this->mail = Yii::$app->getComponent($this->mail);
}
if (!$this->mail instanceof MailerInterface) {
throw new InvalidConfigException("EmailTarget::mailer must be either a mailer object or the application component ID of a mailer object.");
}
} }
/** /**
......
...@@ -247,10 +247,10 @@ abstract class Target extends Component ...@@ -247,10 +247,10 @@ abstract class Target extends Component
$request = Yii::$app->getRequest(); $request = Yii::$app->getRequest();
$ip = $request instanceof Request ? $request->getUserIP() : '-'; $ip = $request instanceof Request ? $request->getUserIP() : '-';
/** @var \yii\web\User $user */ /** @var \yii\web\User $user */
$user = Yii::$app->getComponent('user', false); $user = Yii::$app->has('user', true) ? Yii::$app->get('user') : null;
$userID = $user ? $user->getId(false) : '-'; $userID = $user ? $user->getId(false) : '-';
/** @var \yii\web\Session $session */ /** @var \yii\web\Session $session */
$session = Yii::$app->getComponent('session', false); $session = Yii::$app->has('session', true) ? Yii::$app->get('session') : null;
$sessionID = $session && $session->getIsActive() ? $session->getId() : '-'; $sessionID = $session && $session->getIsActive() ? $session->getId() : '-';
return "[$ip] [$userID] [$sessionID]"; return "[$ip] [$userID] [$sessionID]";
} }
......
...@@ -10,6 +10,7 @@ namespace yii\mutex; ...@@ -10,6 +10,7 @@ namespace yii\mutex;
use Yii; use Yii;
use yii\db\Connection; use yii\db\Connection;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\di\Instance;
/** /**
* @author resurtm <resurtm@gmail.com> * @author resurtm <resurtm@gmail.com>
...@@ -31,11 +32,6 @@ abstract class DbMutex extends Mutex ...@@ -31,11 +32,6 @@ abstract class DbMutex extends Mutex
public function init() public function init()
{ {
parent::init(); parent::init();
if (is_string($this->db)) { $this->db = Instance::ensure($this->db, Connection::className());
$this->db = Yii::$app->getComponent($this->db);
}
if (!$this->db instanceof Connection) {
throw new InvalidConfigException('Mutex::db must be either a DB connection instance or the application component ID of a DB connection.');
}
} }
} }
...@@ -15,6 +15,7 @@ use yii\base\Exception; ...@@ -15,6 +15,7 @@ use yii\base\Exception;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\base\InvalidCallException; use yii\base\InvalidCallException;
use yii\base\InvalidParamException; use yii\base\InvalidParamException;
use yii\di\Instance;
/** /**
* DbManager represents an authorization manager that stores authorization information in database. * DbManager represents an authorization manager that stores authorization information in database.
...@@ -59,14 +60,9 @@ class DbManager extends Manager ...@@ -59,14 +60,9 @@ class DbManager extends Manager
*/ */
public function init() public function init()
{ {
if (is_string($this->db)) {
$this->db = Yii::$app->getComponent($this->db);
}
if (!$this->db instanceof Connection) {
throw new InvalidConfigException("DbManager::db must be either a DB connection instance or the application component ID of a DB connection.");
}
$this->_usingSqlite = !strncmp($this->db->getDriverName(), 'sqlite', 6);
parent::init(); parent::init();
$this->db = Instance::ensure($this->db, Connection::className());
$this->_usingSqlite = !strncmp($this->db->getDriverName(), 'sqlite', 6);
} }
/** /**
......
...@@ -10,6 +10,8 @@ namespace yii\test; ...@@ -10,6 +10,8 @@ namespace yii\test;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\db\Connection; use yii\db\Connection;
use yii\di\Instance;
use yii\base\Object;
/** /**
* DbFixture is the base class for DB-related fixtures. * DbFixture is the base class for DB-related fixtures.
...@@ -34,11 +36,6 @@ abstract class DbFixture extends Fixture ...@@ -34,11 +36,6 @@ abstract class DbFixture extends Fixture
public function init() public function init()
{ {
parent::init(); parent::init();
if (is_string($this->db)) { $this->db = Instance::ensure($this->db, Object::className());
$this->db = Yii::$app->getComponent($this->db);
}
if (!is_object($this->db)) {
throw new InvalidConfigException("The 'db' property must be either a DB connection instance or the application component ID of a DB connection.");
}
} }
} }
...@@ -129,7 +129,7 @@ class Application extends \yii\base\Application ...@@ -129,7 +129,7 @@ class Application extends \yii\base\Application
*/ */
public function getRequest() public function getRequest()
{ {
return $this->getComponent('request'); return $this->get('request');
} }
/** /**
...@@ -138,7 +138,7 @@ class Application extends \yii\base\Application ...@@ -138,7 +138,7 @@ class Application extends \yii\base\Application
*/ */
public function getResponse() public function getResponse()
{ {
return $this->getComponent('response'); return $this->get('response');
} }
/** /**
...@@ -147,7 +147,7 @@ class Application extends \yii\base\Application ...@@ -147,7 +147,7 @@ class Application extends \yii\base\Application
*/ */
public function getSession() public function getSession()
{ {
return $this->getComponent('session'); return $this->get('session');
} }
/** /**
...@@ -156,7 +156,7 @@ class Application extends \yii\base\Application ...@@ -156,7 +156,7 @@ class Application extends \yii\base\Application
*/ */
public function getUser() public function getUser()
{ {
return $this->getComponent('user'); return $this->get('user');
} }
/** /**
...@@ -165,22 +165,20 @@ class Application extends \yii\base\Application ...@@ -165,22 +165,20 @@ class Application extends \yii\base\Application
*/ */
public function getAssetManager() public function getAssetManager()
{ {
return $this->getComponent('assetManager'); return $this->get('assetManager');
} }
/** /**
* Registers the core application components. * @inheritdoc
* @see setComponents
*/ */
public function registerCoreComponents() public function coreComponents()
{ {
parent::registerCoreComponents(); return array_merge([
$this->setComponents([
'request' => ['class' => 'yii\web\Request'], 'request' => ['class' => 'yii\web\Request'],
'response' => ['class' => 'yii\web\Response'], 'response' => ['class' => 'yii\web\Response'],
'session' => ['class' => 'yii\web\Session'], 'session' => ['class' => 'yii\web\Session'],
'user' => ['class' => 'yii\web\User'], 'user' => ['class' => 'yii\web\User'],
'assetManager' => ['class' => 'yii\web\AssetManager'], 'assetManager' => ['class' => 'yii\web\AssetManager'],
]); ], parent::coreComponents());
} }
} }
...@@ -10,6 +10,7 @@ namespace yii\web; ...@@ -10,6 +10,7 @@ namespace yii\web;
use Yii; use Yii;
use yii\caching\Cache; use yii\caching\Cache;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\di\Instance;
/** /**
* CacheSession implements a session component using cache as storage medium. * CacheSession implements a session component using cache as storage medium.
...@@ -52,13 +53,8 @@ class CacheSession extends Session ...@@ -52,13 +53,8 @@ class CacheSession extends Session
*/ */
public function init() public function init()
{ {
if (is_string($this->cache)) {
$this->cache = Yii::$app->getComponent($this->cache);
}
if (!$this->cache instanceof Cache) {
throw new InvalidConfigException('CacheSession::cache must refer to the application component ID of a cache object.');
}
parent::init(); parent::init();
$this->cache = Instance::ensure($this->cache, Cache::className());
} }
/** /**
......
...@@ -11,6 +11,7 @@ use Yii; ...@@ -11,6 +11,7 @@ use Yii;
use yii\db\Connection; use yii\db\Connection;
use yii\db\Query; use yii\db\Query;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\di\Instance;
/** /**
* DbSession extends [[Session]] by using database as session data storage. * DbSession extends [[Session]] by using database as session data storage.
...@@ -74,13 +75,8 @@ class DbSession extends Session ...@@ -74,13 +75,8 @@ class DbSession extends Session
*/ */
public function init() public function init()
{ {
if (is_string($this->db)) {
$this->db = Yii::$app->getComponent($this->db);
}
if (!$this->db instanceof Connection) {
throw new InvalidConfigException("DbSession::db must be either a DB connection instance or the application component ID of a DB connection.");
}
parent::init(); parent::init();
$this->db = Instance::ensure($this->db, Connection::className());
} }
/** /**
......
...@@ -145,7 +145,7 @@ class UrlManager extends Component ...@@ -145,7 +145,7 @@ class UrlManager extends Component
return; return;
} }
if (is_string($this->cache)) { if (is_string($this->cache)) {
$this->cache = Yii::$app->getComponent($this->cache); $this->cache = Yii::$app->get($this->cache, false);
} }
if ($this->cache instanceof Cache) { if ($this->cache instanceof Cache) {
$key = __CLASS__; $key = __CLASS__;
......
...@@ -11,6 +11,7 @@ use Yii; ...@@ -11,6 +11,7 @@ use Yii;
use yii\base\Widget; use yii\base\Widget;
use yii\caching\Cache; use yii\caching\Cache;
use yii\caching\Dependency; use yii\caching\Dependency;
use yii\di\Instance;
/** /**
* *
...@@ -79,11 +80,7 @@ class FragmentCache extends Widget ...@@ -79,11 +80,7 @@ class FragmentCache extends Widget
{ {
parent::init(); parent::init();
if (!$this->enabled) { $this->cache = $this->enabled ? Instance::ensure($this->cache, Cache::className()) : null;
$this->cache = null;
} elseif (is_string($this->cache)) {
$this->cache = Yii::$app->getComponent($this->cache);
}
if ($this->getCachedContent() === false) { if ($this->getCachedContent() === false) {
$this->getView()->cacheStack[] = $this; $this->getView()->cacheStack[] = $this;
......
...@@ -68,7 +68,7 @@ class MessageTest extends VendorTestCase ...@@ -68,7 +68,7 @@ class MessageTest extends VendorTestCase
*/ */
protected function createTestMessage() protected function createTestMessage()
{ {
return Yii::$app->getComponent('mail')->compose(); return Yii::$app->get('mail')->compose();
} }
/** /**
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\di;
use yii\di\Container;
use yii\di\Instance;
use yiiunit\framework\di\stubs\Bar;
use yiiunit\framework\di\stubs\Foo;
use yiiunit\framework\di\stubs\Qux;
use yiiunit\TestCase;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ContainerTest extends TestCase
{
public function testDefault()
{
$namespace = __NAMESPACE__ . '\stubs';
$QuxInterface = "$namespace\\QuxInterface";
$Foo = Foo::className();
$Bar = Bar::className();
$Qux = Qux::className();
// automatic wiring
$container = new Container;
$container->set($QuxInterface, $Qux);
$foo = $container->get($Foo);
$this->assertTrue($foo instanceof $Foo);
$this->assertTrue($foo->bar instanceof $Bar);
$this->assertTrue($foo->bar->qux instanceof $Qux);
// full wiring
$container = new Container;
$container->set($QuxInterface, $Qux);
$container->set($Bar);
$container->set($Qux);
$container->set($Foo);
$foo = $container->get($Foo);
$this->assertTrue($foo instanceof $Foo);
$this->assertTrue($foo->bar instanceof $Bar);
$this->assertTrue($foo->bar->qux instanceof $Qux);
// wiring by closure
$container = new Container;
$container->set('foo', function () {
$qux = new Qux;
$bar = new Bar($qux);
return new Foo($bar);
});
$foo = $container->get('foo');
$this->assertTrue($foo instanceof $Foo);
$this->assertTrue($foo->bar instanceof $Bar);
$this->assertTrue($foo->bar->qux instanceof $Qux);
// wiring by closure which uses container
$container = new Container;
$container->set($QuxInterface, $Qux);
$container->set('foo', function (Container $c, $params, $config) {
return $c->get(Foo::className());
});
$foo = $container->get('foo');
$this->assertTrue($foo instanceof $Foo);
$this->assertTrue($foo->bar instanceof $Bar);
$this->assertTrue($foo->bar->qux instanceof $Qux);
// predefined constructor parameters
$container = new Container;
$container->set('foo', $Foo, [Instance::of('bar')]);
$container->set('bar', $Bar, [Instance::of('qux')]);
$container->set('qux', $Qux);
$foo = $container->get('foo');
$this->assertTrue($foo instanceof $Foo);
$this->assertTrue($foo->bar instanceof $Bar);
$this->assertTrue($foo->bar->qux instanceof $Qux);
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\di;
use yii\base\Component;
use yii\di\Container;
use yii\di\Instance;
use yiiunit\TestCase;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class InstanceTest extends TestCase
{
public function testOf()
{
$container = new Container;
$className = Component::className();
$instance = Instance::of($className, $container);
$this->assertTrue($instance instanceof Instance);
$this->assertTrue($instance->get() instanceof Component);
$this->assertTrue(Instance::ensure($instance, $className) instanceof Component);
$this->assertTrue($instance->get() !== Instance::ensure($instance, $className));
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\di;
use yii\base\Object;
use yii\di\ServiceLocator;
use yiiunit\TestCase;
class Creator
{
public static function create()
{
return new TestClass;
}
}
class TestClass extends Object
{
public $prop1 = 1;
public $prop2;
}
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ServiceLocatorTest extends TestCase
{
public function testCallable()
{
// anonymous function
$container = new ServiceLocator;
$className = TestClass::className();
$container->set($className, function () {
return new TestClass([
'prop1' => 100,
'prop2' => 200,
]);
});
$object = $container->get($className);
$this->assertTrue($object instanceof $className);
$this->assertEquals(100, $object->prop1);
$this->assertEquals(200, $object->prop2);
// static method
$container = new ServiceLocator;
$className = TestClass::className();
$container->set($className, [__NAMESPACE__ . "\\Creator", 'create']);
$object = $container->get($className);
$this->assertTrue($object instanceof $className);
$this->assertEquals(1, $object->prop1);
$this->assertNull($object->prop2);
}
public function testObject()
{
$object = new TestClass;
$className = TestClass::className();
$container = new ServiceLocator;
$container->set($className, $object);
$this->assertTrue($container->get($className) === $object);
}
public function testShared()
{
// with configuration: shared
$container = new ServiceLocator;
$className = TestClass::className();
$container->set($className, [
'class' => $className,
'prop1' => 10,
'prop2' => 20,
]);
$object = $container->get($className);
$this->assertEquals(10, $object->prop1);
$this->assertEquals(20, $object->prop2);
$this->assertTrue($object instanceof $className);
// check shared
$object2 = $container->get($className);
$this->assertTrue($object2 instanceof $className);
$this->assertTrue($object === $object2);
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\di\stubs;
use yii\base\Object;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Bar extends Object
{
public $qux;
public function __construct(QuxInterface $qux, $config = [])
{
$this->qux = $qux;
parent::__construct($config);
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\di\stubs;
use yii\base\Object;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Foo extends Object
{
public $bar;
public function __construct(Bar $bar, $config = [])
{
$this->bar = $bar;
parent::__construct($config);
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\di\stubs;
use yii\base\Object;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Qux extends Object implements QuxInterface
{
public $a;
public function __construct($a = 1, $config = [])
{
$this->a = $a;
parent::__construct($config);
}
public function quxMethod()
{
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\di\stubs;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
interface QuxInterface
{
function quxMethod();
}
...@@ -59,7 +59,7 @@ class BaseMailerTest extends TestCase ...@@ -59,7 +59,7 @@ class BaseMailerTest extends TestCase
*/ */
protected function getTestMailComponent() protected function getTestMailComponent()
{ {
return Yii::$app->getComponent('mail'); return Yii::$app->get('mail');
} }
// Tests : // Tests :
......
...@@ -36,7 +36,7 @@ class BaseMessageTest extends TestCase ...@@ -36,7 +36,7 @@ class BaseMessageTest extends TestCase
*/ */
protected function getMailer() protected function getMailer()
{ {
return Yii::$app->getComponent('mail'); return Yii::$app->get('mail');
} }
// Tests : // Tests :
......
...@@ -58,7 +58,7 @@ class ActiveFixtureTest extends DatabaseTestCase ...@@ -58,7 +58,7 @@ class ActiveFixtureTest extends DatabaseTestCase
public function setUp() public function setUp()
{ {
parent::setUp(); parent::setUp();
\Yii::$app->setComponent('db', $this->getConnection()); \Yii::$app->set('db', $this->getConnection());
ActiveRecord::$db = $this->getConnection(); ActiveRecord::$db = $this->getConnection();
} }
......
...@@ -15,7 +15,7 @@ class CacheSessionTest extends \yiiunit\TestCase ...@@ -15,7 +15,7 @@ class CacheSessionTest extends \yiiunit\TestCase
{ {
parent::setUp(); parent::setUp();
$this->mockApplication(); $this->mockApplication();
Yii::$app->setComponent('cache', new FileCache()); Yii::$app->set('cache', new FileCache());
} }
public function testCacheSession() public function testCacheSession()
...@@ -30,7 +30,7 @@ class CacheSessionTest extends \yiiunit\TestCase ...@@ -30,7 +30,7 @@ class CacheSessionTest extends \yiiunit\TestCase
public function testInvalidCache() public function testInvalidCache()
{ {
$this->setExpectedException('yii\base\InvalidConfigException'); $this->setExpectedException('\Exception');
new CacheSession(['cache' => 'invalid']); new CacheSession(['cache' => 'invalid']);
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment