| <?php |
|
|
| |
| |
| |
| |
| |
| |
|
|
| namespace Piwik\Plugins\CoreAdminHome\Commands; |
|
|
| use Piwik\Config; |
| use Piwik\Plugin\ConsoleCommand; |
| use Piwik\Settings\FieldConfig; |
| use Piwik\Settings\Plugin\SystemConfigSetting; |
|
|
| class ConfigDelete extends ConsoleCommand |
| { |
| |
| private const MSG_NOTHING_FOUND = 'Nothing found'; |
| |
| private const MSG_SUCCESS = 'Success: The setting has been deleted'; |
|
|
| protected function configure() |
| { |
| $this->setName('config:delete'); |
| $this->setDescription('Delete a config setting'); |
| $this->addOptionalArgument( |
| 'argument', |
| "A config setting in the format Section.key or Section.array_key[], e.g. 'Database.username' or 'PluginsInstalled.PluginsInstalled.CustomDimensions'" |
| ); |
| $this->addRequiredValueOption('section', 's', 'The section the INI config setting belongs to.'); |
| $this->addRequiredValueOption('key', 'k', 'The name of the INI config setting.'); |
| $this->addRequiredValueOption('value', 'i', 'For arrays, specify the array value to be deleted.'); |
|
|
| $this->setHelp("This command can be used to delete a INI config setting. |
| |
| You can delete config values per the two sections below, where: |
| - [Section] is the name of the section, e.g. database or General. |
| - [config_setting_name] the name of the setting, e.g. username. |
| - [array_value] For arrays, the specific array value to delete. |
| |
| (1) By settings options --section=[Section] and --key=[config_setting_name], and optionally --value=[array_value]. Examples: |
| #Delete this setting. |
| $ ./console %command.name% --section=database --key=username |
| #Delete one value in an array: |
| $ ./console %command.name% --section=PluginsInstalled --key=PluginsInstalled --value=DevicesDetection |
| |
| OR |
| |
| (2) By using a command argument in the format [Section].[config_setting_name].[array_value]. Examples: |
| #Delete this setting. |
| $ ./console %command.name% 'database.username' |
| #Delete one value in an array: |
| $ ./console %command.name% 'PluginsInstalled.PluginsInstalled.DevicesDetection' |
| |
| NOTES: |
| - Settings may still appear to exist if they are set in global.ini.php or elsewhere. |
| - Section names, key names, and array values are all case-sensitive; so e.g. --section=Database fails but --section=database works. Look in config.ini.php and global.ini.php for the proper case. |
| - If no matching section/setting is found, the string \"" . self::MSG_NOTHING_FOUND . "\" shows. |
| - For safety, this tool cannot be used to delete a whole section of settings or an array of values in a single command. |
| "); |
| } |
|
|
| protected function doExecute(): int |
| { |
| $input = $this->getInput(); |
| $output = $this->getOutput(); |
|
|
| |
| $options = array_filter([ |
| 'section' => $input->getOption('section'), |
| 'key' => $input->getOption('key'), |
| 'value' => $input->getOption('value'), |
| ]); |
|
|
| $argument = trim($input->getArgument('argument') ?? ''); |
|
|
| |
| switch (true) { |
| case empty($argument) && empty($options): |
| throw new \InvalidArgumentException('You must set either an argument or set options --section, --key and optional --value'); |
| case (!empty($argument) && !empty($options)): |
| throw new \InvalidArgumentException('You cannot set both an argument (' . serialize($argument) . ') and options (' . serialize($argument) . ')'); |
| case empty($argument) && (!isset($options['section']) || empty($options['section']) || !isset($options['key']) || empty($options['key'])): |
| throw new \InvalidArgumentException('When using options, --section and --key must be set'); |
| case (!empty($argument)): |
| $settingStr = $argument; |
| break; |
| case (!empty($options)): |
| $settingStr = implode('.', $options); |
| break; |
| default: |
| |
| throw new \Exception('Some unexpected error occurred parsing input values'); |
| } |
|
|
| |
| $settingWrapped = (object) [ |
| 'setting' => null, |
| 'isArray' => false, |
| 'arrayVal' => '', |
| ]; |
|
|
| |
| $settingWrapped = self::parseSettingStr($settingStr, $settingWrapped); |
|
|
| |
| $settingWrapped = $this->checkAndPopulate($settingWrapped); |
|
|
| if (!isset($settingWrapped->setting) || empty($settingWrapped->setting)) { |
| $output->writeln(self::wrapInTag('comment', self::MSG_NOTHING_FOUND)); |
| } else { |
| |
| $result = $this->deleteConfigSetting($settingWrapped); |
|
|
| if ($result) { |
| $output->writeln($this->wrapInTag('info', self::MSG_SUCCESS)); |
| } |
| } |
|
|
| return self::SUCCESS; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| private function checkAndPopulate(object $settingWrapped): object |
| { |
|
|
| |
| if (!($settingWrapped->setting instanceof SystemConfigSetting)) { |
| throw new \InvalidArgumentException('This function expects $settingWrapped->setting to be a SystemConfigSetting instance'); |
| } |
|
|
| $config = Config::getInstance(); |
|
|
| |
| switch (true) { |
| case empty($sectionName = $settingWrapped->setting->getConfigSectionName()): |
| throw new \InvalidArgumentException('A section name must be specified'); |
| case empty($settingName = $settingWrapped->setting->getName()): |
| throw new \InvalidArgumentException('A setting name must be specified'); |
| case empty($section = $config->__get($sectionName)): |
| return new \stdClass(); |
| case empty($section = (object) $section) || !isset($section->$settingName): |
| return new \stdClass(); |
| default: |
| |
| break; |
| } |
|
|
| $settingWrappedNew = clone($settingWrapped); |
| $settingWrappedNew->isArray = is_array($section->$settingName); |
|
|
| if (!$settingWrappedNew->isArray && !empty($settingWrappedNew->arrayVal)) { |
| throw new \InvalidArgumentException('This config setting is not an array'); |
| } |
| if ($settingWrappedNew->isArray) { |
| if (empty($settingWrappedNew->arrayVal)) { |
| throw new \InvalidArgumentException('This config setting is an array, but no array value was specified for deletion'); |
| } |
| if (false === array_search($settingWrappedNew->arrayVal, $section->$settingName)) { |
| return new \stdClass(); |
| } |
| } |
|
|
| return $settingWrappedNew; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| private function deleteConfigSetting(object $settingWrapped): bool |
| { |
|
|
| |
| if (!($settingWrapped->setting instanceof SystemConfigSetting)) { |
| throw new \InvalidArgumentException('This function expects $settingWrapped->setting to be a SystemConfigSetting instance'); |
| } |
|
|
| |
| $sectionName = $settingWrapped->setting->getConfigSectionName(); |
| $settingName = $settingWrapped->setting->getName(); |
|
|
| |
| $config = Config::getInstance(); |
| $section = $config->$sectionName; |
| $setting = $section[$settingName]; |
|
|
| |
| |
| switch (true) { |
| case $settingWrapped->isArray === true && empty($settingWrapped->arrayVal): |
| throw new \InvalidArgumentException('This function refuses to delete config arrays. See usage for how to delete config array values.'); |
| case $settingWrapped->isArray === true: |
| |
|
|
| $key = array_search($settingWrapped->arrayVal, $setting); |
| if ($key !== false) { |
| unset($setting[$key]); |
| } |
|
|
| |
| $section[$settingName] = $setting; |
| break; |
| default: |
| |
| |
| unset($section[$settingName]); |
| break; |
| } |
|
|
| |
| $config->$sectionName = $section; |
|
|
| |
| $config->forceSave(); |
|
|
| return true; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| public static function parseSettingStr(string $settingStr, object $settingWrapped): object |
| { |
|
|
| $matches = []; |
| if (!preg_match('/^([a-zA-Z0-9_]+)(?:\.([a-zA-Z0-9_]+))?(?:\[\])?(?:\.(.+))?/', $settingStr, $matches) || empty($matches[1])) { |
| throw new \InvalidArgumentException("Invalid input string='{$settingStr}': expected section.name or section.name[]"); |
| } |
|
|
|
|
| $settingName = $matches[2] ?? null; |
| $arrayVal = $matches[3] ?? null; |
|
|
| $systemConfigSetting = new SystemConfigSetting( |
| |
| $settingName, |
| |
| '', |
| |
| FieldConfig::TYPE_STRING, |
| |
| 'core', |
| |
| $matches[1] |
| ); |
|
|
| $settingWrappedNew = clone($settingWrapped); |
| $settingWrappedNew->setting = $systemConfigSetting; |
| if ($settingWrappedNew->isArray = !empty($arrayVal)) { |
| $settingWrappedNew->arrayVal = $arrayVal; |
| } |
|
|
| return $settingWrappedNew; |
| } |
| } |
|
|