Yii2:モジュールを管理するためのモジュールの作成

すべての人に挨拶! 現在のプロジェクトではYii2を使用しており、開発プロセス中にモジュールとして何らかのエンティティが必要でした。



Yii2はすでにモジュラーシステムを実装していますが、1つのモジュールが1つのモジュールを別のモジュールに表示することを許可せず、ウィジェットの使用も適切ではないという1つの欠点があります。 これはビューの一部であり、たとえば着信POST要求などのアクションを処理する方法がわかりません(ただし、一度はいくつかの松葉杖でウィジェットを使用していました)。



任意のコントローラーで使用できるネストされたモジュールを含むモジュールを作成します。



その結果、以下が得られます。





このアイデアは、CMS OpenCartのモジュールの実装に取り​​入れられています。



giiを介してディスパッチャモジュールを作成し、 web.php構成にプラグインすることから始めましょう



'dispatcher' => [ 'class' => 'app\modules\dispatcher\Module', ],
      
      





モジュールディレクトリapp \ modules \ dispatcherで、 \ yii \ base \ Moduleを継承するBasicModuleクラスを作成します。



BasicModule.php
 <?php namespace app\modules\dispatcher; use app\modules\dispatcher\components\Controller; use app\modules\dispatcher\models\LayoutModule; /** * * Class Module * @package app\modules\dispatcher\components * */ class BasicModule extends \yii\base\Module { const POSITION_HEADER = 'header'; const POSITION_FOOTER = 'footer'; const POSITION_LEFT = 'left'; const POSITION_RIGHT = 'right'; /** * @var array of positions */ static protected $positions = [ self::POSITION_HEADER, self::POSITION_FOOTER, self::POSITION_LEFT, self::POSITION_RIGHT, ]; /** * @var string controller name */ public $defaultControllerName = 'DefaultController'; /** * @var string dir of modules catalog */ public $modulesDir = 'catalog'; /** * @var string modules namespace */ private $_modulesNamespace; /** * @var string absolute path to modules dir */ public $modulePath; /** * * @throws \yii\base\InvalidParamException */ public function init() { parent::init(); $this->_setModuleVariables(); $this->loadModules(); } /** * Load modules from directory by path * @throws \yii\base\InvalidParamException */ protected function loadModules() { $handle = opendir($this->modulePath); while (($dir = readdir($handle)) !== false) { if ($dir === '.' || $dir === '..') { continue; } $class = $this->_modulesNamespace . '\\' . $dir . '\\Module'; if (class_exists($class)) { $this->modules = [ $dir => [ 'class' => $class, ], ]; } } closedir($handle); } /** * @param $layout * @param array $positions * @return array * @throws \yii\base\InvalidConfigException */ public function run($layout, array $positions = []) { $model = $this->findModel($layout, $positions); $data = []; foreach ($model as $item) { if ($controller = $this->findModuleController($item['module'])) { $data[$item['position']][] = \Yii::createObject($controller, [$item['module'], $this])->index(); } } return $data; } /** * @param $layout_id * @param array $positions * @return array|\yii\db\ActiveRecord[] * @internal param $layout */ public function findModel($layout_id, array $positions = []) { if (empty($positions)) { $positions = self::$positions; } return LayoutModule::find() ->where([ 'layout_id' => $layout_id, 'position' => $positions, 'status' => LayoutModule::STATUS_ACTIVE, ])->orderBy([ 'sort_order' => SORT_ASC ])->asArray()->all(); } /** * @param $name * @return null|string */ public function findModuleController($name) { $className = $this->_modulesNamespace . '\\' . $name . '\controllers\\' . $this->defaultControllerName; return is_subclass_of($className, Controller::class) ? $className : null; } /** * Set modules namespace and path */ private function _setModuleVariables() { $class = new \ReflectionClass($this); $this->_modulesNamespace = $class->getNamespaceName() . '\\' . $this->modulesDir; $this->modulePath = dirname($class->getFileName()) . DIRECTORY_SEPARATOR . $this->modulesDir; } }
      
      







BasicModuleからモジュールクラスアプリ\モジュール\ディスパッチャー\モジュールを継承します



Module.php
 <?php namespace app\modules\dispatcher; /** * dispatcher module definition class */ class Module extends BasicModule { /** * @inheritdoc */ public function init() { parent::init(); } }
      
      







移行を作成して実行します。



