diff --git a/docs/guide/structure-modules.md b/docs/guide/structure-modules.md index 507db664ad..e09e473e00 100644 --- a/docs/guide/structure-modules.md +++ b/docs/guide/structure-modules.md @@ -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 @@ -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 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. diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 82884be721..dd16e15a45 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -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) diff --git a/framework/base/Application.php b/framework/base/Application.php index 77e7525ec7..f94e36f184 100644 --- a/framework/base/Application.php +++ b/framework/base/Application.php @@ -189,6 +189,7 @@ abstract class Application extends Module public function __construct($config = []) { Yii::$app = $this; + $this->setInstance($this); $this->state = self::STATE_BEGIN; diff --git a/framework/base/Module.php b/framework/base/Module.php index 01b6add170..8d4379869b 100644 --- a/framework/base/Module.php +++ b/framework/base/Module.php @@ -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. @@ -137,6 +140,32 @@ class Module extends ServiceLocator parent::__construct($config); } + /** + * 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. * @@ -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; } }