/** * After installation is completed. * * @return void */ protected function _finish() { global $classLoader; // composer's class loader instance snapshot(); Plugin::dropCache(); // trick: makes plugin visible to AcoManager $classLoader->addPsr4($this->_plugin['name'] . "\\", normalizePath(ROOT . "/plugins/{$this->_plugin['name']}/src"), true); AcoManager::buildAcos($this->_plugin['name']); $this->_reset(); }
/** * Runs uninstallation logic inside a safe transactional thread. This prevent * DB inconsistencies on uninstall failure. * * @return bool True on success, false otherwise */ protected function _runTransactional() { // to avoid any possible issue snapshot(); if (!is_writable(TMP)) { $this->err(__d('installer', 'Enable write permissions in /tmp directory before uninstall any plugin or theme.')); return false; } if (!$this->params['plugin']) { $this->err(__d('installer', 'No plugin/theme was given to remove.')); return false; } $this->loadModel('System.Plugins'); try { $plugin = plugin($this->params['plugin']); $pluginEntity = $this->Plugins->find()->where(['name' => $this->params['plugin']])->limit(1)->first(); } catch (\Exception $ex) { $plugin = $pluginEntity = false; } if (!$plugin || !$pluginEntity) { $this->err(__d('installer', 'Plugin "{0}" was not found.', $this->params['plugin'])); return false; } $this->_plugin = $plugin; $type = $plugin->isTheme ? 'theme' : 'plugin'; if ($plugin->isTheme && in_array($plugin->name, [option('front_theme'), option('back_theme')])) { $this->err(__d('installer', '{0} "{1}" is currently being used and cannot be removed.', $type == 'plugin' ? __d('installer', 'The plugin') : __d('installer', 'The theme'), $plugin->humanName)); return false; } $requiredBy = Plugin::checkReverseDependency($this->params['plugin']); if (!empty($requiredBy)) { $names = []; foreach ($requiredBy as $p) { $names[] = $p->name(); } $this->err(__d('installer', '{0} "{1}" cannot be removed as it is required by: {2}', $type == 'plugin' ? __d('installer', 'The plugin') : __d('installer', 'The theme'), $plugin->humanName, implode(', ', $names))); return false; } if (!$this->_canBeDeleted($plugin->path)) { return false; } if (!$this->params['no-callbacks']) { try { $event = $this->trigger("Plugin.{$plugin->name}.beforeUninstall"); if ($event->isStopped() || $event->result === false) { $this->err(__d('installer', 'Task was explicitly rejected by {0}.', $type == 'plugin' ? __d('installer', 'the plugin') : __d('installer', 'the theme'))); return false; } } catch (\Exception $e) { $this->err(__d('installer', 'Internal error, {0} did not respond to "beforeUninstall" callback correctly.', $type == 'plugin' ? __d('installer', 'the plugin') : __d('installer', 'the theme'))); return false; } } if (!$this->Plugins->delete($pluginEntity)) { $this->err(__d('installer', '{0} "{1}" could not be unregistered from DB.', $type == 'plugin' ? __d('installer', 'The plugin') : __d('installer', 'The theme'), $plugin->humanName)); return false; } $this->_removeOptions(); $this->_clearAcoPaths(); $folder = new Folder($plugin->path); $folder->delete(); snapshot(); if (!$this->params['no-callbacks']) { try { $this->trigger("Plugin.{$plugin->name}.afterUninstall"); } catch (\Exception $e) { $this->err(__d('installer', '{0} did not respond to "afterUninstall" callback.', $type == 'plugin' ? __d('installer', 'The plugin') : __d('installer', 'The theme'))); } } Plugin::unload($plugin->name); Plugin::dropCache(); return true; }
/** * Switch site's theme. * * @return void */ protected function _change() { $disabledThemes = plugin()->filter(function ($theme) { return $theme->isTheme && !in_array($theme->name, [option('front_theme'), option('back_theme')]); })->toArray(); if (!count($disabledThemes)) { $this->err(__d('installer', '<info>There are no disabled themes!</info>')); $this->out(); return; } $index = 1; $this->out(); foreach ($disabledThemes as $theme) { $disabledThemes[$index] = $theme; $this->out(__d('installer', '[{0, number, integer}] {1} [{2}]', [$index, $theme->humanName, $theme->isAdmin ? __d('installer', 'backend') : __d('installer', 'frontend')])); $index++; } $this->out(); $message = __d('installer', "Which theme would you like to activate?\n[Q]uit"); while (true) { $in = $this->in($message); if (strtoupper($in) === 'Q') { $this->err(__d('installer', 'Operation aborted')); break; } elseif (intval($in) < 1 || !isset($disabledThemes[intval($in)])) { $this->err(__d('installer', 'Invalid option')); } else { $task = $this->dispatchShell("Installer.themes change -t {$disabledThemes[$in]->name}"); if ($task === 0) { $this->out(__d('installer', 'Theme changed!')); Plugin::dropCache(); } else { $this->err(__d('installer', 'Theme could not be changed.'), 2); $this->out(); } break; } } $this->out(); }
/** * Disables a plugin. * * @return void */ protected function _disable() { $enabledPlugins = plugin()->filter(function ($plugin) { return $plugin->status && !$plugin->isTheme; })->toArray(); if (!count($enabledPlugins)) { $this->err(__d('installer', '<info>There are no active plugins!</info>')); $this->out(); return; } $index = 1; $this->out(); foreach ($enabledPlugins as $plugin) { $enabledPlugins[$index] = $plugin; $this->out(__d('installer', '[{0, number, integer}] {1}', [$index, $plugin->humanName])); $index++; } $this->out(); $message = __d('installer', "Which plugin would you like to disable?\n[Q]uit"); while (true) { $in = $this->in($message); if (strtoupper($in) === 'Q') { $this->err(__d('installer', 'Operation aborted')); break; } elseif (intval($in) < 1 || !isset($enabledPlugins[intval($in)])) { $this->err(__d('installer', 'Invalid option')); } else { $plugin = plugin($enabledPlugins[$in]->name()); $this->hr(); $this->out(__d('installer', '<info>The following plugin will be DISABLED</info>')); $this->hr(); $this->out(__d('installer', 'Name: {0}', $plugin->name)); $this->out(__d('installer', 'Description: {0}', $plugin->composer['description'])); $this->out(__d('installer', 'Status: {0}', $plugin->status ? __d('installer', 'Active') : __d('installer', 'Disabled'))); $this->out(__d('installer', 'Path: {0}', $plugin->path)); $this->hr(); $this->out(); $confirm = $this->in(__d('installer', 'Please type in "{0}" to disable this plugin', $enabledPlugins[$in]->name)); if ($confirm === $enabledPlugins[$in]->name) { $task = $this->dispatchShell("Installer.plugins toggle -p {$enabledPlugins[$in]->name} -s disable"); if ($task === 0) { $this->out(__d('installer', 'Plugin disabled!')); Plugin::dropCache(); } else { $this->err(__d('installer', 'Plugin could not be disabled.'), 2); $this->out(); } } break; } } $this->out(); }
/** * Gets a collection list of plugin that depends on this plugin. * * @return \Cake\Collection\Collection List of plugins */ public function requiredBy() { if ($cache = $this->config('required_by')) { return collection($cache); } Plugin::dropCache(); $out = []; $plugins = Plugin::get()->filter(function ($v, $k) { return $v->name() !== $this->name(); }); foreach ($plugins as $plugin) { if ($dependencies = $plugin->dependencies($plugin->name)) { $packages = array_map(function ($item) { list(, $package) = packageSplit($item, true); return strtolower($package); }, array_keys($dependencies)); if (in_array(strtolower($this->name()), $packages)) { $out[] = $plugin; } } } $this->config('required_by', $out); return collection($out); }