移行
  public $table = '{{%layout_module}}'; public function safeUp() { $tableOptions = null; if ($this->db->driverName === 'mysql') { $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; } $this->createTable($this->table, [ 'id' => $this->primaryKey(), 'layout_id' => $this->integer()->notNull(), // id      'module' => $this->string(150)->notNull(), //  'status' => $this->boolean()->defaultValue(true), 'position' => $this->string(30)->notNull(), 'sort_order' => $this->integer()->defaultValue(1), ], $tableOptions); } public function safeDown() { $this->dropTable($this->table); }
      
      





作成したテーブルに入力します。



 INSERT INTO `layout_module` VALUES ('1', '1', 'test', '1', 'header', '1'); INSERT INTO `layout_module` VALUES ('2', '1', 'test', '1', 'footer', '1'); INSERT INTO `layout_module` VALUES ('3', '1', 'test', '1', 'left', '1');
      
      





ディスパッチャモジュールのルートで、 componentsディレクトリを追加します\ yii \ web \ Controllerを継承するクラスControllerを作成します 。 その中でrender()メソッドを再定義します



Controller.php
 <?php namespace app\modules\dispatcher\components; /** * * Class Controller * @package app\modules\dispatcher\components */ class Controller extends \yii\web\Controller { /** * @param string $view * @param array $params * @return string * @throws \yii\base\InvalidParamException * @throws \yii\base\ViewNotFoundException * @throws \yii\base\InvalidCallException */ public function render($view, $params = []) { $controller = str_replace('Controller', '', $this->module->defaultControllerName); $path = '@app/modules/dispatcher/' . $this->module->modulesDir . '/' . $this->id . '/views/' . $controller; return $this->getView()->render($path . '/' . 'index', $params, $this); } }
      
      







カタログディレクトリをディスパッチャモジュールのルートに追加します-これはモジュールの親ディレクトリです。



次に、最初のモジュールを作成します。その構造は、通常のYii2モジュールと変わりません。 テストディレクトリを作成し、その中にModuleクラスを作成します。



Module.php
 <?php namespace app\modules\dispatcher\catalog\test; /** * test module definition class */ class Module extends \yii\base\Module { /** * @inheritdoc */ public $controllerNamespace = 'app\modules\dispatcher\catalog\test\controllers'; }
      
      







controllersディレクトリを作成し、その中にapp \ modules \ dispatcher \ components \ Controllerから継承するクラスDefaultControllerを作成します



Defaultcontroller.php
 <?php namespace app\modules\dispatcher\catalog\test\controllers; use app\modules\dispatcher\components\Controller; /** * Default controller for the `test` module */ class DefaultController extends Controller { /** * Renders the index view for the module * @return string * @throws \yii\base\InvalidParamException * @throws \yii\base\ViewNotFoundException * @throws \yii\base\InvalidCallException */ public function index() { return $this->render('index'); } }
      
      







重要:モジュールが機能するには、常にapp \ modules \ dispatcher \ components \ Controllerから継承し、 indexメソッドを含む必要があります



ビュー/デフォルトビューとビューファイルのディレクトリを作成します。



index.php
 <div class="dispatcher-default-index"> <p> You may customize this page by editing the following file:<br> <code><?= __FILE__ ?></code> </p> </div>
      
      







ほとんどすべての準備が整いました。モジュールを呼び出すだけです。 これを行うには、 app \ modules \ dispatcher \ componentsに Dispatcherコンポーネントを作成します



Dispatcher.php
 <?php namespace app\modules\dispatcher\components; use yii\base\Object; class Dispatcher extends Object { /** * @var \app\modules\dispatcher\Module */ private $_module; public $module = 'dispatcher'; /** * Dispatcher constructor. * @param array $config */ public function __construct(array $config = []) { parent::__construct($config); $this->_module = \Yii::$app->getModule($this->module); } /** * Get modules by layout * * @param $layout * @param array $positions * @return array * @throws \yii\base\InvalidConfigException */ public function modules($layout, array $positions = []) { return $this->_module->run($layout, $positions); } }
      
      







次に、 web.phpでコンポーネントを接続する必要があります



  'dispatcher' => [ 'class' => 'app\modules\dispatcher\components\Dispatcher', ],
      
      





コンポーネントをコンポーネント配列に追加する必要があることを忘れないでください。



任意のコントローラー(例えばSiteController )で、 actionIndex()メソッドに追加します



  /* @var $modules Dispatcher */ $modules = \Yii::$app->dispatcher->modules(1); return $this->render('index', compact('modules'));
      
      





ビュー内のモジュールビュー/サイト/ index.phpの出力に位置を追加するだけです。



index.php
 <?php /* @var $this yii\web\View */ $this->title = 'My Yii Application'; use app\modules\dispatcher\Module; ?> <div class="site-index"> <?php if (isset($modules[Module::POSITION_HEADER])) { ?> <div class="row"> <?php foreach ($modules[Module::POSITION_HEADER] as $module) { echo $module; } ?> </div> <?php } ?> <div class="jumbotron"> <h1>Congratulations!</h1> <p class="lead">You have successfully created your Yii-powered application.</p> <p><a class="btn btn-lg btn-success" href="http://www.yiiframework.com">Get started with Yii</a></p> </div> <div class="body-content"> <div class="row"> <div class="col-lg-4"> <h2>Heading</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p> <p><a class="btn btn-default" href="http://www.yiiframework.com/doc/">Yii Documentation »</a></p> </div> <div class="col-lg-4"> <h2>Heading</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p> <p><a class="btn btn-default" href="http://www.yiiframework.com/forum/">Yii Forum »</a> </p> </div> <div class="col-lg-4"> <h2>Heading</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p> <p><a class="btn btn-default" href="http://www.yiiframework.com/extensions/">Yii Extensions »</a></p> </div> </div> </div> <?php if (isset($modules[Module::POSITION_FOOTER])) { ?> <div class="row"> <?php foreach ($modules[Module::POSITION_FOOTER] as $module) { echo $module; } ?> </div> <?php } ?> </div>
      
      







モジュールの公式ドキュメントをお勧めします



すべてのコードはGitHubに投稿されます



All Articles