diff --git a/src/Oro/Bundle/ConfigBundle/Command/ConfigViewCommand.php b/src/Oro/Bundle/ConfigBundle/Command/ConfigViewCommand.php
new file mode 100644
index 00000000000..504cfaf8326
--- /dev/null
+++ b/src/Oro/Bundle/ConfigBundle/Command/ConfigViewCommand.php
@@ -0,0 +1,121 @@
+configManager = $configManager;
+ $this->formProvider = $formProvider;
+
+ parent::__construct();
+ }
+
+ /** @noinspection PhpMissingParentCallCommonInspection */
+ protected function configure(): void
+ {
+ $this
+ ->addArgument('name', InputArgument::REQUIRED, 'Config parameter name')
+ ->setDescription('Views a configuration value in the global scope.')
+ ->setHelp(
+ <<<'HELP'
+The %command.name% command views a configuration value in the global scope.
+
+ php %command.full_name%
+
+For example, to view the back-office and storefront URLs of an OroCommerce instance respectively:
+
+ php %command.full_name% oro_ui.application_url
+ php %command.full_name% oro_website.url
+ php %command.full_name% oro_website.secure_url
+
+HELP
+ )
+ ;
+ }
+
+ /**
+ * Find a field node by name from the config tree
+ *
+ * @param GroupNodeDefinition $node
+ * @param string $fieldName
+ * @return ?FieldNodeDefinition null if no matching node was found
+ */
+ protected function findFieldNode(GroupNodeDefinition $node, string $fieldName): ?FieldNodeDefinition
+ {
+ foreach ($node as $child) {
+ if ($child instanceof GroupNodeDefinition) {
+ $result = $this->findFieldNode($child, $fieldName);
+ if ($result !== null) {
+ return $result;
+ }
+ } elseif ($child instanceof FieldNodeDefinition) {
+ if ($child->getName() === $fieldName) {
+ return $child;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ * @noinspection PhpMissingParentCallCommonInspection
+ */
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $symfonyStyle = new SymfonyStyle($input, $output);
+ $configManager = $this->configManager;
+ $fieldName = $input->getArgument('name');
+
+ $configTree = $this->formProvider->getTree();
+ $configField = $this->findFieldNode($configTree, $fieldName);
+ if ($configField !== null
+ && $configField->getType() === OroEncodedPlaceholderPasswordType::class
+ ) {
+ $symfonyStyle->error("Encrypted value");
+ return Command::INVALID;
+ }
+
+ $value = $configManager->get($fieldName);
+ if (is_null($value) && $configField === null) {
+ $symfonyStyle->error("Unknown config field");
+ return Command::FAILURE;
+ }
+ if (is_array($value) || is_object($value) || is_bool($value) || is_null($value)) {
+ $value = json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+ }
+ if (!is_scalar($value)) {
+ $symfonyStyle->error("Value cannot be displayed");
+ return Command::FAILURE;
+ }
+
+ $output->writeln($value);
+ return Command::SUCCESS;
+ }
+}
diff --git a/src/Oro/Bundle/ConfigBundle/Resources/config/commands.yml b/src/Oro/Bundle/ConfigBundle/Resources/config/commands.yml
index 59c3e074d1c..21c8edd91be 100644
--- a/src/Oro/Bundle/ConfigBundle/Resources/config/commands.yml
+++ b/src/Oro/Bundle/ConfigBundle/Resources/config/commands.yml
@@ -7,3 +7,10 @@ services:
- '@oro_config.global'
tags:
- { name: console.command }
+
+ Oro\Bundle\ConfigBundle\Command\ConfigViewCommand:
+ arguments:
+ - '@oro_config.global'
+ - '@oro_config.provider.system_configuration.form_provider'
+ tags:
+ - { name: console.command }
diff --git a/src/Oro/Bundle/ConfigBundle/Tests/Functional/Command/ConfigViewCommandTest.php b/src/Oro/Bundle/ConfigBundle/Tests/Functional/Command/ConfigViewCommandTest.php
new file mode 100644
index 00000000000..6a5bbdb82e8
--- /dev/null
+++ b/src/Oro/Bundle/ConfigBundle/Tests/Functional/Command/ConfigViewCommandTest.php
@@ -0,0 +1,70 @@
+createMock(ConfigManager::class);
+ $configManager->method('get')->will(
+ $this->returnCallback(function ($fieldName) {
+ $configValues = [
+ // Plain values
+ 'oro_frontend.web_api' => true,
+ 'oro_locale.default_localization' => 1,
+ 'oro_sales.opportunity_statuses' => null,
+ 'oro_website.secure_url' => 'https://example.com',
+ 'oro_locale.enabled_localizations' => [1, 2, 3],
+ 'oro_example.dummy_object' => (object)['test' => 'value'],
+
+ // Encrypted value
+ 'oro_example.secret_value' => 'Shh, keep it secret',
+
+ // Nonsense value
+ 'oro_example.nonsense_value' => fopen('php://stdin', 'r'),
+ ];
+ return $configValues[$fieldName] ?? null;
+ })
+ );
+
+ $encryptedField = $this->createConfiguredMock(FieldNodeDefinition::class, [
+ 'getName' => 'oro_example.secret_value',
+ 'getType' => OroEncodedPlaceholderPasswordType::class,
+ ]);
+
+ $nullField = $this->createConfiguredMock(FieldNodeDefinition::class, [
+ 'getName' => 'oro_sales.opportunity_statuses',
+ 'getType' => OpportunityStatusConfigType::class,
+ ]);
+
+ $fieldGroup = $this->createConfiguredMock(GroupNodeDefinition::class, [
+ 'getIterator' => new \ArrayIterator([
+ $encryptedField,
+ $nullField,
+ ]),
+ ]);
+
+ $formProvider = $this->createConfiguredMock(SystemConfigurationFormProvider::class, [
+ 'getTree' => $fieldGroup,
+ ]);
+
+ $this->command = new ConfigViewCommand(
+ $configManager,
+ $formProvider
+ );
+ }
+
+ private function validateConfigView(string $configFieldName, string $expectedValue): void
+ {
+ $commandTester = $this->doExecuteCommand($this->command, ['name' => $configFieldName]);
+ $this->assertOutputContains($commandTester, $expectedValue);
+ }
+
+ public function testViewScalarValues(): void
+ {
+ $this->validateConfigView('oro_frontend.web_api', 'true');
+ $this->validateConfigView('oro_locale.default_localization', '1');
+ $this->validateConfigView('oro_sales.opportunity_statuses', 'null');
+ $this->validateConfigView('oro_website.secure_url', 'https://example.com');
+ }
+
+ public function testViewArrayValue(): void
+ {
+ $this->validateConfigView('oro_locale.enabled_localizations', '[ 1, 2, 3 ]');
+ }
+
+ public function testViewObjectValue(): void
+ {
+ $this->validateConfigView('oro_example.dummy_object', '{ "test": "value" }');
+ }
+
+ public function testViewEncryptedValue(): void
+ {
+ $this->assertProducedError(
+ $this->doExecuteCommand($this->command, ['name' => 'oro_example.secret_value']),
+ "Encrypted value"
+ );
+ }
+
+ public function testViewInvalidValue(): void
+ {
+ $this->assertProducedError(
+ $this->doExecuteCommand($this->command, ['name' => 'oro_example.nonsense_value']),
+ "Value cannot be displayed"
+ );
+ }
+
+ public function testViewNonexistentValue(): void
+ {
+ $this->assertProducedError(
+ $this->doExecuteCommand($this->command, ['name' => 'oro_example.nonexistent_field']),
+ "Unknown config field"
+ );
+ }
+}