/** * Bootstrap method to be called during application bootstrap stage. * * @param Application $app the application currently running */ public function bootstrap($app) { $app->i18n->translations['extensions-manager'] = ['class' => 'yii\\i18n\\PhpMessageSource', 'basePath' => __DIR__ . DIRECTORY_SEPARATOR . 'messages']; DeferredQueueEvent::on(DeferredController::className(), DeferredController::EVENT_DEFERRED_QUEUE_COMPLETE, [DeferredQueueCompleteHandler::className(), 'handleEvent']); if ($app instanceof \yii\console\Application) { $app->controllerMap['extension'] = ExtensionController::className(); $app->on(Application::EVENT_BEFORE_ACTION, function () { $module = ExtensionsManager::module(); if ($module->autoDiscoverMigrations === true) { if (isset(Yii::$app->params['yii.migrations']) === false) { Yii::$app->params['yii.migrations'] = []; } /** @var array $extensions */ $extensions = $module->getExtensions(); foreach ($extensions as $name => $ext) { if ($ext['composer_type'] === Extension::TYPE_DOTPLANT && $module->discoverDotPlantMigrations === false) { continue; } $extData = ComposerInstalledSet::get()->getInstalled($ext['composer_name']); $packageMigrations = ExtensionDataHelper::getInstalledExtraData($extData, 'migrationPath', true); $packagePath = '@vendor/' . $ext['composer_name']; foreach ($packageMigrations as $migrationPath) { Yii::$app->params['yii.migrations'][] = "{$packagePath}/{$migrationPath}"; } } } }); } }
/** * @return bool */ public static function generateConfig() { $installed = ComposerInstalledSet::get()->getInstalled(); $fileName = Yii::getAlias(ExtensionsManager::module()->extensionsStorage); $writer = new ApplicationConfigWriter(['filename' => $fileName]); $config = self::rebuldConfig($installed); $writer->addValues($config); return $writer->commit(); }
/** * Updates config. * Calculates differences between @vengor/composer/installed.json and ExtensionsManager::$extensionsStorage * and writes new ExtensionsManager::$extensionsStorage * */ public function actionUpdateConfig() { $result = (int) (ExtensionFileWriter::updateConfig() !== true); if ($result === 0) { $this->stdout('Update OK' . PHP_EOL, Console::FG_GREEN); } else { $this->stderr('Error updating extensions storage: ', Console::FG_RED); $this->stderr(ExtensionsManager::module()->extensionsStorage . PHP_EOL); } return $result; }
/** * @param bool $onlyActive load configurables only for active extensions * @return array */ public static function getConfigurables($onlyActive = false) { $installed = ComposerInstalledSet::get()->getInstalled(); $configurables = []; foreach ($installed as $package) { $packageConfigurablesFile = ArrayHelper::getValue($package, 'extra.configurables', null); if ($packageConfigurablesFile === null || true === $onlyActive && false === ExtensionsManager::module()->extensionIsActive($package['name'])) { continue; } $fn = Yii::getAlias('@vendor') . DIRECTORY_SEPARATOR . $package['name'] . DIRECTORY_SEPARATOR . $packageConfigurablesFile; if (file_exists($fn) && is_readable($fn)) { $packageConfigurables = (include $fn); array_walk($packageConfigurables, function (&$item) use($package) { $item['package'] = $package['name']; $item['sectionNameTranslated'] = ExtensionDataHelper::getLocalizedDataField($package, Extension::TYPE_YII, 'name'); }); $configurables = ArrayHelper::merge($configurables, $packageConfigurables); } } return $configurables; }
/** * Adds uninstall task into ReportingChain * * @param $extension * @param ReportingChain $chain */ private static function uninstall($extension, ReportingChain $chain) { $module = ExtensionsManager::module(); if (true === $module->extensionIsCore($extension['composer_name'])) { $dummyTask = ExtensionDataHelper::buildTask([realpath(Yii::getAlias('@app') . '/yii'), 'extension/dummy', '--no-interaction', '-o', 'You are unable to uninstall core extensions!'], ExtensionsManager::EXTENSION_DUMMY_DEFERRED_GROUP); $chain->addTask($dummyTask); } else { self::deactivate($extension, $chain); $uninstallTask = ExtensionDataHelper::buildTask([$module->composerPath, 'remove', $extension['composer_name'], "--working-dir={$module->getLocalExtensionsPath()}", $module->verbose == 1 ? '-vvv' : ''], ExtensionsManager::COMPOSER_UNINSTALL_DEFERRED_GROUP); $chain->addTask($uninstallTask); } }
$this->params['breadcrumbs'][] = $this->title; ?> <div class="row"> <div class="col-md-3"> <div class="box box-solid configuration-navigation"> <div class="box-header"> <h3 class="box-title"> <i class="fa fa-list-alt"></i> <?php echo Yii::t('extensions-manager', 'Extensions manager'); ?> </h3> </div> <div class="box-body"> <?php echo \yii\bootstrap\Nav::widget(['items' => ExtensionsManager::navLinks(), 'options' => ['class' => 'nav-pills nav-stacked']]); ?> </div> </div> </div> <div class="col-md-9"> <div class="extensions-controller__search-extensions box box-solid"> <div class="box-header clearfix"> <h3 class="box-title pull-left"> <?php echo Yii::t('extensions-manager', 'Extensions search'); ?> </h3> <div class="pull-right"> <?php echo Html::beginForm(['/extensions-manager/extensions/search'], 'GET', ['class' => 'form-inline']);
/** * Updates all application configurations * * @param bool $usePostData Should we populate all configurationModels with user-data * @param bool $loadCurrent if true current states will be loaded and merged with newly created model * otherwise configs will be just overwritten with data loaded from post if $usePostData === true * @return bool true if all is ok * @throws \yii\base\InvalidConfigException */ public function updateConfiguration($usePostData = true) { /** @var ApplicationConfigWriter[] $configWriters */ $configWriters = []; foreach ($this->configs as $filename => $functionName) { $file = $this->generatedConfigsPath . $filename . '.php'; $configWriters[$filename] = new ApplicationConfigWriter(['filename' => $file]); } $this->getConfigurables(true); $isValid = true; $errorSection = ''; foreach ($this->_configurables as $configurable) { if (!isset($configurable['configurationModel'])) { continue; } /** @var BaseConfigurationModel $configurationModel */ $configurationModel = new $configurable['configurationModel'](); if (false === ExtensionsManager::module()->extensionIsActive($configurable['package'])) { $configurationModel->deleteFromState($this->configurablesStatePath); continue; } else { $configurationModel->loadState($this->configurablesStatePath); } $dataOk = true; if ($usePostData === true) { $dataOk = $configurationModel->load(Yii::$app->request->post()); } if ($dataOk === true) { $event = new ConfigurationSaveEvent(); $event->configurable =& $configurable; $event->configurationModel =& $configurationModel; $configurationModel->trigger($configurationModel->configurationSaveEvent(), $event); if ($event->isValid === true) { if ($configurationModel->validate() === true) { $configurationModel->saveState($this->configurablesStatePath); } else { if (Yii::$app->get('session', false)) { Yii::$app->get('session')->setFlash('info', 'Validation error:' . var_export($configurationModel, true)); } $isValid = false; } } else { $isValid = false; } if ($isValid === false) { $errorSection = $configurable['sectionName']; // event is valid, stop saving data break; } } // model load from user input foreach ($configWriters as $filename => $writer) { $callbackFunction = $this->configs[$filename]; $writer->addValues(call_user_func([$configurationModel, $callbackFunction])); } } // /foreach if ($isValid === true) { // save all configurations $isValid = true; foreach ($configWriters as $writer) { $isValid = $isValid && $writer->commit(); } } if (Yii::$app->get('session', false)) { if ($isValid === true) { Yii::$app->session->setFlash('success', Yii::t('extensions-manager', 'Configuration saved')); } else { Yii::$app->session->setFlash('error', Yii::t('extensions-manager', 'Error saving configuration for module {module}', ['module' => $errorSection])); } } return $isValid; }
/** * @return string|\yii\web\Response */ public function saveData() { if (false === isset($this->model)) { return ''; } if ($this->model->load(Yii::$app->request->post()) && $this->model->validate()) { if (ExtensionsManager::module()->configurationUpdater->updateConfiguration(true)) { return $this->controller->redirect([$this->id, 'sectionIndex' => $this->sectionIndex]); } } return ''; }
/** * This test runs last, because it overrides extensions.php file from installed.json * and we have no activated and core extensions there * * @depends testGetModule * @param ExtensionsManager $module */ public function testGetExtensionsNoFile(ExtensionsManager $module) { TestConfigCleaner::removeExtFile(); $a = $module->getExtensions('', true); $this->assertTrue(TestConfigCleaner::checkExtFile()); $this->assertEquals(4, count($a)); }
/** * @inheritdoc */ public function getModuleClassName() { return ExtensionsManager::className(); }