Commit 8e96623a by Qiang Xue

Fixes #1452: Added `Module::getInstance()` to allow accessing the module…

Fixes #1452: Added `Module::getInstance()` to allow accessing the module instance from anywhere within the module
parent 27943ce7
......@@ -3,8 +3,9 @@ Modules
Modules are self-contained software units that consist of [models](structure-models.md), [views](structure-views.md),
[controllers](structure-controllers.md), and other supporting components. End users can access the controllers
of a module when it is installed in [application](structure-applications.md). Modules differ from
[applications](structure-applications.md) in that the former cannot be deployed alone and must reside within the latter.
of a module when it is installed in [application](structure-applications.md). For these reasons, modules are
often viewed as mini-applications. Modules differ from [applications](structure-applications.md) in that
modules cannot be deployed alone and must reside within applications.
## Creating Modules <a name="creating-modules"></a>
......@@ -135,7 +136,7 @@ the [[yii\base\Application::modules|modules]] property of the application. The f
```
The [[yii\base\Application::modules|modules]] property takes an array of module configurations. Each array key
represents a module ID which uniquely identifies the module among all modules in the application, and the corresponding
represents a *module ID* which uniquely identifies the module among all modules in the application, and the corresponding
array value is a [configuration](concept-configurations.md) for creating the module.
......@@ -152,8 +153,24 @@ controller in the `forum` module.
### Accessing Modules <a name="accessing-modules"></a>
A module is instantiated when one of its controllers is accessed by end users. You may access the instance of a module
using the approaches shown in the following example:
Within a module, you may often need to get the instance of the [module class](#module-classes) so that you can
access the module ID, module parameters, module components, etc. You can do so by using the following statement:
```php
$module = MyModuleClass::getInstance();
```
where `MyModuleClass` refers to the name of the module class that you are interested in. The `getInstance()` method
will return the currently requested instance of the module class. If the module is not requested, the method will
return null. Note that You do not want to manually create a new instance of the module class because it will be
different from the one created by Yii in response to a request.
> Info: When developing a module, you should not assume the module will use a fixed ID. This is because a module
can be associated with an arbitrary ID when used in an application or within another module. In order to get
the module ID, you should use the above approach to get the module instance first, and then get the ID via
`$module->id`.
You may also access the instance of a module using the following approaches:
```php
// get the module whose ID is "forum"
......@@ -163,8 +180,8 @@ $module = \Yii::$app->getModule('forum');
$module = \Yii::$app->controller->module;
```
The first approach is only useful in application code which has knowledge about the module ID, while the second approach
is best used by the code within the module.
The first approach is only useful when you know the module ID, while the second approach is best used when you
know about the controllers being requested.
Once getting hold of a module instance, you can access parameters or components registered with the module. For example,
......@@ -230,5 +247,5 @@ a set of closely related features. Each such feature group can be developed as a
maintained by a specific developer or team.
Modules are also a good way of reusing code at the feature group level. Some commonly used features, such as
user management, comment management, can all be developed in terms of modules so that they can be resued easily
user management, comment management, can all be developed in terms of modules so that they can be reused easily
in future projects.
......@@ -66,6 +66,7 @@ Yii Framework 2 Change Log
- Bug: Fixed the bug that requesting protected or private action methods would cause 500 error instead of 404 (qiangxue)
- Bug: Fixed Object of class Imagick could not be converted to string in CaptchaAction (eXprojects, cebe)
- Enh #422: Added Support for BIT(M) data type default values in Schema (cebe)
- Enh #1452: Added `Module::getInstance()` to allow accessing the module instance from anywhere within the module (qiangxue)
- Enh #2264: `CookieCollection::has()` will return false for expired or removed cookies (qiangxue)
- Enh #2435: `yii\db\IntegrityException` is now thrown on database integrity errors instead of general `yii\db\Exception` (samdark)
- Enh #2558: Enhanced support for memcached by adding `yii\caching\MemCache::persistentId` and `yii\caching\MemCache::options` (qiangxue)
......@@ -110,12 +111,14 @@ Yii Framework 2 Change Log
- Enh #3774: Added `FileValidator::checkExtensionByMimeType` to support validating file types against file mime-types (Ragazzo)
- Enh #3801: Base migration controller `yii\console\controllers\BaseMigrateController` extracted (klimov-paul)
- Enh #3811: Now Gii model generator makes autocomplete for model class field (mitalcoi)
- Enh #3926: `yii\widgets\Breadcrumbs::$links`. Allows individual link to have its own `template` (creocoder, umneeq)
- Enh #3939: `\yii\Inflector::slug()` improvements (samdark)
- Added protected `\yii\Inflector::transliterate()` that could be replaced with custom translit implementation.
- Added proper tests for both intl-based slug and PHP fallback.
- Removed character maps for non-latin languages.
- Improved overall slug results.
- Added note about the fact that intl is required for non-latin languages to requirements checker.
- Enh #4028: Added ability to `yii\widgets\Menu` to encode each item's label separately (creocoder, umneeq)
- Enh: Added support for using sub-queries when building a DB query with `IN` condition (qiangxue)
- Enh: Supported adding a new response formatter without the need to reconfigure existing formatters (qiangxue)
- Enh: Added `yii\web\UrlManager::addRules()` to simplify adding new URL rules (qiangxue)
......@@ -129,8 +132,6 @@ Yii Framework 2 Change Log
- Enh: Added param `hideOnSinglePage` to `yii\widgets\LinkPager` (arturf)
- Enh: Added support for array attributes in `in` validator (creocoder)
- Enh: Improved `yii\helpers\Inflector::slug` to support more cases for Russian, Hebrew and special characters (samdark)
- Enh #3926: `yii\widgets\Breadcrumbs::$links`. Allows individual link to have its own `template` (creocoder, umneeq)
- Enh #4028: Added ability to `yii\widgets\Menu` to encode each item's label separately (creocoder, umneeq)
- Chg #2287: Split `yii\db\ColumnSchema::typecast()` into two methods `phpTypecast()` and `dbTypecast()` to allow specifying PDO type explicitly (cebe)
- Chg #2898: `yii\console\controllers\AssetController` is now using hashes instead of timestamps (samdark)
- Chg #2913: RBAC `DbManager` is now initialized via migration (samdark)
......
......@@ -189,6 +189,7 @@ abstract class Application extends Module
public function __construct($config = [])
{
Yii::$app = $this;
$this->setInstance($this);
$this->state = self::STATE_BEGIN;
......
......@@ -122,7 +122,10 @@ class Module extends ServiceLocator
* @var array child modules of this module
*/
private $_modules = [];
/**
* @var array list of currently requested modules indexed by their class names
*/
private static $_instances = [];
/**
* Constructor.
......@@ -138,6 +141,32 @@ class Module extends ServiceLocator
}
/**
* Returns the currently requested instance of this module class.
* If the module class is not currently requested, null will be returned.
* This method is provided so that you access the module instance from anywhere within the module.
* @return static|null the currently requested instance of this module class, or null if the module class is not requested.
*/
public static function getInstance()
{
$class = get_called_class();
return isset(self::$_instances[$class]) ? self::$_instances[$class] : null;
}
/**
* Sets the currently requested instance of this module class.
* @param Module|null $instance the currently requested instance of this module class.
* If it is null, the instance of the calling class will be removed, if any.
*/
public static function setInstance($instance)
{
if ($instance === null) {
unset(self::$_instances[get_class()]);
} else {
self::$_instances[get_class($instance)] = $instance;
}
}
/**
* Initializes the module.
*
* This method is called after the module is created and initialized with property values
......@@ -326,8 +355,10 @@ class Module extends ServiceLocator
if (is_array($this->_modules[$id]) && !isset($this->_modules[$id]['class'])) {
$this->_modules[$id]['class'] = 'yii\base\Module';
}
return $this->_modules[$id] = Yii::createObject($this->_modules[$id], [$id, $this]);
/** @var $module Module */
$module = Yii::createObject($this->_modules[$id], [$id, $this]);
$module->setInstance($module);
return $this->_modules[$id] = $module;
}
}
......
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